diff --git a/DEPS b/DEPS
index 35f75cd..9c8a3c4 100644
--- a/DEPS
+++ b/DEPS
@@ -133,11 +133,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': 'c7520549812464deb45b1ad5d40274a70f05e1c2',
+  'skia_revision': '159a9595963bd08326e9088db12fd701f78f1eae',
   # 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': 'b5ce76ecb22a8a0aad5d2eee9e011092a4a965e2',
+  'v8_revision': '692f7eeca7782bb3736d793fbac2e2c945a238c2',
   # 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.
@@ -145,15 +145,15 @@
   # 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': '1ad7a07212b28ef9b74b24f4d76d06641cafaec3',
+  'angle_revision': '821337639b3f134f7530a06215f2741b788d064a',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': 'fb280672c04f72dfcc19d5f449380b6601b4b681',
+  'swiftshader_revision': '5b09dd109681fcf147ff6fbf7ed449e38fec31b9',
   # 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': 'c1aefb717810667d6889990d76798a481acce148',
+  'pdfium_revision': '015ab4328738d5a62036f06b67af8983c9b3d8b4',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -200,7 +200,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': '2dd550aaf000a2ea7209e245dadc387b3a96251d',
+  'catapult_revision': 'f88be3bdf9ca3a367b8fc922c53beb0c3aea9a5d',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -276,7 +276,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'ac6fb03dd7b9f5e72c32f234f419173f837b35e4',
+  'quiche_revision': 'de80b29a460deb934a6f53db6e567c403ac17664',
   # 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.
@@ -821,7 +821,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '3a78fde2f31448ec30a807f8cba7c6cf7059b9d1',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + 'c6682b1f2e0d0f8430a0536ec165201a8e77be15',
       'condition': 'checkout_linux',
   },
 
@@ -831,7 +831,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '4ef3221c5d415fb50932eeee7aa98cc797d5a642',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f61af56950276661d14c5c3387a706692487ecab',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -979,7 +979,7 @@
     Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + '3874188bd69fe67a825d07584c74451e45063e95',
 
   'src/third_party/icu':
-    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '35f7e139f33f1ddbfdb68b65dda29aff430c3f6f',
+    Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'ae4b77dc8966796f0bd93bb6342023276749e148',
 
   'src/third_party/icu4j': {
       'packages': [
@@ -1349,13 +1349,13 @@
   },
 
   'src/third_party/webdriver/pylib':
-    Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
+    Var('chromium_git') + '/external/github.com/SeleniumHQ/selenium/py.git' + '@' + 'd0045ec570c1a77612db35d1e92f05e1d27b4d53',
 
   'src/third_party/webgl/src':
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6f0b34abee8dba611c253738d955c59f703c147a',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'bc6a4d094fe3f790af7f26061f1b988a9d6464d4',
+    Var('webrtc_git') + '/src.git' + '@' + '756391a4c28ffced9d774d02ef240bb642afcd9e',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1396,7 +1396,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@a1231e2059f36f4917645293cda4dac0f0cbdffa',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@86162ce37530a5a0c02a925887f924ee975a5400',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 2375072d..86afc51 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -737,6 +737,28 @@
       (),
     ),
     (
+      'StringFromGUID2',
+      (
+        'StringFromGUID2 introduces an unnecessary dependency on ole32.dll.',
+        'Use base::win::String16FromGUID instead.'
+      ),
+      True,
+      (
+        r'/base/win/win_util_unittest.cc'
+      ),
+    ),
+    (
+      'StringFromCLSID',
+      (
+        'StringFromCLSID introduces an unnecessary dependency on ole32.dll.',
+        'Use base::win::String16FromGUID instead.'
+      ),
+      True,
+      (
+        r'/base/win/win_util_unittest.cc'
+      ),
+    ),
+    (
       'kCFAllocatorNull',
       (
         'The use of kCFAllocatorNull with the NoCopy creation of ',
diff --git a/WATCHLISTS b/WATCHLISTS
index 394a3d0..2bfb63e 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -732,9 +732,8 @@
                   '|chrome/browser/ui/webui/chromeos/bluetooth*'\
                   '|chrome/browser/resources/settings/bluetooth_page/'\
                   '|chrome/browser/resources/chromeos/bluetooth_pairing_dialog/'\
-                  '|device/bluetooth'\
-                  '|services/device/bluetooth/'\
-                  '|services/device/public/cpp/bluetooth/'\
+                  '|device/bluetooth/bluez/'\
+                  '|device/bluetooth/chromeos/'\
                   '|ui/webui/resources/cr_components/chromeos/bluetooth*'
     },
     'chromeos_calculator': {
diff --git a/android_webview/browser/aw_settings.cc b/android_webview/browser/aw_settings.cc
index f14368e..6d820dd 100644
--- a/android_webview/browser/aw_settings.cc
+++ b/android_webview/browser/aw_settings.cc
@@ -520,6 +520,16 @@
       break;
     }
   }
+
+  // Blink's behavior is that if the preferred color scheme matches the
+  // supported color scheme, then force dark will be disabled, otherwise
+  // the preferred color scheme will be reset to no preference. Therefore
+  // when enabling force dark, we also set the preferred color scheme to
+  // dark so that dark themed content will be preferred over force darkening.
+  web_prefs->preferred_color_scheme =
+      web_prefs->force_dark_mode_enabled
+          ? blink::PreferredColorScheme::kDark
+          : blink::PreferredColorScheme::kNoPreference;
 }
 
 bool AwSettings::GetAllowFileAccess() {
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index ed018a3a..3f5b6242 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -82,6 +82,10 @@
       return launcher_should_show
                  ? app_list::TabletModeAnimationTransition::kDragReleaseShow
                  : app_list::TabletModeAnimationTransition::kDragReleaseHide;
+    case HomeScreenDelegate::AnimationTrigger::kOverviewMode:
+      return launcher_should_show
+                 ? app_list::TabletModeAnimationTransition::kExitOverviewMode
+                 : app_list::TabletModeAnimationTransition::kEnterOverviewMode;
   }
 }
 
diff --git a/ash/app_list/app_list_metrics.cc b/ash/app_list/app_list_metrics.cc
index 725a9ce..029d11c 100644
--- a/ash/app_list/app_list_metrics.cc
+++ b/ash/app_list/app_list_metrics.cc
@@ -127,7 +127,8 @@
   }
 }
 
-void RecordPageSwitcherSourceMetrics(ui::EventType type) {
+void RecordPageSwitcherSourceByEventType(ui::EventType type,
+                                         bool is_tablet_mode) {
   AppListPageSwitcherSource source;
 
   switch (type) {
@@ -147,9 +148,20 @@
       NOTREACHED();
       return;
   }
+  RecordPageSwitcherSource(source, is_tablet_mode);
+}
 
+void RecordPageSwitcherSource(AppListPageSwitcherSource source,
+                              bool is_tablet_mode) {
   UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogram, source,
                             kMaxAppListPageSwitcherSource);
+  if (is_tablet_mode) {
+    UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogramInTablet,
+                              source, kMaxAppListPageSwitcherSource);
+  } else {
+    UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogramInClamshell,
+                              source, kMaxAppListPageSwitcherSource);
+  }
 }
 
 APP_LIST_EXPORT void RecordSearchResultOpenSource(
diff --git a/ash/app_list/app_list_metrics.h b/ash/app_list/app_list_metrics.h
index 28acc6fd..cdb19d1 100644
--- a/ash/app_list/app_list_metrics.h
+++ b/ash/app_list/app_list_metrics.h
@@ -38,11 +38,21 @@
 constexpr char kAppListStateTransitionSourceHistogram[] =
     "Apps.AppListStateTransitionSource";
 
-// The UMA histogram that logs the source of vertical page switcher usage in the
-// app list.
+// The UMA histogram that logs the source of root app grid page switcher usage
+// in the app list.
 constexpr char kAppListPageSwitcherSourceHistogram[] =
     "Apps.AppListPageSwitcherSource";
 
+// The UMA histogram that logs the source of root app grid page switcher usage
+// in the app list in tablet mode.
+constexpr char kAppListPageSwitcherSourceHistogramInTablet[] =
+    "Apps.AppListPageSwitcherSource.TabletMode";
+
+// The UMA histogram that logs the source of root app grid page switcher usage
+// in the app list in clamshell mode.
+constexpr char kAppListPageSwitcherSourceHistogramInClamshell[] =
+    "Apps.AppListPageSwitcherSource.ClamshellMode";
+
 // The UMA histogram that logs usage of the original and redesigned folders.
 constexpr char kAppListFolderOpenedHistogram[] = "Apps.AppListFolderOpened";
 
@@ -229,14 +239,24 @@
   kAppListButtonShow,
 
   // Activate a window from shelf to hide the launcher in tablet mode.
-  kHideHomeLauncherForWindow
+  kHideHomeLauncherForWindow,
+
+  // Enter the overview mode in tablet
+  kEnterOverviewMode,
+
+  // Exit the overview mode in tablet
+  kExitOverviewMode
 };
 
 void RecordFolderShowHideAnimationSmoothness(int actual_frames,
                                              int ideal_duration_ms,
                                              float refresh_rate);
 
-void RecordPageSwitcherSourceMetrics(ui::EventType type);
+void RecordPageSwitcherSourceByEventType(ui::EventType type,
+                                         bool is_tablet_mode);
+
+void RecordPageSwitcherSource(AppListPageSwitcherSource source,
+                              bool is_tablet_mode);
 
 void RecordPaginationAnimationSmoothness(int actual_frames,
                                          int ideal_duration_ms,
diff --git a/ash/app_list/views/app_list_folder_view.cc b/ash/app_list/views/app_list_folder_view.cc
index c236b1c..10722902 100644
--- a/ash/app_list/views/app_list_folder_view.cc
+++ b/ash/app_list/views/app_list_folder_view.cc
@@ -463,7 +463,8 @@
 
   page_switcher_ =
       contents_container_->AddChildView(std::make_unique<PageSwitcher>(
-          items_grid_view_->pagination_model(), false /* vertical */));
+          items_grid_view_->pagination_model(), false /* vertical */,
+          contents_view_->app_list_view()->is_tablet_mode()));
   view_model_->Add(page_switcher_, kIndexPageSwitcher);
 
   model_->AddObserver(this);
@@ -656,6 +657,11 @@
   background_view_->layer()->SetMaskLayer(background_mask_->layer());
 }
 
+void AppListFolderView::OnTabletModeChanged(bool started) {
+  folder_header_view()->set_tablet_mode(started);
+  page_switcher_->set_is_tablet_mode(started);
+}
+
 void AppListFolderView::NotifyAccessibilityLocationChanges() {
   contents_container_->NotifyAccessibilityEvent(
       ax::mojom::Event::kLocationChanged, true);
diff --git a/ash/app_list/views/app_list_folder_view.h b/ash/app_list/views/app_list_folder_view.h
index 9318baf5..cb47cff6 100644
--- a/ash/app_list/views/app_list_folder_view.h
+++ b/ash/app_list/views/app_list_folder_view.h
@@ -110,9 +110,7 @@
   void UpdateBackgroundMask(int corner_radius, const gfx::Insets& insets);
 
   // Called when tablet mode starts and ends.
-  void OnTabletModeChanged(bool started) {
-    folder_header_view()->set_tablet_mode(started);
-  }
+  void OnTabletModeChanged(bool started);
 
   // When transform in |contents_view_| is updated, notify accessibility to show
   // ChromeVox focus in correct locations.
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index 9835867..109be11d 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -14,6 +14,7 @@
 #include "ash/app_list/views/app_list_main_view.h"
 #include "ash/app_list/views/apps_container_view.h"
 #include "ash/app_list/views/contents_view.h"
+#include "ash/app_list/views/horizontal_page_container.h"
 #include "ash/app_list/views/search_box_view.h"
 #include "ash/assistant/ui/assistant_ui_constants.h"
 #include "ash/public/cpp/app_list/app_list_config.h"
@@ -283,6 +284,16 @@
           "HideLauncherForWindow",
           value);
       break;
+    case TabletModeAnimationTransition::kEnterOverviewMode:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.HomeLauncherTransition.AnimationSmoothness.EnterOverview",
+          value);
+      break;
+    case TabletModeAnimationTransition::kExitOverviewMode:
+      UMA_HISTOGRAM_PERCENTAGE(
+          "Apps.HomeLauncherTransition.AnimationSmoothness.ExitOverview",
+          value);
+      break;
   }
 }
 
@@ -1305,6 +1316,9 @@
   search_box_view_->OnTabletModeChanged(started);
   search_model_->SetTabletMode(started);
   GetAppsContainerView()->OnTabletModeChanged(started);
+  app_list_main_view_->contents_view()
+      ->horizontal_page_container()
+      ->OnTabletModeChanged(started);
 
   if (!started) {
     Dismiss();
diff --git a/ash/app_list/views/apps_container_view.cc b/ash/app_list/views/apps_container_view.cc
index a7b97f2..a551e8418 100644
--- a/ash/app_list/views/apps_container_view.cc
+++ b/ash/app_list/views/apps_container_view.cc
@@ -71,8 +71,9 @@
   AddChildView(apps_grid_view_);
 
   // Page switcher should be initialized after AppsGridView.
-  page_switcher_ = new PageSwitcher(apps_grid_view_->pagination_model(),
-                                    true /* vertical */);
+  page_switcher_ =
+      new PageSwitcher(apps_grid_view_->pagination_model(), true /* vertical */,
+                       contents_view_->app_list_view()->is_tablet_mode());
   AddChildView(page_switcher_);
 
   app_list_folder_view_ = new AppListFolderView(this, model, contents_view_);
@@ -223,6 +224,7 @@
   suggestion_chip_container_view_->OnTabletModeChanged(started);
   apps_grid_view_->OnTabletModeChanged(started);
   app_list_folder_view_->OnTabletModeChanged(started);
+  page_switcher_->set_is_tablet_mode(started);
 }
 
 void AppsContainerView::Layout() {
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc
index dc11c56..7812596 100644
--- a/ash/app_list/views/apps_grid_view.cc
+++ b/ash/app_list/views/apps_grid_view.cc
@@ -340,7 +340,8 @@
       &pagination_model_,
       folder_delegate_ ? ash::PaginationController::SCROLL_AXIS_HORIZONTAL
                        : ash::PaginationController::SCROLL_AXIS_VERTICAL,
-      base::BindRepeating(&RecordPageSwitcherSourceMetrics));
+      base::BindRepeating(&RecordPageSwitcherSourceByEventType),
+      IsTabletMode());
 }
 
 AppsGridView::~AppsGridView() {
@@ -435,6 +436,8 @@
 }
 
 void AppsGridView::OnTabletModeChanged(bool started) {
+  pagination_controller_->set_is_tablet_mode(started);
+
   // Enable/Disable folder icons's background blur based on tablet mode.
   for (int i = 0; i < view_model_.view_size(); ++i) {
     auto* item_view = view_model_.view_at(i);
@@ -2069,8 +2072,7 @@
   }
 
   pagination_model_.SelectPage(page_flip_target_, true);
-  UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogram,
-                            kDragAppToBorder, kMaxAppListPageSwitcherSource);
+  RecordPageSwitcherSource(kDragAppToBorder, IsTabletMode());
 
   BeginHideCurrentGhostImageView();
 }
@@ -2909,11 +2911,8 @@
   Layout();
   AnnounceReorder(target_index);
 
-  if (target_index.page != original_selected_view_index.page) {
-    UMA_HISTOGRAM_ENUMERATION(kAppListPageSwitcherSourceHistogram,
-                              kMoveAppWithKeyboard,
-                              kMaxAppListPageSwitcherSource);
-  }
+  if (target_index.page != original_selected_view_index.page)
+    RecordPageSwitcherSource(kMoveAppWithKeyboard, IsTabletMode());
 }
 
 size_t AppsGridView::GetTargetItemIndexForMove(AppListItemView* moved_view,
diff --git a/ash/app_list/views/horizontal_page_container.cc b/ash/app_list/views/horizontal_page_container.cc
index 2c7293d..2e2ca7ea 100644
--- a/ash/app_list/views/horizontal_page_container.cc
+++ b/ash/app_list/views/horizontal_page_container.cc
@@ -27,7 +27,8 @@
   pagination_model_.AddObserver(this);
   pagination_controller_ = std::make_unique<ash::PaginationController>(
       &pagination_model_, ash::PaginationController::SCROLL_AXIS_HORIZONTAL,
-      base::BindRepeating(&RecordPageSwitcherSourceMetrics));
+      base::BindRepeating(&RecordPageSwitcherSourceByEventType),
+      contents_view_->app_list_view()->is_tablet_mode());
 
   // Add horizontal pages.
   apps_container_view_ = new AppsContainerView(contents_view_, model);
@@ -126,6 +127,10 @@
   return GetSelectedPage()->ShouldShowSearchBox();
 }
 
+void HorizontalPageContainer::OnTabletModeChanged(bool started) {
+  pagination_controller_->set_is_tablet_mode(started);
+}
+
 void HorizontalPageContainer::TotalPagesChanged() {}
 
 void HorizontalPageContainer::SelectedPageChanged(int old_selected,
diff --git a/ash/app_list/views/horizontal_page_container.h b/ash/app_list/views/horizontal_page_container.h
index a5d3fa8..a1b27cf 100644
--- a/ash/app_list/views/horizontal_page_container.h
+++ b/ash/app_list/views/horizontal_page_container.h
@@ -51,6 +51,8 @@
 
   AppsContainerView* apps_container_view() { return apps_container_view_; }
 
+  void OnTabletModeChanged(bool started);
+
  private:
   // PaginationModelObserver:
   void TotalPagesChanged() override;
diff --git a/ash/app_list/views/page_switcher.cc b/ash/app_list/views/page_switcher.cc
index aa942e0..fa80d30 100644
--- a/ash/app_list/views/page_switcher.cc
+++ b/ash/app_list/views/page_switcher.cc
@@ -183,8 +183,13 @@
 
 }  // namespace
 
-PageSwitcher::PageSwitcher(ash::PaginationModel* model, bool vertical)
-    : model_(model), buttons_(new views::View), vertical_(vertical) {
+PageSwitcher::PageSwitcher(ash::PaginationModel* model,
+                           bool vertical,
+                           bool is_tablet_mode)
+    : model_(model),
+      buttons_(new views::View),
+      vertical_(vertical),
+      is_tablet_mode_(is_tablet_mode) {
   SetPaintToLayer();
   layer()->SetFillsBoundsOpaquely(false);
 
@@ -240,10 +245,9 @@
   const int page = std::distance(children.begin(), it);
   if (page == model_->selected_page())
     return;
-  UMA_HISTOGRAM_ENUMERATION(
-      kAppListPageSwitcherSourceHistogram,
+  RecordPageSwitcherSource(
       event.IsGestureEvent() ? kTouchPageIndicator : kClickPageIndicator,
-      kMaxAppListPageSwitcherSource);
+      is_tablet_mode_);
   model_->SelectPage(page, true /* animate */);
 }
 
diff --git a/ash/app_list/views/page_switcher.h b/ash/app_list/views/page_switcher.h
index dd4603a..494373e 100644
--- a/ash/app_list/views/page_switcher.h
+++ b/ash/app_list/views/page_switcher.h
@@ -22,7 +22,7 @@
                      public views::ButtonListener,
                      public ash::PaginationModelObserver {
  public:
-  PageSwitcher(ash::PaginationModel* model, bool vertical);
+  PageSwitcher(ash::PaginationModel* model, bool vertical, bool is_tablet_mode);
   ~PageSwitcher() override;
 
   // Overridden from views::View:
@@ -30,6 +30,7 @@
   void Layout() override;
 
   void set_ignore_button_press(bool ignore) { ignore_button_press_ = ignore; }
+  void set_is_tablet_mode(bool started) { is_tablet_mode_ = started; }
 
  private:
   // Overridden from views::ButtonListener:
@@ -51,6 +52,9 @@
   // True if button press should be ignored.
   bool ignore_button_press_ = false;
 
+  // Whether tablet mode is enabled.
+  bool is_tablet_mode_;
+
   DISALLOW_COPY_AND_ASSIGN(PageSwitcher);
 };
 
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index fa9e1d4..437c5645 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -736,15 +736,19 @@
     return;
   }
 
+  const bool embedded_assistant =
+      app_list_features::IsEmbeddedAssistantUIEnabled();
   views::ImageButton* assistant = assistant_button();
   assistant->SetImage(
       views::ImageButton::STATE_NORMAL,
-      gfx::CreateVectorIcon(app_list_features::IsEmbeddedAssistantUIEnabled()
-                                ? ash::kAssistantMicIcon
-                                : ash::kAssistantIcon,
-                            kAssistantIconSize, search_box_color()));
-  assistant->SetAccessibleName(
-      l10n_util::GetStringUTF16(IDS_APP_LIST_START_ASSISTANT));
+      gfx::CreateVectorIcon(
+          embedded_assistant ? ash::kAssistantMicIcon : ash::kAssistantIcon,
+          kAssistantIconSize, search_box_color()));
+  base::string16 assistant_button_label(l10n_util::GetStringUTF16(
+      embedded_assistant ? IDS_APP_LIST_START_ASSISTANT_VOICE_QUERY
+                         : IDS_APP_LIST_START_ASSISTANT));
+  assistant->SetAccessibleName(assistant_button_label);
+  assistant->SetTooltipText(assistant_button_label);
 }
 
 }  // namespace app_list
diff --git a/ash/home_screen/home_screen_delegate.h b/ash/home_screen/home_screen_delegate.h
index bf6c1e0f..7e87e48 100644
--- a/ash/home_screen/home_screen_delegate.h
+++ b/ash/home_screen/home_screen_delegate.h
@@ -31,7 +31,10 @@
     kLauncherButton,
 
     // Launcher animation is triggered by window activation.
-    kHideForWindow
+    kHideForWindow,
+
+    // Launcher animation is triggered by entering/exiting overview mode.
+    kOverviewMode
   };
 
   virtual ~HomeScreenDelegate() = default;
diff --git a/ash/home_screen/home_screen_presenter.cc b/ash/home_screen/home_screen_presenter.cc
index 49e46d0..2011c9f 100644
--- a/ash/home_screen/home_screen_presenter.cc
+++ b/ash/home_screen/home_screen_presenter.cc
@@ -102,6 +102,9 @@
                                                         bool animate) {
   // If animating, set the source parameters first.
   if (animate) {
+    controller_->delegate()->NotifyHomeLauncherAnimationTransition(
+        HomeScreenDelegate::AnimationTrigger::kOverviewMode,
+        /*launcher_will_show=*/!start);
     controller_->delegate()->UpdateYPositionAndOpacityForHomeLauncher(
         start ? 0 : kOverviewAnimationYOffset, start ? 1.f : 0.f,
         base::NullCallback());
diff --git a/ash/public/cpp/pagination/pagination_controller.cc b/ash/public/cpp/pagination/pagination_controller.cc
index 2f3adb0a..68bc424f 100644
--- a/ash/public/cpp/pagination/pagination_controller.cc
+++ b/ash/public/cpp/pagination/pagination_controller.cc
@@ -22,10 +22,12 @@
 
 PaginationController::PaginationController(PaginationModel* model,
                                            ScrollAxis scroll_axis,
-                                           const RecordMetrics& record_metrics)
+                                           const RecordMetrics& record_metrics,
+                                           bool is_tablet_mode)
     : pagination_model_(model),
       scroll_axis_(scroll_axis),
-      record_metrics_(record_metrics) {
+      record_metrics_(record_metrics),
+      is_tablet_mode_(is_tablet_mode) {
   DCHECK(record_metrics_);
 }
 
@@ -51,7 +53,7 @@
       !pagination_model_->has_transition()) {
     const int delta = offset_magnitude > 0 ? -1 : 1;
     if (pagination_model_->IsValidPageRelative(delta)) {
-      record_metrics_.Run(type);
+      record_metrics_.Run(type, is_tablet_mode_);
     }
     pagination_model_->SelectPageRelative(delta, true);
     return true;
@@ -94,7 +96,7 @@
           pagination_model_->transition().progress < kFinishTransitionThreshold;
       pagination_model_->EndScroll(cancel_transition);
       if (!cancel_transition) {
-        record_metrics_.Run(event.type());
+        record_metrics_.Run(event.type(), is_tablet_mode_);
       }
       return true;
     }
@@ -107,7 +109,7 @@
       if (fabs(velocity) > kMinHorizVelocityToSwitchPage) {
         const int delta = velocity < 0 ? 1 : -1;
         if (pagination_model_->IsValidPageRelative(delta)) {
-          record_metrics_.Run(event.type());
+          record_metrics_.Run(event.type(), is_tablet_mode_);
         }
         pagination_model_->SelectPageRelative(delta, true);
       }
diff --git a/ash/public/cpp/pagination/pagination_controller.h b/ash/public/cpp/pagination/pagination_controller.h
index 184fba6..5bca6026 100644
--- a/ash/public/cpp/pagination/pagination_controller.h
+++ b/ash/public/cpp/pagination/pagination_controller.h
@@ -24,14 +24,15 @@
  public:
   enum ScrollAxis { SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL };
 
-  using RecordMetrics = base::RepeatingCallback<void(ui::EventType)>;
+  using RecordMetrics = base::RepeatingCallback<void(ui::EventType, bool)>;
 
   // Creates a PaginationController. Does not take ownership of |model|. The
   // |model| is required to outlive this PaginationController. |scroll_axis|
   // specifies the axis in which the pages will scroll.
   PaginationController(PaginationModel* model,
                        ScrollAxis scroll_axis,
-                       const RecordMetrics& record_metrics);
+                       const RecordMetrics& record_metrics,
+                       bool is_tablet_mode);
   ~PaginationController();
 
   ScrollAxis scroll_axis() const { return scroll_axis_; }
@@ -45,12 +46,17 @@
   // PaginationModel. Returns true if the event was captured.
   bool OnGestureEvent(const ui::GestureEvent& event, const gfx::Rect& bounds);
 
+  void set_is_tablet_mode(bool started) { is_tablet_mode_ = started; }
+
  private:
   PaginationModel* pagination_model_;  // Not owned.
   ScrollAxis scroll_axis_;
 
   const RecordMetrics record_metrics_;
 
+  // Whether tablet mode is enabled.
+  bool is_tablet_mode_;
+
   DISALLOW_COPY_AND_ASSIGN(PaginationController);
 };
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index d7a39e4..9b8ab65 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -755,6 +755,9 @@
     "system/system_monitor.h",
     "task/cancelable_task_tracker.cc",
     "task/cancelable_task_tracker.h",
+    "task/common/checked_lock.h",
+    "task/common/checked_lock_impl.cc",
+    "task/common/checked_lock_impl.h",
     "task/common/intrusive_heap.h",
     "task/common/operations_controller.cc",
     "task/common/operations_controller.h",
@@ -830,9 +833,6 @@
     "task/thread_pool/platform_native_worker_pool_win.h",
     "task/thread_pool/priority_queue.cc",
     "task/thread_pool/priority_queue.h",
-    "task/thread_pool/scheduler_lock.h",
-    "task/thread_pool/scheduler_lock_impl.cc",
-    "task/thread_pool/scheduler_lock_impl.h",
     "task/thread_pool/scheduler_parallel_task_runner.cc",
     "task/thread_pool/scheduler_parallel_task_runner.h",
     "task/thread_pool/scheduler_sequenced_task_runner.cc",
@@ -2578,6 +2578,7 @@
     "system/sys_info_unittest.cc",
     "system/system_monitor_unittest.cc",
     "task/cancelable_task_tracker_unittest.cc",
+    "task/common/checked_lock_unittest.cc",
     "task/common/intrusive_heap_unittest.cc",
     "task/common/operations_controller_unittest.cc",
     "task/common/task_annotator_unittest.cc",
@@ -2601,7 +2602,6 @@
     "task/thread_pool/can_run_policy_test.h",
     "task/thread_pool/delayed_task_manager_unittest.cc",
     "task/thread_pool/priority_queue_unittest.cc",
-    "task/thread_pool/scheduler_lock_unittest.cc",
     "task/thread_pool/scheduler_single_thread_task_runner_manager_unittest.cc",
     "task/thread_pool/scheduler_worker_pool_impl_unittest.cc",
     "task/thread_pool/scheduler_worker_pool_unittest.cc",
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
index 46bbd16b..f10b2c3 100644
--- a/base/base_paths_mac.mm
+++ b/base/base_paths_mac.mm
@@ -111,12 +111,17 @@
       return base::mac::GetUserDirectory(NSDesktopDirectory, result);
 #endif
     case base::DIR_ASSETS:
+#if defined(OS_IOS)
+      // TODO(https://crbug.com/957792): Assets live alongside the executable.
+      return PathService::Get(base::DIR_MODULE, result);
+#else
       if (!base::mac::AmIBundled()) {
         return PathService::Get(base::DIR_MODULE, result);
       }
       *result = base::mac::FrameworkBundlePath().Append(
           FILE_PATH_LITERAL("Resources"));
       return true;
+#endif  // !defined(OS_IOS)
     case base::DIR_CACHE:
       return base::mac::GetUserDirectory(NSCachesDirectory, result);
     default:
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
index 73a2f23c..f9db705 100644
--- a/base/debug/stack_trace.h
+++ b/base/debug/stack_trace.h
@@ -39,7 +39,14 @@
 BASE_EXPORT bool EnableInProcessStackDumping();
 
 #if defined(OS_POSIX)
-BASE_EXPORT void SetStackDumpFirstChanceCallback(bool (*handler)(int,
+// Sets a first-chance callback for the stack dump signal handler. This callback
+// is called at the beginning of the signal handler to handle special kinds of
+// signals, like out-of-bounds memory accesses in WebAssembly (WebAssembly Trap
+// Handler).
+// {SetStackDumpFirstChanceCallback} returns {true} if the callback
+// has been set correctly. It returns {false} if the stack dump signal handler
+// has not been registered with the OS, e.g. because of ASAN.
+BASE_EXPORT bool SetStackDumpFirstChanceCallback(bool (*handler)(int,
                                                                  void*,
                                                                  void*));
 #endif
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
index d4b8b3a..de2f356 100644
--- a/base/debug/stack_trace_posix.cc
+++ b/base/debug/stack_trace_posix.cc
@@ -803,9 +803,25 @@
   return success;
 }
 
-void SetStackDumpFirstChanceCallback(bool (*handler)(int, void*, void*)) {
+bool SetStackDumpFirstChanceCallback(bool (*handler)(int, void*, void*)) {
   DCHECK(try_handle_signal == nullptr || handler == nullptr);
   try_handle_signal = handler;
+
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) ||    \
+    defined(UNDEFINED_SANITIZER)
+  struct sigaction installed_handler;
+  CHECK_EQ(sigaction(SIGSEGV, NULL, &installed_handler), 0);
+  // If the installed handler does not point to StackDumpSignalHandler, then
+  // allow_user_segv_handler is 0.
+  if (installed_handler.sa_sigaction != StackDumpSignalHandler) {
+    LOG(WARNING)
+        << "WARNING: sanitizers are preventing signal handler installation. "
+        << "WebAssembly trap handlers are disabled.\n";
+    return false;
+  }
+#endif
+  return true;
 }
 
 size_t CollectStackTrace(void** trace, size_t count) {
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
index bcb87d0..b47a84fe 100644
--- a/base/path_service_unittest.cc
+++ b/base/path_service_unittest.cc
@@ -42,11 +42,6 @@
   if (dir_type == DIR_USER_DESKTOP)
     check_path_exists = false;
 #endif
-#if defined(OS_IOS)
-  // Bundled unittests on iOS may not have Resources directory in the bundle.
-  if (dir_type == DIR_ASSETS)
-    check_path_exists = false;
-#endif
 #if defined(OS_MACOSX)
   if (dir_type != DIR_EXE && dir_type != DIR_MODULE && dir_type != FILE_EXE &&
       dir_type != FILE_MODULE) {
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
index 1b4fdb3a..d030e438 100644
--- a/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -65,8 +65,6 @@
 #endif
 
 using SamplingParams = StackSamplingProfiler::SamplingParams;
-using Frames = std::vector<Frame>;
-using FrameSets = std::vector<std::vector<Frame>>;
 
 namespace {
 
@@ -277,9 +275,9 @@
 }
 
 // Formats a sample into a string that can be output for test diagnostics.
-std::string FormatSampleForDiagnosticOutput(const Frames& frames) {
+std::string FormatSampleForDiagnosticOutput(const std::vector<Frame>& sample) {
   std::string output;
-  for (const auto& frame : frames) {
+  for (const auto& frame : sample) {
     output += StringPrintf(
         "0x%p %s\n", reinterpret_cast<const void*>(frame.instruction_pointer),
         frame.module ? frame.module->GetDebugBasename().AsUTF8Unsafe().c_str()
@@ -290,7 +288,7 @@
 
 // Expects that the stack contains the functions with the specified address
 // ranges, in the specified order.
-void ExpectStackContains(const Frames& stack,
+void ExpectStackContains(const std::vector<Frame>& stack,
                          const std::vector<FunctionAddressRange>& functions) {
   auto frame_it = stack.begin();
   auto function_it = functions.begin();
@@ -314,7 +312,7 @@
 // Expects that the stack does not contain the functions with the specified
 // address ranges.
 void ExpectStackDoesNotContain(
-    const Frames& stack,
+    const std::vector<Frame>& stack,
     const std::vector<FunctionAddressRange>& functions) {
   struct FunctionAddressRangeCompare {
     bool operator()(const FunctionAddressRange& a,
@@ -342,11 +340,11 @@
   }
 }
 
-// Profile consists of a set of frame sets and other sampling information.
+// Profile consists of a set of samples and other sampling information.
 struct Profile {
   Profile() = default;
   Profile(Profile&& other) = default;
-  Profile(const FrameSets& frame_sets,
+  Profile(const std::vector<std::vector<Frame>>& samples,
           int metadata_count,
           TimeDelta profile_duration,
           TimeDelta sampling_period);
@@ -355,8 +353,8 @@
 
   Profile& operator=(Profile&& other) = default;
 
-  // The collected frame sets.
-  FrameSets frame_sets;
+  // The collected samples.
+  std::vector<std::vector<Frame>> samples;
 
   // The number of invocations of RecordMetadata().
   int metadata_count;
@@ -368,11 +366,11 @@
   TimeDelta sampling_period;
 };
 
-Profile::Profile(const FrameSets& frame_sets,
+Profile::Profile(const std::vector<std::vector<Frame>>& samples,
                  int metadata_count,
                  TimeDelta profile_duration,
                  TimeDelta sampling_period)
-    : frame_sets(frame_sets),
+    : samples(samples),
       metadata_count(metadata_count),
       profile_duration(profile_duration),
       sampling_period(sampling_period) {}
@@ -382,7 +380,7 @@
 // this should run as quickly as possible.
 using ProfileCompletedCallback = Callback<void(Profile)>;
 
-// TestProfileBuilder collects frames produced by the profiler.
+// TestProfileBuilder collects samples produced by the profiler.
 class TestProfileBuilder : public ProfileBuilder {
  public:
   TestProfileBuilder(ModuleCache* module_cache,
@@ -393,15 +391,15 @@
   // ProfileBuilder:
   ModuleCache* GetModuleCache() override;
   void RecordMetadata() override;
-  void OnSampleCompleted(Frames frames) override;
+  void OnSampleCompleted(std::vector<Frame> sample) override;
   void OnProfileCompleted(TimeDelta profile_duration,
                           TimeDelta sampling_period) override;
 
  private:
   ModuleCache* module_cache_;
 
-  // The sets of frames recorded.
-  std::vector<Frames> frame_sets_;
+  // The set of recorded samples.
+  std::vector<std::vector<Frame>> samples_;
 
   // The number of invocations of RecordMetadata().
   int metadata_count_ = 0;
@@ -426,14 +424,14 @@
   ++metadata_count_;
 }
 
-void TestProfileBuilder::OnSampleCompleted(Frames frames) {
-  frame_sets_.push_back(std::move(frames));
+void TestProfileBuilder::OnSampleCompleted(std::vector<Frame> sample) {
+  samples_.push_back(std::move(sample));
 }
 
 void TestProfileBuilder::OnProfileCompleted(TimeDelta profile_duration,
                                             TimeDelta sampling_period) {
   callback_.Run(
-      Profile(frame_sets_, metadata_count_, profile_duration, sampling_period));
+      Profile(samples_, metadata_count_, profile_duration, sampling_period));
 }
 
 // Loads the other library, which defines a function to be called in the
@@ -482,12 +480,14 @@
 #endif
 }
 
-// Executes ProfileFunction while ThreadFunction is running on the target
+// The callback to perform profiling on the provided thread.
+using ProfileCallback = OnceCallback<void(PlatformThreadId)>;
+
+// Executes |profile_callback| while running |scenario| on the target
 // thread. Performs all necessary target thread startup and shutdown work before
 // and afterward.
-template <class ProfileFunction>
 void WithTargetThread(UnwindScenario* scenario,
-                      ProfileFunction profile_function) {
+                      ProfileCallback profile_callback) {
   UnwindScenario::SampleEvents events;
   TargetThread target_thread(
       BindLambdaForTesting([&]() { scenario->Execute(&events); }));
@@ -497,44 +497,46 @@
 
   events.ready_for_sample.Wait();
 
-  profile_function(target_thread.id());
+  std::move(profile_callback).Run(target_thread.id());
 
   events.sample_finished.Signal();
 
   PlatformThread::Join(target_thread_handle);
 }
 
-template <class ProfileFunction>
-void WithTargetThread(ProfileFunction profile_function) {
+void WithTargetThread(ProfileCallback profile_callback) {
   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
-  WithTargetThread(&scenario, profile_function);
+  WithTargetThread(&scenario, std::move(profile_callback));
 }
 
-Frames SampleScenario(UnwindScenario* scenario, ModuleCache* module_cache) {
+// Returns the sample seen when taking one sample of |scenario|.
+std::vector<Frame> SampleScenario(UnwindScenario* scenario,
+                                  ModuleCache* module_cache) {
   SamplingParams params;
   params.sampling_interval = TimeDelta::FromMilliseconds(0);
   params.samples_per_profile = 1;
 
   Profile profile;
-  WithTargetThread(scenario, [&](PlatformThreadId target_thread_id) {
-    WaitableEvent sampling_thread_completed(
-        WaitableEvent::ResetPolicy::MANUAL,
-        WaitableEvent::InitialState::NOT_SIGNALED);
-    StackSamplingProfiler profiler(
-        target_thread_id, params,
-        std::make_unique<TestProfileBuilder>(
-            module_cache,
-            BindLambdaForTesting(
-                [&profile, &sampling_thread_completed](Profile result_profile) {
+  WithTargetThread(
+      scenario, BindLambdaForTesting([&](PlatformThreadId target_thread_id) {
+        WaitableEvent sampling_thread_completed(
+            WaitableEvent::ResetPolicy::MANUAL,
+            WaitableEvent::InitialState::NOT_SIGNALED);
+        StackSamplingProfiler profiler(
+            target_thread_id, params,
+            std::make_unique<TestProfileBuilder>(
+                module_cache,
+                BindLambdaForTesting([&profile, &sampling_thread_completed](
+                                         Profile result_profile) {
                   profile = std::move(result_profile);
                   sampling_thread_completed.Signal();
                 })));
-    profiler.Start();
-    sampling_thread_completed.Wait();
-  });
+        profiler.Start();
+        sampling_thread_completed.Wait();
+      }));
 
-  CHECK_EQ(1u, profile.frame_sets.size());
-  return profile.frame_sets[0];
+  CHECK_EQ(1u, profile.samples.size());
+  return profile.samples[0];
 }
 
 struct TestProfilerInfo {
@@ -580,22 +582,22 @@
   return profilers;
 }
 
-// Captures frames as specified by |params| on the TargetThread, and returns
+// Captures samples as specified by |params| on the TargetThread, and returns
 // them. Waits up to |profiler_wait_time| for the profiler to complete.
-FrameSets CaptureFrameSets(const SamplingParams& params,
-                           TimeDelta profiler_wait_time,
-                           ModuleCache* module_cache) {
-  FrameSets frame_sets;
-  WithTargetThread([&](PlatformThreadId target_thread_id) {
+std::vector<std::vector<Frame>> CaptureSamples(const SamplingParams& params,
+                                               TimeDelta profiler_wait_time,
+                                               ModuleCache* module_cache) {
+  std::vector<std::vector<Frame>> samples;
+  WithTargetThread(BindLambdaForTesting([&](PlatformThreadId target_thread_id) {
     TestProfilerInfo info(target_thread_id, params, module_cache);
     info.profiler.Start();
     info.completed.TimedWait(profiler_wait_time);
     info.profiler.Stop();
     info.completed.Wait();
-    frame_sets = std::move(info.profile.frame_sets);
-  });
+    samples = std::move(info.profile.samples);
+  }));
 
-  return frame_sets;
+  return samples;
 }
 
 // Waits for one of multiple samplings to complete.
@@ -709,9 +711,9 @@
   // Wait for the sampling thread to complete and fill out |profile|.
   sampling_thread_completed.Wait();
 
-  // Look up the frames.
-  ASSERT_EQ(1u, profile.frame_sets.size());
-  const Frames& frames = profile.frame_sets[0];
+  // Look up the sample.
+  ASSERT_EQ(1u, profile.samples.size());
+  const std::vector<Frame>& sample = profile.samples[0];
 
   if (wait_until_unloaded) {
     // We expect the stack to look something like this, with the frame in the
@@ -721,12 +723,12 @@
     // WaitForSample()
     // TargetThread::OtherLibraryCallback
     // <frame in unloaded library>
-    EXPECT_EQ(nullptr, frames.back().module)
+    EXPECT_EQ(nullptr, sample.back().module)
         << "Stack:\n"
-        << FormatSampleForDiagnosticOutput(frames);
+        << FormatSampleForDiagnosticOutput(sample);
 
-    ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange()});
-    ExpectStackDoesNotContain(frames,
+    ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange()});
+    ExpectStackDoesNotContain(sample,
                               {scenario.GetSetupFunctionAddressRange(),
                                scenario.GetOuterFunctionAddressRange()});
   } else {
@@ -735,16 +737,16 @@
     // the same stack as |wait_until_unloaded|, if not we should have the full
     // stack. The important thing is that we should not crash.
 
-    if (!frames.back().module) {
+    if (!sample.back().module) {
       // This is the same case as |wait_until_unloaded|.
-      ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange()});
-      ExpectStackDoesNotContain(frames,
+      ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange()});
+      ExpectStackDoesNotContain(sample,
                                 {scenario.GetSetupFunctionAddressRange(),
                                  scenario.GetOuterFunctionAddressRange()});
       return;
     }
 
-    ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
+    ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
                                  scenario.GetSetupFunctionAddressRange(),
                                  scenario.GetOuterFunctionAddressRange()});
   }
@@ -787,14 +789,14 @@
 #endif
 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Basic) {
   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
-  const Frames& frames = SampleScenario(&scenario, module_cache());
+  const std::vector<Frame>& sample = SampleScenario(&scenario, module_cache());
 
   // Check that all the modules are valid.
-  for (const auto& frame : frames)
+  for (const auto& frame : sample)
     EXPECT_NE(nullptr, frame.module);
 
   // The stack should contain a full unwind.
-  ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
+  ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
                                scenario.GetSetupFunctionAddressRange(),
                                scenario.GetOuterFunctionAddressRange()});
 }
@@ -832,10 +834,10 @@
 #endif
 PROFILER_TEST_F(StackSamplingProfilerTest, MAYBE_Alloca) {
   UnwindScenario scenario(BindRepeating(&CallWithAlloca));
-  const Frames& frames = SampleScenario(&scenario, module_cache());
+  const std::vector<Frame>& sample = SampleScenario(&scenario, module_cache());
 
   // The stack should contain a full unwind.
-  ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
+  ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
                                scenario.GetSetupFunctionAddressRange(),
                                scenario.GetOuterFunctionAddressRange()});
 }
@@ -852,10 +854,10 @@
   ScopedNativeLibrary other_library(LoadOtherLibrary());
   UnwindScenario scenario(
       BindRepeating(&CallThroughOtherLibrary, Unretained(other_library.get())));
-  const Frames& frames = SampleScenario(&scenario, module_cache());
+  const std::vector<Frame>& sample = SampleScenario(&scenario, module_cache());
 
   // The stack should contain a full unwind.
-  ExpectStackContains(frames, {scenario.GetWaitForSampleAddressRange(),
+  ExpectStackContains(sample, {scenario.GetWaitForSampleAddressRange(),
                                scenario.GetSetupFunctionAddressRange(),
                                scenario.GetOuterFunctionAddressRange()});
 }
@@ -886,7 +888,8 @@
 
 // Checks that a profiler can stop/destruct without ever having started.
 PROFILER_TEST_F(StackSamplingProfilerTest, StopWithoutStarting) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     SamplingParams params;
     params.sampling_interval = TimeDelta::FromMilliseconds(0);
     params.samples_per_profile = 1;
@@ -907,7 +910,7 @@
 
     profiler.Stop();  // Constructed but never started.
     EXPECT_FALSE(sampling_completed.IsSignaled());
-  });
+  }));
 }
 
 // Checks that its okay to stop a profiler before it finishes even when the
@@ -933,7 +936,8 @@
     size_t count_ = 0;
   };
 
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     SamplingParams params[2];
 
     // Providing an initial delay makes it more likely that both will be
@@ -982,22 +986,22 @@
 
     // Ensure that the first profiler didn't do anything since it was stopped.
     EXPECT_EQ(count0, samples_recorded[0].Get());
-  });
+  }));
 }
 
-// Checks that no frames are captured if the profiling is stopped during the
+// Checks that no sample are captured if the profiling is stopped during the
 // initial delay.
 PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInitialDelay) {
   SamplingParams params;
   params.initial_delay = TimeDelta::FromSeconds(60);
 
-  FrameSets frame_sets =
-      CaptureFrameSets(params, TimeDelta::FromMilliseconds(0), module_cache());
+  std::vector<std::vector<Frame>> samples =
+      CaptureSamples(params, TimeDelta::FromMilliseconds(0), module_cache());
 
-  EXPECT_TRUE(frame_sets.empty());
+  EXPECT_TRUE(samples.empty());
 }
 
-// Checks that tasks can be stopped before completion and incomplete frames are
+// Checks that tasks can be stopped before completion and incomplete samples are
 // captured.
 PROFILER_TEST_F(StackSamplingProfilerTest, StopDuringInterSampleInterval) {
   // Test delegate that counts samples.
@@ -1015,7 +1019,8 @@
     WaitableEvent sample_recorded_;
   };
 
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     SamplingParams params;
 
     params.sampling_interval = AVeryLongTimeDelta();
@@ -1034,8 +1039,8 @@
     profiler_info.profiler.Stop();
     profiler_info.completed.Wait();
 
-    EXPECT_EQ(1u, profiler_info.profile.frame_sets.size());
-  });
+    EXPECT_EQ(1u, profiler_info.profile.samples.size());
+  }));
 }
 
 // Checks that we can destroy the profiler while profiling.
@@ -1044,7 +1049,8 @@
   params.sampling_interval = TimeDelta::FromMilliseconds(10);
 
   Profile profile;
-  WithTargetThread([&, this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([&, this](
+                                            PlatformThreadId target_thread_id) {
     std::unique_ptr<StackSamplingProfiler> profiler;
     auto profile_builder = std::make_unique<TestProfileBuilder>(
         module_cache(),
@@ -1059,7 +1065,7 @@
     // Wait longer than a sample interval to catch any use-after-free actions by
     // the profiler thread.
     PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
-  });
+  }));
 }
 
 // Checks that the different profilers may be run.
@@ -1068,40 +1074,42 @@
   params.sampling_interval = TimeDelta::FromMilliseconds(0);
   params.samples_per_profile = 1;
 
-  FrameSets frame_sets =
-      CaptureFrameSets(params, AVeryLongTimeDelta(), module_cache());
-  ASSERT_EQ(1u, frame_sets.size());
+  std::vector<std::vector<Frame>> samples =
+      CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
+  ASSERT_EQ(1u, samples.size());
 
-  frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta(), module_cache());
-  ASSERT_EQ(1u, frame_sets.size());
+  samples = CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
+  ASSERT_EQ(1u, samples.size());
 }
 
 // Checks that a sampler can be started while another is running.
 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleStart) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
-    std::vector<SamplingParams> params(2);
+  WithTargetThread(
+      BindLambdaForTesting([this](PlatformThreadId target_thread_id) {
+        std::vector<SamplingParams> params(2);
 
-    params[0].initial_delay = AVeryLongTimeDelta();
-    params[0].samples_per_profile = 1;
+        params[0].initial_delay = AVeryLongTimeDelta();
+        params[0].samples_per_profile = 1;
 
-    params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
-    params[1].samples_per_profile = 1;
+        params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
+        params[1].samples_per_profile = 1;
 
-    std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
-        CreateProfilers(target_thread_id, params, module_cache());
+        std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
+            CreateProfilers(target_thread_id, params, module_cache());
 
-    profiler_infos[0]->profiler.Start();
-    profiler_infos[1]->profiler.Start();
-    profiler_infos[1]->completed.Wait();
-    EXPECT_EQ(1u, profiler_infos[1]->profile.frame_sets.size());
-  });
+        profiler_infos[0]->profiler.Start();
+        profiler_infos[1]->profiler.Start();
+        profiler_infos[1]->completed.Wait();
+        EXPECT_EQ(1u, profiler_infos[1]->profile.samples.size());
+      }));
 }
 
 // Checks that the profile duration and the sampling interval are calculated
 // correctly. Also checks that RecordMetadata() is invoked each time a sample
 // is recorded.
 PROFILER_TEST_F(StackSamplingProfilerTest, ProfileGeneralInfo) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     SamplingParams params;
     params.sampling_interval = TimeDelta::FromMilliseconds(1);
     params.samples_per_profile = 3;
@@ -1110,7 +1118,7 @@
 
     profiler_info.profiler.Start();
     profiler_info.completed.Wait();
-    EXPECT_EQ(3u, profiler_info.profile.frame_sets.size());
+    EXPECT_EQ(3u, profiler_info.profile.samples.size());
 
     // The profile duration should be greater than the total sampling intervals.
     EXPECT_GT(profiler_info.profile.profile_duration,
@@ -1122,7 +1130,7 @@
     // The number of invocations of RecordMetadata() should be equal to the
     // number of samples recorded.
     EXPECT_EQ(3, profiler_info.profile.metadata_count);
-  });
+  }));
 }
 
 // Checks that the sampling thread can shut down.
@@ -1131,9 +1139,9 @@
   params.sampling_interval = TimeDelta::FromMilliseconds(0);
   params.samples_per_profile = 1;
 
-  FrameSets frame_sets =
-      CaptureFrameSets(params, AVeryLongTimeDelta(), module_cache());
-  ASSERT_EQ(1u, frame_sets.size());
+  std::vector<std::vector<Frame>> samples =
+      CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
+  ASSERT_EQ(1u, samples.size());
 
   // Capture thread should still be running at this point.
   ASSERT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
@@ -1157,9 +1165,9 @@
   params.sampling_interval = TimeDelta::FromMilliseconds(0);
   params.samples_per_profile = 1;
 
-  FrameSets frame_sets =
-      CaptureFrameSets(params, AVeryLongTimeDelta(), module_cache());
-  ASSERT_EQ(1u, frame_sets.size());
+  std::vector<std::vector<Frame>> samples =
+      CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
+  ASSERT_EQ(1u, samples.size());
 
   // Capture thread should still be running at this point.
   ASSERT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
@@ -1169,15 +1177,16 @@
   StackSamplingProfiler::TestPeer::PerformSamplingThreadIdleShutdown(false);
 
   // Ensure another capture will start the sampling thread and run.
-  frame_sets = CaptureFrameSets(params, AVeryLongTimeDelta(), module_cache());
-  ASSERT_EQ(1u, frame_sets.size());
+  samples = CaptureSamples(params, AVeryLongTimeDelta(), module_cache());
+  ASSERT_EQ(1u, samples.size());
   EXPECT_TRUE(StackSamplingProfiler::TestPeer::IsSamplingThreadRunning());
 }
 
 // Checks that it's safe to stop a task after it's completed and the sampling
 // thread has shut-down for being idle.
 PROFILER_TEST_F(StackSamplingProfilerTest, StopAfterIdleShutdown) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     SamplingParams params;
 
     params.sampling_interval = TimeDelta::FromMilliseconds(1);
@@ -1197,14 +1206,15 @@
     // Stop should be safe though its impossible to know at this moment if the
     // sampling thread has completely exited or will just "stop soon".
     profiler_info.profiler.Stop();
-  });
+  }));
 }
 
 // Checks that profilers can run both before and after the sampling thread has
 // started.
 PROFILER_TEST_F(StackSamplingProfilerTest,
                 ProfileBeforeAndAfterSamplingThreadRunning) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     std::vector<SamplingParams> params(2);
 
     params[0].initial_delay = AVeryLongTimeDelta();
@@ -1228,13 +1238,14 @@
     // Only the second profiler should finish before test times out.
     size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
     EXPECT_EQ(1U, completed_profiler);
-  });
+  }));
 }
 
 // Checks that an idle-shutdown task will abort if a new profiler starts
 // between when it was posted and when it runs.
 PROFILER_TEST_F(StackSamplingProfilerTest, IdleShutdownAbort) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     SamplingParams params;
 
     params.sampling_interval = TimeDelta::FromMilliseconds(1);
@@ -1244,7 +1255,7 @@
 
     profiler_info.profiler.Start();
     profiler_info.completed.Wait();
-    EXPECT_EQ(1u, profiler_info.profile.frame_sets.size());
+    EXPECT_EQ(1u, profiler_info.profile.samples.size());
 
     // Perform an idle shutdown but simulate that a new capture is started
     // before it can actually run.
@@ -1262,50 +1273,53 @@
     TestProfilerInfo another_info(target_thread_id, params, module_cache());
     another_info.profiler.Start();
     another_info.completed.Wait();
-    EXPECT_EQ(1u, another_info.profile.frame_sets.size());
-  });
+    EXPECT_EQ(1u, another_info.profile.samples.size());
+  }));
 }
 
 // Checks that synchronized multiple sampling requests execute in parallel.
 PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_InSync) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
-    std::vector<SamplingParams> params(2);
+  WithTargetThread(
+      BindLambdaForTesting([this](PlatformThreadId target_thread_id) {
+        std::vector<SamplingParams> params(2);
 
-    // Providing an initial delay makes it more likely that both will be
-    // scheduled before either starts to run. Once started, samples will
-    // run ordered by their scheduled, interleaved times regardless of
-    // whatever interval the thread wakes up. Thus, total execution time
-    // will be 10ms (delay) + 10x1ms (sampling) + 1/2 timer minimum interval.
-    params[0].initial_delay = TimeDelta::FromMilliseconds(10);
-    params[0].sampling_interval = TimeDelta::FromMilliseconds(1);
-    params[0].samples_per_profile = 9;
+        // Providing an initial delay makes it more likely that both will be
+        // scheduled before either starts to run. Once started, samples will
+        // run ordered by their scheduled, interleaved times regardless of
+        // whatever interval the thread wakes up. Thus, total execution time
+        // will be 10ms (delay) + 10x1ms (sampling) + 1/2 timer minimum
+        // interval.
+        params[0].initial_delay = TimeDelta::FromMilliseconds(10);
+        params[0].sampling_interval = TimeDelta::FromMilliseconds(1);
+        params[0].samples_per_profile = 9;
 
-    params[1].initial_delay = TimeDelta::FromMilliseconds(11);
-    params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
-    params[1].samples_per_profile = 8;
+        params[1].initial_delay = TimeDelta::FromMilliseconds(11);
+        params[1].sampling_interval = TimeDelta::FromMilliseconds(1);
+        params[1].samples_per_profile = 8;
 
-    std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
-        CreateProfilers(target_thread_id, params, module_cache());
+        std::vector<std::unique_ptr<TestProfilerInfo>> profiler_infos =
+            CreateProfilers(target_thread_id, params, module_cache());
 
-    profiler_infos[0]->profiler.Start();
-    profiler_infos[1]->profiler.Start();
+        profiler_infos[0]->profiler.Start();
+        profiler_infos[1]->profiler.Start();
 
-    // Wait for one profiler to finish.
-    size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
+        // Wait for one profiler to finish.
+        size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
 
-    size_t other_profiler = 1 - completed_profiler;
-    // Wait for the other profiler to finish.
-    profiler_infos[other_profiler]->completed.Wait();
+        size_t other_profiler = 1 - completed_profiler;
+        // Wait for the other profiler to finish.
+        profiler_infos[other_profiler]->completed.Wait();
 
-    // Ensure each got the correct number of frame sets.
-    EXPECT_EQ(9u, profiler_infos[0]->profile.frame_sets.size());
-    EXPECT_EQ(8u, profiler_infos[1]->profile.frame_sets.size());
-  });
+        // Ensure each got the correct number of samples.
+        EXPECT_EQ(9u, profiler_infos[0]->profile.samples.size());
+        EXPECT_EQ(8u, profiler_infos[1]->profile.samples.size());
+      }));
 }
 
 // Checks that several mixed sampling requests execute in parallel.
 PROFILER_TEST_F(StackSamplingProfilerTest, ConcurrentProfiling_Mixed) {
-  WithTargetThread([this](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([this](
+                                            PlatformThreadId target_thread_id) {
     std::vector<SamplingParams> params(3);
 
     params[0].initial_delay = TimeDelta::FromMilliseconds(8);
@@ -1328,14 +1342,13 @@
 
     // Wait for one profiler to finish.
     size_t completed_profiler = WaitForSamplingComplete(profiler_infos);
-    EXPECT_EQ(10u,
-              profiler_infos[completed_profiler]->profile.frame_sets.size());
+    EXPECT_EQ(10u, profiler_infos[completed_profiler]->profile.samples.size());
     // Stop and destroy all profilers, always in the same order. Don't crash.
     for (auto& i : profiler_infos)
       i->profiler.Stop();
     for (auto& i : profiler_infos)
       i.reset();
-  });
+  }));
 }
 
 // Checks that different threads can be sampled in parallel.
@@ -1404,8 +1417,8 @@
   profiler2.Start();
   sampling_thread_completed1.Wait();
   sampling_thread_completed2.Wait();
-  EXPECT_EQ(9u, profile1.frame_sets.size());
-  EXPECT_EQ(8u, profile2.frame_sets.size());
+  EXPECT_EQ(9u, profile1.samples.size());
+  EXPECT_EQ(8u, profile2.samples.size());
 
   events1.sample_finished.Signal();
   events2.sample_finished.Signal();
@@ -1455,7 +1468,7 @@
 
 // Checks that different threads can run samplers in parallel.
 PROFILER_TEST_F(StackSamplingProfilerTest, MultipleProfilerThreads) {
-  WithTargetThread([](PlatformThreadId target_thread_id) {
+  WithTargetThread(BindLambdaForTesting([](PlatformThreadId target_thread_id) {
     // Providing an initial delay makes it more likely that both will be
     // scheduled before either starts to run. Once started, samples will
     // run ordered by their scheduled, interleaved times regardless of
@@ -1486,12 +1499,12 @@
     // Wait for them both to finish and validate collection.
     profiler_thread1.Wait();
     profiler_thread2.Wait();
-    EXPECT_EQ(9u, profiler_thread1.profile().frame_sets.size());
-    EXPECT_EQ(8u, profiler_thread2.profile().frame_sets.size());
+    EXPECT_EQ(9u, profiler_thread1.profile().samples.size());
+    EXPECT_EQ(8u, profiler_thread2.profile().samples.size());
 
     profiler_thread1.Join();
     profiler_thread2.Join();
-  });
+  }));
 }
 
 PROFILER_TEST_F(StackSamplingProfilerTest, AddAuxUnwinder_BeforeStart) {
@@ -1502,7 +1515,8 @@
   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
 
   Profile profile;
-  WithTargetThread(&scenario, [&](PlatformThreadId target_thread_id) {
+  WithTargetThread(&scenario, BindLambdaForTesting([&](PlatformThreadId
+                                                           target_thread_id) {
     WaitableEvent sampling_thread_completed(
         WaitableEvent::ResetPolicy::MANUAL,
         WaitableEvent::InitialState::NOT_SIGNALED);
@@ -1519,12 +1533,12 @@
         std::make_unique<TestAuxUnwinder>(Frame(23, nullptr)));
     profiler.Start();
     sampling_thread_completed.Wait();
-  });
+  }));
 
   // The sample should have one frame from the context values and one from the
   // TestAuxUnwinder.
-  ASSERT_EQ(1u, profile.frame_sets.size());
-  const Frames& frames = profile.frame_sets[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  const std::vector<Frame>& frames = profile.samples[0];
 
   ASSERT_EQ(2u, frames.size());
   EXPECT_EQ(23u, frames[1].instruction_pointer);
@@ -1539,7 +1553,8 @@
   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
 
   Profile profile;
-  WithTargetThread(&scenario, [&](PlatformThreadId target_thread_id) {
+  WithTargetThread(&scenario, BindLambdaForTesting([&](PlatformThreadId
+                                                           target_thread_id) {
     WaitableEvent sampling_thread_completed(
         WaitableEvent::ResetPolicy::MANUAL,
         WaitableEvent::InitialState::NOT_SIGNALED);
@@ -1556,12 +1571,12 @@
     profiler.AddAuxUnwinder(
         std::make_unique<TestAuxUnwinder>(Frame(23, nullptr)));
     sampling_thread_completed.Wait();
-  });
+  }));
 
   // The sample should have one frame from the context values and one from the
   // TestAuxUnwinder.
-  ASSERT_EQ(1u, profile.frame_sets.size());
-  const Frames& frames = profile.frame_sets[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  const std::vector<Frame>& frames = profile.samples[0];
 
   ASSERT_EQ(2u, frames.size());
   EXPECT_EQ(23u, frames[1].instruction_pointer);
@@ -1576,7 +1591,8 @@
   UnwindScenario scenario(BindRepeating(&CallWithPlainFunction));
 
   Profile profile;
-  WithTargetThread(&scenario, [&](PlatformThreadId target_thread_id) {
+  WithTargetThread(&scenario, BindLambdaForTesting([&](PlatformThreadId
+                                                           target_thread_id) {
     WaitableEvent sampling_thread_completed(
         WaitableEvent::ResetPolicy::MANUAL,
         WaitableEvent::InitialState::NOT_SIGNALED);
@@ -1594,7 +1610,7 @@
     profiler.AddAuxUnwinder(
         std::make_unique<TestAuxUnwinder>(Frame(23, nullptr)));
     sampling_thread_completed.Wait();
-  });
+  }));
 
   // The AuxUnwinder should be accepted without error. It will have no effect
   // since the collection has stopped.
diff --git a/base/sampling_heap_profiler/module_cache_win.cc b/base/sampling_heap_profiler/module_cache_win.cc
index 639cbc9..ee62cd62 100644
--- a/base/sampling_heap_profiler/module_cache_win.cc
+++ b/base/sampling_heap_profiler/module_cache_win.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/pe_image.h"
 #include "base/win/scoped_handle.h"
+#include "base/win/win_util.h"
 
 namespace base {
 
@@ -52,12 +53,7 @@
     return;
   *pdb_name = FilePath(std::move(pdb_filename)).BaseName();
 
-  const int kGUIDSize = 39;
-  string16 buffer;
-  int result = ::StringFromGUID2(
-      guid, as_writable_wcstr(WriteInto(&buffer, kGUIDSize)), kGUIDSize);
-  if (result != kGUIDSize)
-    return;
+  auto buffer = win::String16FromGUID(guid);
   RemoveChars(buffer, STRING16_LITERAL("{}-"), &buffer);
   buffer.append(NumberToString16(age));
   *build_id = UTF16ToUTF8(buffer);
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 4de71656d..e975107f 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -383,6 +383,10 @@
 inline bool IsAsciiDigit(Char c) {
   return c >= '0' && c <= '9';
 }
+template <typename Char>
+inline bool IsAsciiPrintable(Char c) {
+  return c >= ' ' && c <= '~';
+}
 
 template <typename Char>
 inline bool IsHexDigit(Char c) {
diff --git a/base/task/common/checked_lock.h b/base/task/common/checked_lock.h
new file mode 100644
index 0000000..29ce5735
--- /dev/null
+++ b/base/task/common/checked_lock.h
@@ -0,0 +1,131 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TASK_COMMON_CHECKED_LOCK_H_
+#define BASE_TASK_COMMON_CHECKED_LOCK_H_
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/task/common/checked_lock_impl.h"
+#include "base/thread_annotations.h"
+
+namespace base {
+namespace internal {
+
+// CheckedLock should be used anywhere a Lock would be used in the base/task
+// impl. When DCHECK_IS_ON(), lock checking occurs. Otherwise, CheckedLock is
+// equivalent to base::Lock.
+//
+// The shape of CheckedLock is as follows:
+// CheckedLock()
+//     Default constructor, no predecessor lock.
+//     DCHECKs
+//         On Acquisition if any CheckedLock is acquired on this thread.
+//             Okay if a universal predecessor is acquired.
+//
+// CheckedLock(const CheckedLock* predecessor)
+//     Constructor that specifies an allowed predecessor for that lock.
+//     DCHECKs
+//         On Construction if |predecessor| forms a predecessor lock cycle.
+//         On Acquisition if the previous lock acquired on the thread is not
+//             either |predecessor| or a universal predecessor. Okay if there
+//             was no previous lock acquired.
+//
+// CheckedLock(UniversalPredecessor universal_predecessor)
+//     Constructor for a lock that will allow the acquisition of any lock after
+//     it, without needing to explicitly be named a predecessor. Can only be
+//     acquired if no locks are currently held by this thread.
+//     DCHECKs
+//         On Acquisition if any CheckedLock is acquired on this thread.
+//
+// void Acquire()
+//     Acquires the lock.
+//
+// void Release()
+//     Releases the lock.
+//
+// void AssertAcquired().
+//     DCHECKs if the lock is not acquired.
+//
+// std::unique_ptr<ConditionVariable> CreateConditionVariable()
+//     Creates a condition variable using this as a lock.
+
+#if DCHECK_IS_ON()
+class LOCKABLE CheckedLock : public CheckedLockImpl {
+ public:
+  CheckedLock() = default;
+  explicit CheckedLock(const CheckedLock* predecessor)
+      : CheckedLockImpl(predecessor) {}
+  explicit CheckedLock(UniversalPredecessor universal_predecessor)
+      : CheckedLockImpl(universal_predecessor) {}
+};
+#else   // DCHECK_IS_ON()
+class LOCKABLE CheckedLock : public Lock {
+ public:
+  CheckedLock() = default;
+  explicit CheckedLock(const CheckedLock*) {}
+  explicit CheckedLock(UniversalPredecessor) {}
+  static void AssertNoLockHeldOnCurrentThread() {}
+
+  std::unique_ptr<ConditionVariable> CreateConditionVariable() {
+    return std::unique_ptr<ConditionVariable>(new ConditionVariable(this));
+  }
+};
+#endif  // DCHECK_IS_ON()
+
+// Provides the same functionality as base::AutoLock for CheckedLock.
+using CheckedAutoLock = internal::BasicAutoLock<CheckedLock>;
+
+// Provides the same functionality as base::AutoUnlock for CheckedLock.
+using CheckedAutoUnlock = internal::BasicAutoUnlock<CheckedLock>;
+
+// Provides the same functionality as base::AutoLockMaybe for CheckedLock.
+using CheckedAutoLockMaybe = internal::BasicAutoLockMaybe<CheckedLock>;
+
+// Informs the clang thread safety analysis that an aliased lock is acquired.
+// Because the clang thread safety analysis doesn't understand aliased locks
+// [1], this code wouldn't compile without AnnotateAcquiredLockAlias:
+//
+// class Example {
+//  public:
+//    CheckedLock lock_;
+//    int value = 0 GUARDED_BY(lock_);
+// };
+//
+// Example example;
+// CheckedLock* acquired = &example.lock_;
+// CheckedAutoLock auto_lock(*acquired);
+// AnnotateAcquiredLockAlias annotate(*acquired, example.lock_);
+// example.value = 42;  // Doesn't compile without |annotate|.
+//
+// [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis
+class SCOPED_LOCKABLE AnnotateAcquiredLockAlias {
+ public:
+  // |acquired_lock| is an acquired lock. |lock_alias| is an alias of
+  // |acquired_lock|.
+  AnnotateAcquiredLockAlias(const CheckedLock& acquired_lock,
+                            const CheckedLock& lock_alias)
+      EXCLUSIVE_LOCK_FUNCTION(lock_alias)
+      : acquired_lock_(acquired_lock) {
+    DCHECK_EQ(&acquired_lock, &lock_alias);
+    acquired_lock_.AssertAcquired();
+  }
+  ~AnnotateAcquiredLockAlias() UNLOCK_FUNCTION() {
+    acquired_lock_.AssertAcquired();
+  }
+
+ private:
+  const CheckedLock& acquired_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnnotateAcquiredLockAlias);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_TASK_COMMON_CHECKED_LOCK_H_
diff --git a/base/task/thread_pool/scheduler_lock_impl.cc b/base/task/common/checked_lock_impl.cc
similarity index 67%
rename from base/task/thread_pool/scheduler_lock_impl.cc
rename to base/task/common/checked_lock_impl.cc
index b6f62e3..c801f05 100644
--- a/base/task/thread_pool/scheduler_lock_impl.cc
+++ b/base/task/common/checked_lock_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/task/thread_pool/scheduler_lock_impl.h"
+#include "base/task/common/checked_lock_impl.h"
 
 #include <algorithm>
 #include <unordered_map>
@@ -11,7 +11,7 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/synchronization/condition_variable.h"
-#include "base/task/thread_pool/scheduler_lock.h"
+#include "base/task/common/checked_lock.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/thread_local.h"
 
@@ -24,25 +24,25 @@
  public:
   SafeAcquisitionTracker() = default;
 
-  void RegisterLock(const SchedulerLockImpl* const lock,
-                    const SchedulerLockImpl* const predecessor) {
+  void RegisterLock(const CheckedLockImpl* const lock,
+                    const CheckedLockImpl* const predecessor) {
     DCHECK_NE(lock, predecessor) << "Reentrant locks are unsupported.";
     AutoLock auto_lock(allowed_predecessor_map_lock_);
     allowed_predecessor_map_[lock] = predecessor;
     AssertSafePredecessor(lock);
   }
 
-  void UnregisterLock(const SchedulerLockImpl* const lock) {
+  void UnregisterLock(const CheckedLockImpl* const lock) {
     AutoLock auto_lock(allowed_predecessor_map_lock_);
     allowed_predecessor_map_.erase(lock);
   }
 
-  void RecordAcquisition(const SchedulerLockImpl* const lock) {
+  void RecordAcquisition(const CheckedLockImpl* const lock) {
     AssertSafeAcquire(lock);
     GetAcquiredLocksOnCurrentThread()->push_back(lock);
   }
 
-  void RecordRelease(const SchedulerLockImpl* const lock) {
+  void RecordRelease(const CheckedLockImpl* const lock) {
     LockVector* acquired_locks = GetAcquiredLocksOnCurrentThread();
     const auto iter_at_lock =
         std::find(acquired_locks->begin(), acquired_locks->end(), lock);
@@ -55,13 +55,13 @@
   }
 
  private:
-  using LockVector = std::vector<const SchedulerLockImpl*>;
+  using LockVector = std::vector<const CheckedLockImpl*>;
   using PredecessorMap =
-      std::unordered_map<const SchedulerLockImpl*, const SchedulerLockImpl*>;
+      std::unordered_map<const CheckedLockImpl*, const CheckedLockImpl*>;
 
   // This asserts that the lock is safe to acquire. This means that this should
   // be run before actually recording the acquisition.
-  void AssertSafeAcquire(const SchedulerLockImpl* const lock) {
+  void AssertSafeAcquire(const CheckedLockImpl* const lock) {
     const LockVector* acquired_locks = GetAcquiredLocksOnCurrentThread();
 
     // If the thread currently holds no locks, this is inherently safe.
@@ -73,34 +73,34 @@
 
     // Otherwise, make sure that the previous lock acquired is either an
     // allowed predecessor for this lock or a universal predecessor.
-    const SchedulerLockImpl* previous_lock = acquired_locks->back();
+    const CheckedLockImpl* previous_lock = acquired_locks->back();
     if (previous_lock->is_universal_predecessor())
       return;
 
     AutoLock auto_lock(allowed_predecessor_map_lock_);
     // Using at() is exception-safe here as |lock| was registered already.
-    const SchedulerLockImpl* allowed_predecessor =
+    const CheckedLockImpl* allowed_predecessor =
         allowed_predecessor_map_.at(lock);
     DCHECK_EQ(previous_lock, allowed_predecessor);
   }
 
   // Asserts that |lock|'s registered predecessor is safe. Because
-  // SchedulerLocks are registered at construction time and any predecessor
-  // specified on a SchedulerLock must already exist, the first registered
-  // SchedulerLock in a potential chain must have a null predecessor and is thus
-  // cycle-free. Any subsequent SchedulerLock with a predecessor must come from
-  // the set of registered SchedulerLocks. Since the registered SchedulerLocks
-  // only contain cycle-free SchedulerLocks, this subsequent SchedulerLock is
-  // itself cycle-free and may be safely added to the registered SchedulerLock
+  // CheckedLocks are registered at construction time and any predecessor
+  // specified on a CheckedLock must already exist, the first registered
+  // CheckedLock in a potential chain must have a null predecessor and is thus
+  // cycle-free. Any subsequent CheckedLock with a predecessor must come from
+  // the set of registered CheckedLocks. Since the registered CheckedLocks
+  // only contain cycle-free CheckedLocks, this subsequent CheckedLock is
+  // itself cycle-free and may be safely added to the registered CheckedLock
   // set.
-  void AssertSafePredecessor(const SchedulerLockImpl* lock) const {
+  void AssertSafePredecessor(const CheckedLockImpl* lock) const {
     allowed_predecessor_map_lock_.AssertAcquired();
     // Using at() is exception-safe here as |lock| was registered already.
-    const SchedulerLockImpl* predecessor = allowed_predecessor_map_.at(lock);
+    const CheckedLockImpl* predecessor = allowed_predecessor_map_.at(lock);
     if (predecessor) {
       DCHECK(allowed_predecessor_map_.find(predecessor) !=
              allowed_predecessor_map_.end())
-          << "SchedulerLock was registered before its predecessor. "
+          << "CheckedLock was registered before its predecessor. "
           << "Potential cycle detected";
     }
   }
@@ -130,40 +130,39 @@
 
 }  // namespace
 
-SchedulerLockImpl::SchedulerLockImpl() : SchedulerLockImpl(nullptr) {}
+CheckedLockImpl::CheckedLockImpl() : CheckedLockImpl(nullptr) {}
 
-SchedulerLockImpl::SchedulerLockImpl(const SchedulerLockImpl* predecessor)
+CheckedLockImpl::CheckedLockImpl(const CheckedLockImpl* predecessor)
     : is_universal_predecessor_(false) {
   g_safe_acquisition_tracker.Get().RegisterLock(this, predecessor);
 }
 
-SchedulerLockImpl::SchedulerLockImpl(UniversalPredecessor)
+CheckedLockImpl::CheckedLockImpl(UniversalPredecessor)
     : is_universal_predecessor_(true) {}
 
-SchedulerLockImpl::~SchedulerLockImpl() {
+CheckedLockImpl::~CheckedLockImpl() {
   g_safe_acquisition_tracker.Get().UnregisterLock(this);
 }
 
-void SchedulerLockImpl::AssertNoLockHeldOnCurrentThread() {
+void CheckedLockImpl::AssertNoLockHeldOnCurrentThread() {
   g_safe_acquisition_tracker.Get().AssertNoLockHeldOnCurrentThread();
 }
 
-void SchedulerLockImpl::Acquire() {
+void CheckedLockImpl::Acquire() {
   lock_.Acquire();
   g_safe_acquisition_tracker.Get().RecordAcquisition(this);
 }
 
-void SchedulerLockImpl::Release() {
+void CheckedLockImpl::Release() {
   lock_.Release();
   g_safe_acquisition_tracker.Get().RecordRelease(this);
 }
 
-void SchedulerLockImpl::AssertAcquired() const {
+void CheckedLockImpl::AssertAcquired() const {
   lock_.AssertAcquired();
 }
 
-std::unique_ptr<ConditionVariable>
-SchedulerLockImpl::CreateConditionVariable() {
+std::unique_ptr<ConditionVariable> CheckedLockImpl::CreateConditionVariable() {
   return std::make_unique<ConditionVariable>(&lock_);
 }
 
diff --git a/base/task/thread_pool/scheduler_lock_impl.h b/base/task/common/checked_lock_impl.h
similarity index 69%
rename from base/task/thread_pool/scheduler_lock_impl.h
rename to base/task/common/checked_lock_impl.h
index 0b827bf..2a3dac6 100644
--- a/base/task/thread_pool/scheduler_lock_impl.h
+++ b/base/task/common/checked_lock_impl.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef BASE_TASK_THREAD_POOL_SCHEDULER_LOCK_IMPL_H_
-#define BASE_TASK_THREAD_POOL_SCHEDULER_LOCK_IMPL_H_
+#ifndef BASE_TASK_COMMON_CHECKED_LOCK_IMPL_H_
+#define BASE_TASK_COMMON_CHECKED_LOCK_IMPL_H_
 
 #include <memory>
 
@@ -23,12 +23,12 @@
 // This lock tracks all of the available locks to make sure that any locks are
 // acquired in an expected order.
 // See scheduler_lock.h for details.
-class BASE_EXPORT SchedulerLockImpl {
+class BASE_EXPORT CheckedLockImpl {
  public:
-  SchedulerLockImpl();
-  explicit SchedulerLockImpl(const SchedulerLockImpl* predecessor);
-  explicit SchedulerLockImpl(UniversalPredecessor);
-  ~SchedulerLockImpl();
+  CheckedLockImpl();
+  explicit CheckedLockImpl(const CheckedLockImpl* predecessor);
+  explicit CheckedLockImpl(UniversalPredecessor);
+  ~CheckedLockImpl();
 
   static void AssertNoLockHeldOnCurrentThread();
 
@@ -45,10 +45,10 @@
   Lock lock_;
   const bool is_universal_predecessor_;
 
-  DISALLOW_COPY_AND_ASSIGN(SchedulerLockImpl);
+  DISALLOW_COPY_AND_ASSIGN(CheckedLockImpl);
 };
 
 }  // namespace internal
 }  // namespace base
 
-#endif  // BASE_TASK_THREAD_POOL_SCHEDULER_LOCK_IMPL_H_
+#endif  // BASE_TASK_COMMON_CHECKED_LOCK_IMPL_H_
diff --git a/base/task/thread_pool/scheduler_lock_unittest.cc b/base/task/common/checked_lock_unittest.cc
similarity index 70%
rename from base/task/thread_pool/scheduler_lock_unittest.cc
rename to base/task/common/checked_lock_unittest.cc
index f572774..85223cc 100644
--- a/base/task/thread_pool/scheduler_lock_unittest.cc
+++ b/base/task/common/checked_lock_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/task/thread_pool/scheduler_lock.h"
+#include "base/task/common/checked_lock.h"
 
 #include <stdlib.h>
 
@@ -23,7 +23,7 @@
 // Acquire()/Release() don't crash.
 class BasicLockTestThread : public SimpleThread {
  public:
-  explicit BasicLockTestThread(SchedulerLock* lock)
+  explicit BasicLockTestThread(CheckedLock* lock)
       : SimpleThread("BasicLockTestThread"), lock_(lock), acquired_(0) {}
 
   int acquired() const { return acquired_; }
@@ -43,7 +43,7 @@
     }
   }
 
-  SchedulerLock* const lock_;
+  CheckedLock* const lock_;
   int acquired_;
 
   DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
@@ -51,7 +51,7 @@
 
 class BasicLockAcquireAndWaitThread : public SimpleThread {
  public:
-  explicit BasicLockAcquireAndWaitThread(SchedulerLock* lock)
+  explicit BasicLockAcquireAndWaitThread(CheckedLock* lock)
       : SimpleThread("BasicLockAcquireAndWaitThread"),
         lock_(lock),
         lock_acquire_event_(WaitableEvent::ResetPolicy::AUTOMATIC,
@@ -72,7 +72,7 @@
     lock_->Release();
   }
 
-  SchedulerLock* const lock_;
+  CheckedLock* const lock_;
   WaitableEvent lock_acquire_event_;
   WaitableEvent main_thread_continue_event_;
 
@@ -81,8 +81,8 @@
 
 }  // namespace
 
-TEST(ThreadPoolLock, Basic) {
-  SchedulerLock lock;
+TEST(CheckedLockTest, Basic) {
+  CheckedLock lock;
   BasicLockTestThread thread(&lock);
 
   thread.Start();
@@ -112,37 +112,37 @@
   EXPECT_EQ(thread.acquired(), 20);
 }
 
-TEST(ThreadPoolLock, AcquirePredecessor) {
-  SchedulerLock predecessor;
-  SchedulerLock lock(&predecessor);
+TEST(CheckedLockTest, AcquirePredecessor) {
+  CheckedLock predecessor;
+  CheckedLock lock(&predecessor);
   predecessor.Acquire();
   lock.Acquire();
   lock.Release();
   predecessor.Release();
 }
 
-TEST(ThreadPoolLock, AcquirePredecessorWrongOrder) {
-  SchedulerLock predecessor;
-  SchedulerLock lock(&predecessor);
+TEST(CheckedLockTest, AcquirePredecessorWrongOrder) {
+  CheckedLock predecessor;
+  CheckedLock lock(&predecessor);
   EXPECT_DCHECK_DEATH({
     lock.Acquire();
     predecessor.Acquire();
   });
 }
 
-TEST(ThreadPoolLock, AcquireNonPredecessor) {
-  SchedulerLock lock1;
-  SchedulerLock lock2;
+TEST(CheckedLockTest, AcquireNonPredecessor) {
+  CheckedLock lock1;
+  CheckedLock lock2;
   EXPECT_DCHECK_DEATH({
     lock1.Acquire();
     lock2.Acquire();
   });
 }
 
-TEST(ThreadPoolLock, AcquireMultipleLocksInOrder) {
-  SchedulerLock lock1;
-  SchedulerLock lock2(&lock1);
-  SchedulerLock lock3(&lock2);
+TEST(CheckedLockTest, AcquireMultipleLocksInOrder) {
+  CheckedLock lock1;
+  CheckedLock lock2(&lock1);
+  CheckedLock lock3(&lock2);
   lock1.Acquire();
   lock2.Acquire();
   lock3.Acquire();
@@ -151,29 +151,29 @@
   lock1.Release();
 }
 
-TEST(ThreadPoolLock, AcquireMultipleLocksInTheMiddleOfAChain) {
-  SchedulerLock lock1;
-  SchedulerLock lock2(&lock1);
-  SchedulerLock lock3(&lock2);
+TEST(CheckedLockTest, AcquireMultipleLocksInTheMiddleOfAChain) {
+  CheckedLock lock1;
+  CheckedLock lock2(&lock1);
+  CheckedLock lock3(&lock2);
   lock2.Acquire();
   lock3.Acquire();
   lock3.Release();
   lock2.Release();
 }
 
-TEST(ThreadPoolLock, AcquireMultipleLocksNoTransitivity) {
-  SchedulerLock lock1;
-  SchedulerLock lock2(&lock1);
-  SchedulerLock lock3(&lock2);
+TEST(CheckedLockTest, AcquireMultipleLocksNoTransitivity) {
+  CheckedLock lock1;
+  CheckedLock lock2(&lock1);
+  CheckedLock lock3(&lock2);
   EXPECT_DCHECK_DEATH({
     lock1.Acquire();
     lock3.Acquire();
   });
 }
 
-TEST(ThreadPoolLock, AcquireLocksDifferentThreadsSafely) {
-  SchedulerLock lock1;
-  SchedulerLock lock2;
+TEST(CheckedLockTest, AcquireLocksDifferentThreadsSafely) {
+  CheckedLock lock1;
+  CheckedLock lock2;
   BasicLockAcquireAndWaitThread thread(&lock1);
   thread.Start();
 
@@ -184,7 +184,7 @@
   lock2.Release();
 }
 
-TEST(ThreadPoolLock,
+TEST(CheckedLockTest,
      AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorFirst) {
   // A lock and its predecessor may be safely acquired on different threads.
   // This Thread                Other Thread
@@ -192,8 +192,8 @@
   //                            lock.Acquire()
   // predecessor.Release()
   //                            lock.Release()
-  SchedulerLock predecessor;
-  SchedulerLock lock(&predecessor);
+  CheckedLock predecessor;
+  CheckedLock lock(&predecessor);
   predecessor.Acquire();
   BasicLockAcquireAndWaitThread thread(&lock);
   thread.Start();
@@ -203,7 +203,7 @@
   thread.Join();
 }
 
-TEST(ThreadPoolLock,
+TEST(CheckedLockTest,
      AcquireLocksWithPredecessorDifferentThreadsSafelyPredecessorLast) {
   // A lock and its predecessor may be safely acquired on different threads.
   // This Thread                Other Thread
@@ -211,8 +211,8 @@
   //                            predecessor.Acquire()
   // lock.Release()
   //                            predecessor.Release()
-  SchedulerLock predecessor;
-  SchedulerLock lock(&predecessor);
+  CheckedLock predecessor;
+  CheckedLock lock(&predecessor);
   lock.Acquire();
   BasicLockAcquireAndWaitThread thread(&predecessor);
   thread.Start();
@@ -222,7 +222,7 @@
   thread.Join();
 }
 
-TEST(ThreadPoolLock,
+TEST(CheckedLockTest,
      AcquireLocksWithPredecessorDifferentThreadsSafelyNoInterference) {
   // Acquisition of an unrelated lock on another thread should not affect a
   // legal lock acquisition with a predecessor on this thread.
@@ -233,10 +233,10 @@
   //                            unrelated.Release()
   // lock.Release()
   // predecessor.Release();
-  SchedulerLock predecessor;
-  SchedulerLock lock(&predecessor);
+  CheckedLock predecessor;
+  CheckedLock lock(&predecessor);
   predecessor.Acquire();
-  SchedulerLock unrelated;
+  CheckedLock unrelated;
   BasicLockAcquireAndWaitThread thread(&unrelated);
   thread.Start();
   thread.WaitForLockAcquisition();
@@ -247,28 +247,28 @@
   predecessor.Release();
 }
 
-TEST(ThreadPoolLock, SelfReferentialLock) {
+TEST(CheckedLockTest, SelfReferentialLock) {
   struct SelfReferentialLock {
     SelfReferentialLock() : lock(&lock) {}
 
-    SchedulerLock lock;
+    CheckedLock lock;
   };
 
   EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; });
 }
 
-TEST(ThreadPoolLock, PredecessorCycle) {
+TEST(CheckedLockTest, PredecessorCycle) {
   struct LockCycle {
     LockCycle() : lock1(&lock2), lock2(&lock1) {}
 
-    SchedulerLock lock1;
-    SchedulerLock lock2;
+    CheckedLock lock1;
+    CheckedLock lock2;
   };
 
   EXPECT_DCHECK_DEATH({ LockCycle cycle; });
 }
 
-TEST(ThreadPoolLock, PredecessorLongerCycle) {
+TEST(CheckedLockTest, PredecessorLongerCycle) {
   struct LockCycle {
     LockCycle()
         : lock1(&lock5),
@@ -277,21 +277,21 @@
           lock4(&lock3),
           lock5(&lock4) {}
 
-    SchedulerLock lock1;
-    SchedulerLock lock2;
-    SchedulerLock lock3;
-    SchedulerLock lock4;
-    SchedulerLock lock5;
+    CheckedLock lock1;
+    CheckedLock lock2;
+    CheckedLock lock3;
+    CheckedLock lock4;
+    CheckedLock lock5;
   };
 
   EXPECT_DCHECK_DEATH({ LockCycle cycle; });
 }
 
-TEST(ThreadPoolLock, AcquireLockAfterUniversalPredecessor) {
+TEST(CheckedLockTest, AcquireLockAfterUniversalPredecessor) {
   // Acquisition of a universal-predecessor lock should not prevent acquisition
-  // of a SchedulerLock after it.
-  SchedulerLock universal_predecessor((UniversalPredecessor()));
-  SchedulerLock lock;
+  // of a CheckedLock after it.
+  CheckedLock universal_predecessor((UniversalPredecessor()));
+  CheckedLock lock;
 
   universal_predecessor.Acquire();
   lock.Acquire();
@@ -299,13 +299,13 @@
   universal_predecessor.Release();
 }
 
-TEST(ThreadPoolLock, AcquireMultipleLocksAfterUniversalPredecessor) {
+TEST(CheckedLockTest, AcquireMultipleLocksAfterUniversalPredecessor) {
   // Acquisition of a universal-predecessor lock does not affect acquisition
   // rules for locks beyond the one acquired directly after it.
-  SchedulerLock universal_predecessor((UniversalPredecessor()));
-  SchedulerLock lock;
-  SchedulerLock lock2(&lock);
-  SchedulerLock lock3;
+  CheckedLock universal_predecessor((UniversalPredecessor()));
+  CheckedLock lock;
+  CheckedLock lock2(&lock);
+  CheckedLock lock3;
 
   universal_predecessor.Acquire();
   lock.Acquire();
@@ -321,10 +321,10 @@
   });
 }
 
-TEST(ThreadPoolLock, AcquireUniversalPredecessorAfterLock) {
+TEST(CheckedLockTest, AcquireUniversalPredecessorAfterLock) {
   // A universal-predecessor lock may not be acquired after any other lock.
-  SchedulerLock universal_predecessor((UniversalPredecessor()));
-  SchedulerLock lock;
+  CheckedLock universal_predecessor((UniversalPredecessor()));
+  CheckedLock lock;
 
   EXPECT_DCHECK_DEATH({
     lock.Acquire();
@@ -332,11 +332,11 @@
   });
 }
 
-TEST(ThreadPoolLock, AcquireUniversalPredecessorAfterUniversalPredecessor) {
+TEST(CheckedLockTest, AcquireUniversalPredecessorAfterUniversalPredecessor) {
   // A universal-predecessor lock may not be acquired after any other lock, not
   // even another universal predecessor.
-  SchedulerLock universal_predecessor((UniversalPredecessor()));
-  SchedulerLock universal_predecessor2((UniversalPredecessor()));
+  CheckedLock universal_predecessor((UniversalPredecessor()));
+  CheckedLock universal_predecessor2((UniversalPredecessor()));
 
   EXPECT_DCHECK_DEATH({
     universal_predecessor.Acquire();
@@ -344,15 +344,15 @@
   });
 }
 
-TEST(ThreadPoolLock, AssertNoLockHeldOnCurrentThread) {
+TEST(CheckedLockTest, AssertNoLockHeldOnCurrentThread) {
   // AssertNoLockHeldOnCurrentThread() shouldn't fail when no lock is acquired.
-  SchedulerLock::AssertNoLockHeldOnCurrentThread();
+  CheckedLock::AssertNoLockHeldOnCurrentThread();
 
   // AssertNoLockHeldOnCurrentThread() should fail when a lock is acquired.
-  SchedulerLock lock;
+  CheckedLock lock;
   {
-    AutoSchedulerLock auto_lock(lock);
-    EXPECT_DCHECK_DEATH({ SchedulerLock::AssertNoLockHeldOnCurrentThread(); });
+    CheckedAutoLock auto_lock(lock);
+    EXPECT_DCHECK_DEATH({ CheckedLock::AssertNoLockHeldOnCurrentThread(); });
   }
 }
 
@@ -360,16 +360,16 @@
 
 class MemberGuardedByLock {
  public:
-  SchedulerLock lock_;
+  CheckedLock lock_;
   int value GUARDED_BY(lock_) = 0;
 };
 
 }  // namespace
 
-TEST(ThreadPoolLock, AnnotateAcquiredLockAlias) {
+TEST(CheckedLockTest, AnnotateAcquiredLockAlias) {
   MemberGuardedByLock member_guarded_by_lock;
-  SchedulerLock* acquired = &member_guarded_by_lock.lock_;
-  AutoSchedulerLock auto_lock(*acquired);
+  CheckedLock* acquired = &member_guarded_by_lock.lock_;
+  CheckedAutoLock auto_lock(*acquired);
   AnnotateAcquiredLockAlias annotate(*acquired, member_guarded_by_lock.lock_);
   member_guarded_by_lock.value = 42;  // Doesn't compile without |annotate|.
 }
diff --git a/base/task/lazy_task_runner.cc b/base/task/lazy_task_runner.cc
index 20bac91..fc80c8e7 100644
--- a/base/task/lazy_task_runner.cc
+++ b/base/task/lazy_task_runner.cc
@@ -107,14 +107,14 @@
 }
 
 ScopedLazyTaskRunnerListForTesting::~ScopedLazyTaskRunnerListForTesting() {
-  internal::AutoSchedulerLock auto_lock(lock_);
+  internal::CheckedAutoLock auto_lock(lock_);
   for (auto& callback : callbacks_)
     std::move(callback).Run();
   g_scoped_lazy_task_runner_list_for_testing = nullptr;
 }
 
 void ScopedLazyTaskRunnerListForTesting::AddCallback(OnceClosure callback) {
-  internal::AutoSchedulerLock auto_lock(lock_);
+  internal::CheckedAutoLock auto_lock(lock_);
   callbacks_.push_back(std::move(callback));
 }
 
diff --git a/base/task/lazy_task_runner.h b/base/task/lazy_task_runner.h
index 544d3473..68d19a68 100644
--- a/base/task/lazy_task_runner.h
+++ b/base/task/lazy_task_runner.h
@@ -13,9 +13,9 @@
 #include "base/lazy_instance_helpers.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/single_thread_task_runner_thread_mode.h"
 #include "base/task/task_traits.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/thread_annotations.h"
 #include "build/build_config.h"
 
@@ -204,7 +204,7 @@
   // Add |callback| to the list of callbacks to run on destruction.
   void AddCallback(OnceClosure callback);
 
-  SchedulerLock lock_;
+  CheckedLock lock_;
 
   // List of callbacks to run on destruction.
   std::vector<OnceClosure> callbacks_ GUARDED_BY(lock_);
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc
index 3d82c2c..b3e01b0 100644
--- a/base/task/sequence_manager/task_queue.cc
+++ b/base/task/sequence_manager/task_queue.cc
@@ -176,8 +176,8 @@
 scoped_refptr<SingleThreadTaskRunner> TaskQueue::CreateTaskRunner(
     TaskType task_type) {
   // We only need to lock if we're not on the main thread.
-  base::internal::AutoSchedulerLockMaybe lock(IsOnMainThread() ? &impl_lock_
-                                                               : nullptr);
+  base::internal::CheckedAutoLockMaybe lock(IsOnMainThread() ? &impl_lock_
+                                                             : nullptr);
   if (!impl_)
     return CreateNullTaskRunner();
   return impl_->CreateTaskRunner(task_type);
@@ -331,7 +331,7 @@
 }
 
 std::unique_ptr<internal::TaskQueueImpl> TaskQueue::TakeTaskQueueImpl() {
-  base::internal::AutoSchedulerLock lock(impl_lock_);
+  base::internal::CheckedAutoLock lock(impl_lock_);
   DCHECK(impl_);
   return std::move(impl_);
 }
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h
index e90891c3..71449ee 100644
--- a/base/task/sequence_manager/task_queue.h
+++ b/base/task/sequence_manager/task_queue.h
@@ -12,10 +12,10 @@
 #include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/sequence_manager/lazy_now.h"
 #include "base/task/sequence_manager/tasks.h"
 #include "base/task/task_observer.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/threading/platform_thread.h"
 #include "base/time/time.h"
 
@@ -354,7 +354,7 @@
   // |impl_lock_| must be acquired when writing to |impl_| or when accessing
   // it from non-main thread. Reading from the main thread does not require
   // a lock.
-  mutable base::internal::SchedulerLock impl_lock_{
+  mutable base::internal::CheckedLock impl_lock_{
       base::internal::UniversalPredecessor{}};
   std::unique_ptr<internal::TaskQueueImpl> impl_;
 
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
index 048e531..6cf3842 100644
--- a/base/task/sequence_manager/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -114,7 +114,7 @@
 
 TaskQueueImpl::~TaskQueueImpl() {
 #if DCHECK_IS_ON()
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   // NOTE this check shouldn't fire because |SequenceManagerImpl::queues_|
   // contains a strong reference to this TaskQueueImpl and the
   // SequenceManagerImpl destructor calls UnregisterTaskQueue on all task
@@ -160,7 +160,7 @@
   TaskDeque immediate_incoming_queue;
 
   {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     any_thread_.unregistered = true;
     any_thread_.time_domain = nullptr;
     immediate_incoming_queue.swap(any_thread_.immediate_incoming_queue);
@@ -231,7 +231,7 @@
                                          CurrentThread current_thread) {
 #if DCHECK_IS_ON()
   if (current_thread == TaskQueueImpl::CurrentThread::kNotMainThread) {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     // Add a per-priority delay to cross thread tasks. This can help diagnose
     // scheduler induced flakiness by making things flake most of the time.
     task->delay +=
@@ -255,7 +255,7 @@
   {
     // TODO(alexclarke): Maybe add a main thread only immediate_incoming_queue
     // See https://crbug.com/901800
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     TimeTicks now;
     bool add_queue_time_to_tasks = sequence_manager_->GetAddQueueTimeToTasks();
     if (delayed_fence_allowed_ || add_queue_time_to_tasks) {
@@ -351,7 +351,7 @@
 
     TimeTicks time_domain_now;
     {
-      base::internal::AutoSchedulerLock lock(any_thread_lock_);
+      base::internal::CheckedAutoLock lock(any_thread_lock_);
       time_domain_now = any_thread_.time_domain->Now();
     }
     TimeTicks time_domain_delayed_run_time = time_domain_now + task.delay;
@@ -433,7 +433,7 @@
 }
 
 void TaskQueueImpl::TakeImmediateIncomingQueueTasks(TaskDeque* queue) {
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   DCHECK(queue->empty());
   queue->swap(any_thread_.immediate_incoming_queue);
 
@@ -473,7 +473,7 @@
     return false;
   }
 
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   return any_thread_.immediate_incoming_queue.empty();
 }
 
@@ -483,7 +483,7 @@
   task_count += main_thread_only().delayed_incoming_queue.size();
   task_count += main_thread_only().immediate_work_queue->Size();
 
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   task_count += any_thread_.immediate_incoming_queue.size();
   return task_count;
 }
@@ -504,7 +504,7 @@
   }
 
   // Finally tasks on |immediate_incoming_queue| count as immediate work.
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   return !any_thread_.immediate_incoming_queue.empty();
 }
 
@@ -565,7 +565,7 @@
   if (!associated_thread_->IsBoundToCurrentThread())
     return;
 
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   TRACE_COUNTER_WITH_FLAG1(
       TRACE_DISABLED_BY_DEFAULT("sequence_manager"), GetName(),
       TRACE_EVENT_FLAG_DISALLOW_POSTTASK,
@@ -591,7 +591,7 @@
 void TaskQueueImpl::AsValueInto(TimeTicks now,
                                 trace_event::TracedValue* state,
                                 bool force_verbose) const {
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   state->BeginDictionary();
   state->SetString("name", GetName());
   if (any_thread_.unregistered) {
@@ -691,7 +691,7 @@
 
 void TaskQueueImpl::SetTimeDomain(TimeDomain* time_domain) {
   {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     DCHECK(time_domain);
     DCHECK(!any_thread_.unregistered);
     if (any_thread_.unregistered)
@@ -743,7 +743,7 @@
       main_thread_only().delayed_work_queue->InsertFence(current_fence);
 
   {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     if (!task_unblocked && previous_fence && previous_fence < current_fence) {
       if (!any_thread_.immediate_incoming_queue.empty() &&
           any_thread_.immediate_incoming_queue.front().enqueue_order() >
@@ -780,7 +780,7 @@
   task_unblocked |= main_thread_only().delayed_work_queue->RemoveFence();
 
   {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     if (!task_unblocked && previous_fence) {
       if (!any_thread_.immediate_incoming_queue.empty() &&
           any_thread_.immediate_incoming_queue.front().enqueue_order() >
@@ -805,7 +805,7 @@
     return false;
   }
 
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   if (any_thread_.immediate_incoming_queue.empty())
     return true;
 
@@ -882,7 +882,7 @@
   bool has_pending_immediate_work;
 
   {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     UpdateCrossThreadQueueStateLocked();
     has_pending_immediate_work = HasPendingImmediateWorkLocked();
   }
@@ -934,7 +934,7 @@
   main_thread_only().immediate_work_queue->MaybeShrinkQueue();
 
   {
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     any_thread_.immediate_incoming_queue.MaybeShrinkQueue();
   }
 
@@ -943,7 +943,7 @@
 }
 
 void TaskQueueImpl::PushImmediateIncomingTaskForTest(Task&& task) {
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   any_thread_.immediate_incoming_queue.push_back(std::move(task));
 }
 
@@ -964,7 +964,7 @@
     // the lock to avoid a cross-thread post task setting it again before
     // we actually make |immediate_work_queue| non-empty.
     if (main_thread_only().immediate_work_queue->Empty()) {
-      base::internal::AutoSchedulerLock lock(any_thread_lock_);
+      base::internal::CheckedAutoLock lock(any_thread_lock_);
       empty_queues_to_reload_handle_.SetActive(false);
 
       any_thread_.immediate_work_queue_empty = false;
@@ -1027,7 +1027,7 @@
   }
 
   // Finally tasks on |immediate_incoming_queue| count as immediate work.
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   return !any_thread_.immediate_incoming_queue.empty();
 }
 
@@ -1067,7 +1067,7 @@
 }
 
 bool TaskQueueImpl::IsUnregistered() const {
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   return any_thread_.unregistered;
 }
 
@@ -1095,7 +1095,7 @@
   {
     // Limit the scope of the lock to ensure that the deque is destroyed
     // outside of the lock to allow it to post tasks.
-    base::internal::AutoSchedulerLock lock(any_thread_lock_);
+    base::internal::CheckedAutoLock lock(any_thread_lock_);
     deque.swap(any_thread_.immediate_incoming_queue);
     any_thread_.immediate_work_queue_empty = true;
     empty_queues_to_reload_handle_.SetActive(false);
@@ -1113,7 +1113,7 @@
   if (!main_thread_only().delayed_incoming_queue.empty())
     return true;
 
-  base::internal::AutoSchedulerLock lock(any_thread_lock_);
+  base::internal::CheckedAutoLock lock(any_thread_lock_);
   if (!any_thread_.immediate_incoming_queue.empty())
     return true;
 
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index e80981ae..d366d5e 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/pending_task.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/common/intrusive_heap.h"
 #include "base/task/common/operations_controller.h"
 #include "base/task/sequence_manager/associated_thread_id.h"
@@ -23,7 +24,6 @@
 #include "base/task/sequence_manager/lazily_deallocated_deque.h"
 #include "base/task/sequence_manager/sequenced_task_source.h"
 #include "base/task/sequence_manager/task_queue.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/traced_value.h"
@@ -412,7 +412,7 @@
 
   const scoped_refptr<GuardedTaskPoster> task_poster_;
 
-  mutable base::internal::SchedulerLock any_thread_lock_;
+  mutable base::internal::CheckedLock any_thread_lock_;
 
   struct AnyThread {
     explicit AnyThread(TimeDomain* time_domain);
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
index 76057a2..1886b5c 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.cc
@@ -87,7 +87,7 @@
       base::internal::ScopedSetSequenceLocalStorageMapForCurrentThread>(
       &sequence_local_storage_map_);
   {
-    base::internal::AutoSchedulerLock task_runner_lock(task_runner_lock_);
+    base::internal::CheckedAutoLock task_runner_lock(task_runner_lock_);
     if (task_runner_)
       InitializeThreadTaskRunnerHandle();
   }
@@ -117,7 +117,7 @@
 }
 
 void ThreadControllerWithMessagePumpImpl::ScheduleWork() {
-  base::internal::SchedulerLock::AssertNoLockHeldOnCurrentThread();
+  base::internal::CheckedLock::AssertNoLockHeldOnCurrentThread();
   if (work_deduplicator_.OnWorkRequested() ==
       ShouldScheduleWork::kScheduleImmediate) {
     pump_->ScheduleWork();
@@ -158,7 +158,7 @@
 
 void ThreadControllerWithMessagePumpImpl::SetDefaultTaskRunner(
     scoped_refptr<SingleThreadTaskRunner> task_runner) {
-  base::internal::AutoSchedulerLock lock(task_runner_lock_);
+  base::internal::CheckedAutoLock lock(task_runner_lock_);
   task_runner_ = task_runner;
   if (associated_thread_->IsBound()) {
     DCHECK(associated_thread_->IsBoundToCurrentThread());
@@ -177,7 +177,7 @@
 
 scoped_refptr<SingleThreadTaskRunner>
 ThreadControllerWithMessagePumpImpl::GetDefaultTaskRunner() {
-  base::internal::AutoSchedulerLock lock(task_runner_lock_);
+  base::internal::CheckedAutoLock lock(task_runner_lock_);
   return task_runner_;
 }
 
diff --git a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
index af1ec41f..8f4e5b16 100644
--- a/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
+++ b/base/task/sequence_manager/thread_controller_with_message_pump_impl.h
@@ -10,13 +10,13 @@
 #include "base/message_loop/message_pump.h"
 #include "base/message_loop/work_id_provider.h"
 #include "base/run_loop.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/common/task_annotator.h"
 #include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/task/sequence_manager/sequenced_task_source.h"
 #include "base/task/sequence_manager/thread_controller.h"
 #include "base/task/sequence_manager/work_deduplicator.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/thread_annotations.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/sequence_local_storage_map.h"
@@ -144,7 +144,7 @@
   scoped_refptr<AssociatedThreadId> associated_thread_;
   MainThreadOnly main_thread_only_;
 
-  mutable base::internal::SchedulerLock task_runner_lock_;
+  mutable base::internal::CheckedLock task_runner_lock_;
   scoped_refptr<SingleThreadTaskRunner> task_runner_
       GUARDED_BY(task_runner_lock_);
 
diff --git a/base/task/thread_pool/delayed_task_manager.cc b/base/task/thread_pool/delayed_task_manager.cc
index a805bec..9807d57 100644
--- a/base/task/thread_pool/delayed_task_manager.cc
+++ b/base/task/thread_pool/delayed_task_manager.cc
@@ -63,7 +63,7 @@
 
   TimeTicks process_ripe_tasks_time;
   {
-    AutoSchedulerLock auto_lock(queue_lock_);
+    CheckedAutoLock auto_lock(queue_lock_);
     DCHECK(!service_thread_task_runner_);
     service_thread_task_runner_ = std::move(service_thread_task_runner);
     process_ripe_tasks_time = GetTimeToScheduleProcessRipeTasksLockRequired();
@@ -83,7 +83,7 @@
   CHECK(task.task);
   TimeTicks process_ripe_tasks_time;
   {
-    AutoSchedulerLock auto_lock(queue_lock_);
+    CheckedAutoLock auto_lock(queue_lock_);
     delayed_task_queue_.insert(DelayedTask(std::move(task),
                                            std::move(post_task_now_callback),
                                            std::move(task_runner)));
@@ -100,7 +100,7 @@
   TimeTicks process_ripe_tasks_time;
 
   {
-    AutoSchedulerLock auto_lock(queue_lock_);
+    CheckedAutoLock auto_lock(queue_lock_);
     const TimeTicks now = tick_clock_->NowTicks();
     while (!delayed_task_queue_.empty() &&
            delayed_task_queue_.Min().task.delayed_run_time <= now) {
diff --git a/base/task/thread_pool/delayed_task_manager.h b/base/task/thread_pool/delayed_task_manager.h
index f83901719..c5cb475 100644
--- a/base/task/thread_pool/delayed_task_manager.h
+++ b/base/task/thread_pool/delayed_task_manager.h
@@ -14,8 +14,8 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/atomic_flag.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/common/intrusive_heap.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/task.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/tick_clock.h"
@@ -116,7 +116,7 @@
   // it is never modified. It is therefore safe to access
   // |service_thread_task_runner_| without synchronization once it is observed
   // that it is non-null.
-  SchedulerLock queue_lock_;
+  CheckedLock queue_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(DelayedTaskManager);
 };
diff --git a/base/task/thread_pool/platform_native_worker_pool.cc b/base/task/thread_pool/platform_native_worker_pool.cc
index 552369b..fb2f40d 100644
--- a/base/task/thread_pool/platform_native_worker_pool.cc
+++ b/base/task/thread_pool/platform_native_worker_pool.cc
@@ -18,7 +18,7 @@
  public:
   ScopedWorkersExecutor(PlatformNativeWorkerPool* outer) : outer_(outer) {}
   ~ScopedWorkersExecutor() {
-    SchedulerLock::AssertNoLockHeldOnCurrentThread();
+    CheckedLock::AssertNoLockHeldOnCurrentThread();
 
     for (size_t i = 0; i < num_threadpool_work_to_submit_; ++i)
       outer_->SubmitWork();
@@ -60,7 +60,7 @@
   StartImpl();
 
   ScopedWorkersExecutor executor(this);
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   DCHECK(!started_);
   started_ = true;
   EnsureEnoughWorkersLockRequired(&executor);
@@ -87,7 +87,7 @@
       ScopedReenqueueExecutor reenqueue_executor;
       auto task_source_and_transaction =
           TaskSourceAndTransaction::FromTaskSource(std::move(task_source));
-      AutoSchedulerLock auto_lock(lock_);
+      CheckedAutoLock auto_lock(lock_);
       ReEnqueueTaskSourceLockRequired(&workers_executor, &reenqueue_executor,
                                       std::move(task_source_and_transaction));
     }
@@ -95,7 +95,7 @@
 }
 
 scoped_refptr<TaskSource> PlatformNativeWorkerPool::GetWork() {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   DCHECK_GT(num_pending_threadpool_work_, 0U);
   --num_pending_threadpool_work_;
   // There can be more pending threadpool work than TaskSources in the
@@ -158,7 +158,7 @@
 
 void PlatformNativeWorkerPool::DidUpdateCanRunPolicy() {
   ScopedWorkersExecutor executor(this);
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   EnsureEnoughWorkersLockRequired(&executor);
 }
 
diff --git a/base/task/thread_pool/priority_queue.h b/base/task/thread_pool/priority_queue.h
index 1ec5c7d..be4683f1 100644
--- a/base/task/thread_pool/priority_queue.h
+++ b/base/task/thread_pool/priority_queue.h
@@ -10,8 +10,8 @@
 #include "base/base_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/common/intrusive_heap.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/sequence_sort_key.h"
 #include "base/task/thread_pool/task_source.h"
 
diff --git a/base/task/thread_pool/scheduler_lock.h b/base/task/thread_pool/scheduler_lock.h
deleted file mode 100644
index f39b206..0000000
--- a/base/task/thread_pool/scheduler_lock.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TASK_THREAD_POOL_SCHEDULER_LOCK_H_
-#define BASE_TASK_THREAD_POOL_SCHEDULER_LOCK_H_
-
-#include <memory>
-
-#include "base/base_export.h"
-#include "base/macros.h"
-#include "base/synchronization/condition_variable.h"
-#include "base/synchronization/lock.h"
-#include "base/task/thread_pool/scheduler_lock_impl.h"
-#include "base/thread_annotations.h"
-
-namespace base {
-namespace internal {
-
-// SchedulerLock should be used anywhere a lock would be used in the scheduler.
-// When DCHECK_IS_ON(), lock checking occurs. Otherwise, SchedulerLock is
-// equivalent to base::Lock.
-//
-// The shape of SchedulerLock is as follows:
-// SchedulerLock()
-//     Default constructor, no predecessor lock.
-//     DCHECKs
-//         On Acquisition if any scheduler lock is acquired on this thread.
-//             Okay if a universal predecessor is acquired.
-//
-// SchedulerLock(const SchedulerLock* predecessor)
-//     Constructor that specifies an allowed predecessor for that lock.
-//     DCHECKs
-//         On Construction if |predecessor| forms a predecessor lock cycle.
-//         On Acquisition if the previous lock acquired on the thread is not
-//             either |predecessor| or a universal predecessor. Okay if there
-//             was no previous lock acquired.
-//
-// SchedulerLock(UniversalPredecessor universal_predecessor)
-//     Constructor for a lock that will allow the acquisition of any lock after
-//     it, without needing to explicitly be named a predecessor. Can only be
-//     acquired if no locks are currently held by this thread.
-//     DCHECKs
-//         On Acquisition if any scheduler lock is acquired on this thread.
-//
-// void Acquire()
-//     Acquires the lock.
-//
-// void Release()
-//     Releases the lock.
-//
-// void AssertAcquired().
-//     DCHECKs if the lock is not acquired.
-//
-// std::unique_ptr<ConditionVariable> CreateConditionVariable()
-//     Creates a condition variable using this as a lock.
-
-#if DCHECK_IS_ON()
-class LOCKABLE SchedulerLock : public SchedulerLockImpl {
- public:
-  SchedulerLock() = default;
-  explicit SchedulerLock(const SchedulerLock* predecessor)
-      : SchedulerLockImpl(predecessor) {}
-  explicit SchedulerLock(UniversalPredecessor universal_predecessor)
-      : SchedulerLockImpl(universal_predecessor) {}
-};
-#else   // DCHECK_IS_ON()
-class LOCKABLE SchedulerLock : public Lock {
- public:
-  SchedulerLock() = default;
-  explicit SchedulerLock(const SchedulerLock*) {}
-  explicit SchedulerLock(UniversalPredecessor) {}
-  static void AssertNoLockHeldOnCurrentThread() {}
-
-  std::unique_ptr<ConditionVariable> CreateConditionVariable() {
-    return std::unique_ptr<ConditionVariable>(new ConditionVariable(this));
-  }
-};
-#endif  // DCHECK_IS_ON()
-
-// Provides the same functionality as base::AutoLock for SchedulerLock.
-using AutoSchedulerLock = internal::BasicAutoLock<SchedulerLock>;
-
-// Provides the same functionality as base::AutoUnlock for SchedulerLock.
-using AutoSchedulerUnlock = internal::BasicAutoUnlock<SchedulerLock>;
-
-// Provides the same functionality as base::AutoLockMaybe for SchedulerLock.
-using AutoSchedulerLockMaybe = internal::BasicAutoLockMaybe<SchedulerLock>;
-
-// Informs the clang thread safety analysis that an aliased lock is acquired.
-// Because the clang thread safety analysis doesn't understand aliased locks
-// [1], this code wouldn't compile without AnnotateAcquiredLockAlias:
-//
-// class Example {
-//  public:
-//    SchedulerLock lock_;
-//    int value = 0 GUARDED_BY(lock_);
-// };
-//
-// Example example;
-// SchedulerLock* acquired = &example.lock_;
-// AutoSchedulerLock auto_lock(*acquired);
-// AnnotateAcquiredLockAlias annotate(*acquired, example.lock_);
-// example.value = 42;  // Doesn't compile without |annotate|.
-//
-// [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis
-class SCOPED_LOCKABLE AnnotateAcquiredLockAlias {
- public:
-  // |acquired_lock| is an acquired lock. |lock_alias| is an alias of
-  // |acquired_lock|.
-  AnnotateAcquiredLockAlias(const SchedulerLock& acquired_lock,
-                            const SchedulerLock& lock_alias)
-      EXCLUSIVE_LOCK_FUNCTION(lock_alias)
-      : acquired_lock_(acquired_lock) {
-    DCHECK_EQ(&acquired_lock, &lock_alias);
-    acquired_lock_.AssertAcquired();
-  }
-  ~AnnotateAcquiredLockAlias() UNLOCK_FUNCTION() {
-    acquired_lock_.AssertAcquired();
-  }
-
- private:
-  const SchedulerLock& acquired_lock_;
-
-  DISALLOW_COPY_AND_ASSIGN(AnnotateAcquiredLockAlias);
-};
-
-}  // namespace internal
-}  // namespace base
-
-#endif  // BASE_TASK_THREAD_POOL_SCHEDULER_LOCK_H_
diff --git a/base/task/thread_pool/scheduler_parallel_task_runner.cc b/base/task/thread_pool/scheduler_parallel_task_runner.cc
index 35c41541..f83395a8 100644
--- a/base/task/thread_pool/scheduler_parallel_task_runner.cc
+++ b/base/task/thread_pool/scheduler_parallel_task_runner.cc
@@ -29,7 +29,7 @@
       traits_, this, TaskSourceExecutionMode::kParallel);
 
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     sequences_.insert(sequence.get());
   }
 
@@ -44,7 +44,7 @@
 void SchedulerParallelTaskRunner::UnregisterSequence(Sequence* sequence) {
   DCHECK(sequence);
 
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   sequences_.erase(sequence);
 }
 
diff --git a/base/task/thread_pool/scheduler_parallel_task_runner.h b/base/task/thread_pool/scheduler_parallel_task_runner.h
index 40ca662..ede136e 100644
--- a/base/task/thread_pool/scheduler_parallel_task_runner.h
+++ b/base/task/thread_pool/scheduler_parallel_task_runner.h
@@ -9,8 +9,8 @@
 #include "base/callback_forward.h"
 #include "base/containers/flat_set.h"
 #include "base/location.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/task_traits.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task_runner.h"
 #include "base/thread_annotations.h"
 #include "base/time/time.h"
@@ -45,7 +45,7 @@
   const TaskTraits traits_;
   SchedulerTaskRunnerDelegate* const scheduler_task_runner_delegate_;
 
-  SchedulerLock lock_;
+  CheckedLock lock_;
 
   // List of alive Sequences instantiated by this SchedulerParallelTaskRunner.
   // Sequences are added when they are instantiated, and removed when they are
diff --git a/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc b/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc
index a72fd18..1d355d4 100644
--- a/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc
+++ b/base/task/thread_pool/scheduler_single_thread_task_runner_manager.cc
@@ -101,7 +101,7 @@
   }
 
   scoped_refptr<TaskSource> GetWork(SchedulerWorker* worker) override {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     DCHECK(worker_awake_);
     auto task_source = GetWorkLockRequired(worker);
     if (task_source == nullptr) {
@@ -143,7 +143,7 @@
   void DidUpdateCanRunPolicy() {
     bool should_wakeup = false;
     {
-      AutoSchedulerLock auto_lock(lock_);
+      CheckedAutoLock auto_lock(lock_);
       if (!worker_awake_ && CanRunNextTaskSource()) {
         should_wakeup = true;
         worker_awake_ = true;
@@ -154,7 +154,7 @@
   }
 
   void EnableFlushPriorityQueueTaskSourcesOnDestroyForTesting() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     priority_queue_.EnableFlushTaskSourcesOnDestroyForTesting();
   }
 
@@ -169,7 +169,7 @@
 
   const TrackedRef<TaskTracker>& task_tracker() { return task_tracker_; }
 
-  SchedulerLock lock_;
+  CheckedLock lock_;
   bool worker_awake_ GUARDED_BY(lock_) = false;
 
  private:
@@ -177,7 +177,7 @@
   // Returns true iff the worker must wakeup, i.e. task source is allowed to run
   // and the worker was not awake.
   bool EnqueueTaskSource(TaskSourceAndTransaction task_source_and_transaction) {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     priority_queue_.Push(std::move(task_source_and_transaction.task_source),
                          task_source_and_transaction.transaction.GetSortKey());
     if (!worker_awake_ && CanRunNextTaskSource()) {
@@ -239,7 +239,7 @@
     // * Both SchedulerWorkerDelegate::GetWork() and the Windows Message Queue
     //   have work:
     //   Process task sources from each source round-robin style.
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     DCHECK(worker_awake_);
     scoped_refptr<TaskSource> task_source;
     if (get_work_first_) {
@@ -249,7 +249,7 @@
     }
 
     if (!task_source) {
-      AutoSchedulerUnlock auto_unlock(lock_);
+      CheckedAutoUnlock auto_unlock(lock_);
       task_source = GetWorkFromWindowsMessageQueue();
       if (task_source)
         get_work_first_ = true;
@@ -282,7 +282,7 @@
     DWORD reason = MsgWaitForMultipleObjectsEx(
         1, &wake_up_event_handle, milliseconds_wait, QS_ALLINPUT, 0);
     if (reason != WAIT_OBJECT_0) {
-      AutoSchedulerLock auto_lock(lock_);
+      CheckedAutoLock auto_lock(lock_);
       worker_awake_ = true;
     }
   }
@@ -462,7 +462,7 @@
 
   decltype(workers_) workers_to_start;
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     started_ = true;
     workers_to_start = workers_;
   }
@@ -481,7 +481,7 @@
   decltype(workers_) workers_to_update;
 
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     if (!started_)
       return;
     workers_to_update = workers_;
@@ -547,7 +547,7 @@
   bool new_worker = false;
   bool started;
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     if (!worker) {
       const auto& environment_params =
           kEnvironmentParams[GetEnvironmentIndexForTraits(traits)];
@@ -575,7 +575,7 @@
 void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() {
   decltype(workers_) local_workers;
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     local_workers = std::move(workers_);
   }
 
@@ -586,7 +586,7 @@
   }
 
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     DCHECK(workers_.empty())
         << "New worker(s) unexpectedly registered during join.";
     workers_ = std::move(local_workers);
@@ -665,10 +665,10 @@
 
 void SchedulerSingleThreadTaskRunnerManager::UnregisterSchedulerWorker(
     SchedulerWorker* worker) {
-  // Cleanup uses a SchedulerLock, so call Cleanup() after releasing |lock_|.
+  // Cleanup uses a CheckedLock, so call Cleanup() after releasing |lock_|.
   scoped_refptr<SchedulerWorker> worker_to_destroy;
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
 
     // Skip when joining (the join logic takes care of the rest).
     if (workers_.empty())
@@ -688,7 +688,7 @@
   decltype(shared_com_scheduler_workers_) local_shared_com_scheduler_workers;
 #endif
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     for (size_t i = 0; i < base::size(shared_scheduler_workers_); ++i) {
       for (size_t j = 0; j < base::size(shared_scheduler_workers_[i]); ++j) {
         local_shared_scheduler_workers[i][j] = shared_scheduler_workers_[i][j];
diff --git a/base/task/thread_pool/scheduler_single_thread_task_runner_manager.h b/base/task/thread_pool/scheduler_single_thread_task_runner_manager.h
index ef6ae77..bb665f6 100644
--- a/base/task/thread_pool/scheduler_single_thread_task_runner_manager.h
+++ b/base/task/thread_pool/scheduler_single_thread_task_runner_manager.h
@@ -12,9 +12,9 @@
 #include "base/base_export.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/single_thread_task_runner_thread_mode.h"
 #include "base/task/thread_pool/environment_config.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/tracked_ref.h"
 #include "base/thread_annotations.h"
 #include "base/threading/platform_thread.h"
@@ -130,7 +130,7 @@
   // function. Set in Start() and never modified afterwards.
   SchedulerWorkerObserver* scheduler_worker_observer_ = nullptr;
 
-  SchedulerLock lock_;
+  CheckedLock lock_;
   std::vector<scoped_refptr<SchedulerWorker>> workers_ GUARDED_BY(lock_);
   int next_worker_id_ GUARDED_BY(lock_) = 0;
 
diff --git a/base/task/thread_pool/scheduler_worker.cc b/base/task/thread_pool/scheduler_worker.cc
index d105fb9c..83309f747 100644
--- a/base/task/thread_pool/scheduler_worker.cc
+++ b/base/task/thread_pool/scheduler_worker.cc
@@ -42,7 +42,7 @@
     ThreadPriority priority_hint,
     std::unique_ptr<Delegate> delegate,
     TrackedRef<TaskTracker> task_tracker,
-    const SchedulerLock* predecessor_lock,
+    const CheckedLock* predecessor_lock,
     SchedulerBackwardCompatibility backward_compatibility)
     : thread_lock_(predecessor_lock),
       delegate_(std::move(delegate)),
@@ -63,8 +63,8 @@
 
 bool SchedulerWorker::Start(
     SchedulerWorkerObserver* scheduler_worker_observer) {
-  SchedulerLock::AssertNoLockHeldOnCurrentThread();
-  AutoSchedulerLock auto_lock(thread_lock_);
+  CheckedLock::AssertNoLockHeldOnCurrentThread();
+  CheckedAutoLock auto_lock(thread_lock_);
   DCHECK(thread_handle_.is_null());
 
   if (should_exit_.IsSet() || join_called_for_testing_.IsSet())
@@ -91,7 +91,7 @@
   // Signalling an event can deschedule the current thread. Since being
   // descheduled while holding a lock is undesirable (https://crbug.com/890978),
   // assert that no lock is held by the current thread.
-  SchedulerLock::AssertNoLockHeldOnCurrentThread();
+  CheckedLock::AssertNoLockHeldOnCurrentThread();
   // Calling WakeUp() after Cleanup() or Join() is wrong because the
   // SchedulerWorker cannot run more tasks.
   DCHECK(!join_called_for_testing_.IsSet());
@@ -107,7 +107,7 @@
   PlatformThreadHandle thread_handle;
 
   {
-    AutoSchedulerLock auto_lock(thread_lock_);
+    CheckedAutoLock auto_lock(thread_lock_);
 
     if (thread_handle_.is_null())
       return;
@@ -121,12 +121,12 @@
 }
 
 bool SchedulerWorker::ThreadAliveForTesting() const {
-  AutoSchedulerLock auto_lock(thread_lock_);
+  CheckedAutoLock auto_lock(thread_lock_);
   return !thread_handle_.is_null();
 }
 
 SchedulerWorker::~SchedulerWorker() {
-  AutoSchedulerLock auto_lock(thread_lock_);
+  CheckedAutoLock auto_lock(thread_lock_);
 
   // If |thread_handle_| wasn't joined, detach it.
   if (!thread_handle_.is_null()) {
@@ -142,19 +142,19 @@
 }
 
 void SchedulerWorker::BeginUnusedPeriod() {
-  AutoSchedulerLock auto_lock(thread_lock_);
+  CheckedAutoLock auto_lock(thread_lock_);
   DCHECK(last_used_time_.is_null());
   last_used_time_ = TimeTicks::Now();
 }
 
 void SchedulerWorker::EndUnusedPeriod() {
-  AutoSchedulerLock auto_lock(thread_lock_);
+  CheckedAutoLock auto_lock(thread_lock_);
   DCHECK(!last_used_time_.is_null());
   last_used_time_ = TimeTicks();
 }
 
 TimeTicks SchedulerWorker::GetLastUsedTime() const {
-  AutoSchedulerLock auto_lock(thread_lock_);
+  CheckedAutoLock auto_lock(thread_lock_);
   return last_used_time_;
 }
 
diff --git a/base/task/thread_pool/scheduler_worker.h b/base/task/thread_pool/scheduler_worker.h
index e5f9eb9b..f85e8583 100644
--- a/base/task/thread_pool/scheduler_worker.h
+++ b/base/task/thread_pool/scheduler_worker.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/waitable_event.h"
-#include "base/task/thread_pool/scheduler_lock.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/thread_pool/scheduler_worker_params.h"
 #include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/tracked_ref.h"
@@ -111,7 +111,7 @@
   SchedulerWorker(ThreadPriority priority_hint,
                   std::unique_ptr<Delegate> delegate,
                   TrackedRef<TaskTracker> task_tracker,
-                  const SchedulerLock* predecessor_lock = nullptr,
+                  const CheckedLock* predecessor_lock = nullptr,
                   SchedulerBackwardCompatibility backward_compatibility =
                       SchedulerBackwardCompatibility::DISABLED);
 
@@ -208,7 +208,7 @@
   // thread is created and the second access occurs on the thread.
   scoped_refptr<SchedulerWorker> self_;
 
-  mutable SchedulerLock thread_lock_;
+  mutable CheckedLock thread_lock_;
 
   // Handle for the thread managed by |this|.
   PlatformThreadHandle thread_handle_ GUARDED_BY(thread_lock_);
diff --git a/base/task/thread_pool/scheduler_worker_pool.cc b/base/task/thread_pool/scheduler_worker_pool.cc
index dbb6e1b..ca44ea6d 100644
--- a/base/task/thread_pool/scheduler_worker_pool.cc
+++ b/base/task/thread_pool/scheduler_worker_pool.cc
@@ -115,7 +115,7 @@
 
 bool SchedulerWorkerPool::RemoveTaskSource(
     scoped_refptr<TaskSource> task_source) {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   return priority_queue_.RemoveTaskSource(std::move(task_source));
 }
 
@@ -143,7 +143,7 @@
 void SchedulerWorkerPool::UpdateSortKeyImpl(
     BaseScopedWorkersExecutor* executor,
     TaskSourceAndTransaction task_source_and_transaction) {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   priority_queue_.UpdateSortKey(std::move(task_source_and_transaction));
   EnsureEnoughWorkersLockRequired(executor);
 }
@@ -151,7 +151,7 @@
 void SchedulerWorkerPool::PushTaskSourceAndWakeUpWorkersImpl(
     BaseScopedWorkersExecutor* executor,
     TaskSourceAndTransaction task_source_and_transaction) {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   DCHECK(!replacement_pool_);
   priority_queue_.Push(std::move(task_source_and_transaction.task_source),
                        task_source_and_transaction.transaction.GetSortKey());
@@ -160,8 +160,8 @@
 
 void SchedulerWorkerPool::InvalidateAndHandoffAllTaskSourcesToOtherPool(
     SchedulerWorkerPool* destination_pool) {
-  AutoSchedulerLock current_pool_lock(lock_);
-  AutoSchedulerLock destination_pool_lock(destination_pool->lock_);
+  CheckedAutoLock current_pool_lock(lock_);
+  CheckedAutoLock destination_pool_lock(destination_pool->lock_);
   destination_pool->priority_queue_ = std::move(priority_queue_);
   replacement_pool_ = destination_pool;
 }
diff --git a/base/task/thread_pool/scheduler_worker_pool.h b/base/task/thread_pool/scheduler_worker_pool.h
index 75c14071..0b85a3e 100644
--- a/base/task/thread_pool/scheduler_worker_pool.h
+++ b/base/task/thread_pool/scheduler_worker_pool.h
@@ -7,8 +7,8 @@
 
 #include "base/base_export.h"
 #include "base/memory/ref_counted.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/thread_pool/priority_queue.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
 #include "base/task/thread_pool/task_source.h"
@@ -192,7 +192,7 @@
   // atomic, nor immutable after start. Since this lock is a bottleneck to post
   // and schedule work, only simple data structure manipulations are allowed
   // within its scope (no thread creation or wake up).
-  mutable SchedulerLock lock_;
+  mutable CheckedLock lock_;
 
   // PriorityQueue from which all threads of this worker pool get work.
   PriorityQueue priority_queue_ GUARDED_BY(lock_);
diff --git a/base/task/thread_pool/scheduler_worker_pool_impl.cc b/base/task/thread_pool/scheduler_worker_pool_impl.cc
index 0da65e8..0f8fd5b 100644
--- a/base/task/thread_pool/scheduler_worker_pool_impl.cc
+++ b/base/task/thread_pool/scheduler_worker_pool_impl.cc
@@ -111,7 +111,7 @@
     workers_to_start_.AddWorker(std::move(worker));
   }
 
-  void Flush(SchedulerLock* held_lock) {
+  void Flush(CheckedLock* held_lock) {
     static_assert(std::is_pod<BaseScopedWorkersExecutor>::value &&
                       sizeof(BaseScopedWorkersExecutor) == 1,
                   "Must add BaseScopedWorkersExecutor::Flush() if it becomes "
@@ -119,7 +119,7 @@
 
     if (workers_to_wake_up_.empty() && workers_to_start_.empty())
       return;
-    AutoSchedulerUnlock auto_unlock(*held_lock);
+    CheckedAutoUnlock auto_unlock(*held_lock);
     FlushImpl();
     workers_to_wake_up_.clear();
     workers_to_start_.clear();
@@ -173,7 +173,7 @@
   };
 
   void FlushImpl() {
-    SchedulerLock::AssertNoLockHeldOnCurrentThread();
+    CheckedLock::AssertNoLockHeldOnCurrentThread();
 
     // Wake up workers.
     workers_to_wake_up_.ForEachWorker(
@@ -239,9 +239,9 @@
     return read_any().is_running_best_effort_task;
   }
 
-  // Exposed for AnnotateSchedulerLockAcquired in
+  // Exposed for AnnotateCheckedLockAcquired in
   // SchedulerWorkerPoolImpl::AdjustMaxTasks()
-  const SchedulerLock& lock() const LOCK_RETURNED(outer_->lock_) {
+  const CheckedLock& lock() const LOCK_RETURNED(outer_->lock_) {
     return outer_->lock_;
   }
 
@@ -394,7 +394,7 @@
 
   ScopedWorkersExecutor executor(this);
 
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
 
   DCHECK(workers_.empty());
 
@@ -451,7 +451,7 @@
 size_t SchedulerWorkerPoolImpl::GetMaxConcurrentNonBlockedTasksDeprecated()
     const {
 #if DCHECK_IS_ON()
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   DCHECK_NE(after_start().initial_max_tasks, 0U)
       << "GetMaxConcurrentTasksDeprecated() should only be called after the "
       << "worker pool has started.";
@@ -460,7 +460,7 @@
 }
 
 void SchedulerWorkerPoolImpl::WaitForWorkersIdleForTesting(size_t n) {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
 
 #if DCHECK_IS_ON()
   DCHECK(!some_workers_cleaned_up_for_testing_)
@@ -473,12 +473,12 @@
 }
 
 void SchedulerWorkerPoolImpl::WaitForAllWorkersIdleForTesting() {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   WaitForWorkersIdleLockRequiredForTesting(workers_.size());
 }
 
 void SchedulerWorkerPoolImpl::WaitForWorkersCleanedUpForTesting(size_t n) {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
 
   if (!num_workers_cleaned_up_for_testing_cv_)
     num_workers_cleaned_up_for_testing_cv_ = lock_.CreateConditionVariable();
@@ -496,7 +496,7 @@
 
   decltype(workers_) workers_copy;
   {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     priority_queue_.EnableFlushTaskSourcesOnDestroyForTesting();
 
     DCHECK_GT(workers_.size(), size_t(0)) << "Joined an unstarted worker pool.";
@@ -513,29 +513,29 @@
   for (const auto& worker : workers_copy)
     worker->JoinForTesting();
 
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   DCHECK(workers_ == workers_copy);
   // Release |workers_| to clear their TrackedRef against |this|.
   workers_.clear();
 }
 
 size_t SchedulerWorkerPoolImpl::NumberOfWorkersForTesting() const {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   return workers_.size();
 }
 
 size_t SchedulerWorkerPoolImpl::GetMaxTasksForTesting() const {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   return max_tasks_;
 }
 
 size_t SchedulerWorkerPoolImpl::NumberOfIdleWorkersForTesting() const {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   return idle_workers_stack_.Size();
 }
 
 void SchedulerWorkerPoolImpl::ReportHeartbeatMetrics() const {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   num_workers_histogram_->Add(workers_.size());
 
   num_active_workers_histogram_->Add(workers_.size() -
@@ -565,7 +565,7 @@
 
   {
 #if DCHECK_IS_ON()
-    AutoSchedulerLock auto_lock(outer_->lock_);
+    CheckedAutoLock auto_lock(outer_->lock_);
     DCHECK(ContainsWorker(outer_->workers_, worker));
 #endif
   }
@@ -601,7 +601,7 @@
   DCHECK(!read_worker().is_running_best_effort_task);
 
   ScopedWorkersExecutor executor(outer_.get());
-  AutoSchedulerLock auto_lock(outer_->lock_);
+  CheckedAutoLock auto_lock(outer_->lock_);
 
   DCHECK(ContainsWorker(outer_->workers_, worker));
 
@@ -670,7 +670,7 @@
 
   ScopedWorkersExecutor workers_executor(outer_.get());
   ScopedReenqueueExecutor reenqueue_executor;
-  AutoSchedulerLock auto_lock(outer_->lock_);
+  CheckedAutoLock auto_lock(outer_->lock_);
 
   DCHECK(!incremented_max_tasks_since_blocked_);
 
@@ -791,7 +791,7 @@
 #if DCHECK_IS_ON()
   {
     bool shutdown_complete = outer_->task_tracker_->IsShutdownComplete();
-    AutoSchedulerLock auto_lock(outer_->lock_);
+    CheckedAutoLock auto_lock(outer_->lock_);
 
     // |worker| should already have been removed from the idle workers stack and
     // |workers_| by the time the thread is about to exit. (except in the cases
@@ -839,7 +839,7 @@
     return;
 
   {
-    AutoSchedulerLock auto_lock(outer_->lock_);
+    CheckedAutoLock auto_lock(outer_->lock_);
 
     // Don't do anything if a MAY_BLOCK ScopedBlockingCall instantiated in the
     // same scope already caused the max tasks to be incremented.
@@ -863,7 +863,7 @@
   DCHECK_CALLED_ON_VALID_THREAD(worker_thread_checker_);
   DCHECK(worker_only().is_running_task);
 
-  AutoSchedulerLock auto_lock(outer_->lock_);
+  CheckedAutoLock auto_lock(outer_->lock_);
   if (incremented_max_tasks_since_blocked_) {
     outer_->DecrementMaxTasksLockRequired(
         read_worker().is_running_best_effort_task);
@@ -883,7 +883,7 @@
   DCHECK(worker_only().is_running_task);
 
   ScopedWorkersExecutor executor(outer_.get());
-  AutoSchedulerLock auto_lock(outer_->lock_);
+  CheckedAutoLock auto_lock(outer_->lock_);
 
   DCHECK(!incremented_max_tasks_since_blocked_);
   DCHECK(read_worker().may_block_start_time.is_null());
@@ -900,7 +900,7 @@
   DCHECK(worker_only().is_running_task);
 
   ScopedWorkersExecutor executor(outer_.get());
-  AutoSchedulerLock auto_lock(outer_->lock_);
+  CheckedAutoLock auto_lock(outer_->lock_);
 
   DCHECK(!incremented_max_tasks_since_blocked_);
   DCHECK(read_worker().may_block_start_time.is_null());
@@ -1047,7 +1047,7 @@
 
 void SchedulerWorkerPoolImpl::DidUpdateCanRunPolicy() {
   ScopedWorkersExecutor executor(this);
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   EnsureEnoughWorkersLockRequired(&executor);
 }
 
@@ -1092,7 +1092,7 @@
       after_start().service_thread_task_runner->RunsTasksInCurrentSequence());
 
   ScopedWorkersExecutor executor(this);
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   DCHECK(adjust_max_tasks_posted_);
   adjust_max_tasks_posted_ = false;
 
diff --git a/base/task/thread_pool/scheduler_worker_pool_unittest.cc b/base/task/thread_pool/scheduler_worker_pool_unittest.cc
index 1f615b3..7fd55c41 100644
--- a/base/task/thread_pool/scheduler_worker_pool_unittest.cc
+++ b/base/task/thread_pool/scheduler_worker_pool_unittest.cc
@@ -382,7 +382,7 @@
 TEST_P(ThreadPoolWorkerPoolTest, UpdatePriorityBestEffortToUserBlocking) {
   StartWorkerPool();
 
-  SchedulerLock num_tasks_running_lock;
+  CheckedLock num_tasks_running_lock;
   std::unique_ptr<ConditionVariable> num_tasks_running_cv =
       num_tasks_running_lock.CreateConditionVariable();
   size_t num_tasks_running = 0;
@@ -398,13 +398,13 @@
         FROM_HERE, BindLambdaForTesting([&]() {
           // Increment the number of tasks running.
           {
-            AutoSchedulerLock auto_lock(num_tasks_running_lock);
+            CheckedAutoLock auto_lock(num_tasks_running_lock);
             ++num_tasks_running;
           }
           num_tasks_running_cv->Broadcast();
 
           // Wait until all posted tasks are running.
-          AutoSchedulerLock auto_lock(num_tasks_running_lock);
+          CheckedAutoLock auto_lock(num_tasks_running_lock);
           while (num_tasks_running < kMaxTasks) {
             ScopedClearBlockingObserverForTesting clear_blocking_observer;
             ScopedAllowBaseSyncPrimitivesForTesting allow_base_sync_primitives;
@@ -415,7 +415,7 @@
 
   // Wait until |kMaxBestEffort| tasks start running.
   {
-    AutoSchedulerLock auto_lock(num_tasks_running_lock);
+    CheckedAutoLock auto_lock(num_tasks_running_lock);
     while (num_tasks_running < kMaxBestEffortTasks)
       num_tasks_running_cv->Wait();
   }
@@ -429,7 +429,7 @@
   // tasks lower than |kMaxTasks|.
   static_assert(kMaxBestEffortTasks < kMaxTasks, "");
   {
-    AutoSchedulerLock auto_lock(num_tasks_running_lock);
+    CheckedAutoLock auto_lock(num_tasks_running_lock);
     while (num_tasks_running < kMaxTasks)
       num_tasks_running_cv->Wait();
   }
diff --git a/base/task/thread_pool/scheduler_worker_unittest.cc b/base/task/thread_pool/scheduler_worker_unittest.cc
index a43da7e..4882fbd5 100644
--- a/base/task/thread_pool/scheduler_worker_unittest.cc
+++ b/base/task/thread_pool/scheduler_worker_unittest.cc
@@ -16,8 +16,8 @@
 #include "base/memory/ref_counted.h"
 #include "base/synchronization/condition_variable.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/thread_pool/environment_config.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/scheduler_worker_observer.h"
 #include "base/task/thread_pool/sequence.h"
 #include "base/task/thread_pool/task.h"
@@ -96,34 +96,34 @@
 
   // Wait until GetWork() has been called |num_get_work| times.
   void WaitForNumGetWork(size_t num_get_work) {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     while (num_get_work_ < num_get_work)
       num_get_work_cv_->Wait();
   }
 
   void SetMaxGetWork(size_t max_get_work) {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     max_get_work_ = max_get_work;
   }
 
   void SetNumSequencesToCreate(size_t num_sequences_to_create) {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     EXPECT_EQ(0U, num_sequences_to_create_);
     num_sequences_to_create_ = num_sequences_to_create;
   }
 
   size_t NumRunTasks() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     return num_run_tasks_;
   }
 
   std::vector<scoped_refptr<TaskSource>> CreatedTaskSources() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     return created_sequences_;
   }
 
   std::vector<scoped_refptr<TaskSource>> DidRunTaskSequences() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     return did_run_task_sequences_;
   }
 
@@ -146,7 +146,7 @@
 
       // Without synchronization, OnMainEntry() could be called twice without
       // generating an error.
-      AutoSchedulerLock auto_lock(outer_->lock_);
+      CheckedAutoLock auto_lock(outer_->lock_);
       EXPECT_FALSE(outer_->main_entry_called_.IsSignaled());
       outer_->main_entry_called_.Signal();
     }
@@ -156,7 +156,7 @@
       EXPECT_EQ(outer_->worker_.get(), worker);
 
       {
-        AutoSchedulerLock auto_lock(outer_->lock_);
+        CheckedAutoLock auto_lock(outer_->lock_);
 
         // Increment the number of times that this method has been called.
         ++outer_->num_get_work_;
@@ -189,7 +189,7 @@
 
       {
         // Add the Sequence to the vector of created Sequences.
-        AutoSchedulerLock auto_lock(outer_->lock_);
+        CheckedAutoLock auto_lock(outer_->lock_);
         outer_->created_sequences_.push_back(sequence);
       }
 
@@ -202,7 +202,7 @@
     // execution.
     void DidRunTask(scoped_refptr<TaskSource> sequence) override {
       {
-        AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
+        CheckedAutoLock auto_lock(expect_did_run_task_lock_);
         EXPECT_TRUE(expect_did_run_task_);
         expect_did_run_task_ = false;
       }
@@ -223,7 +223,7 @@
         }
 
         // Add |sequence| to |did_run_task_sequences_|.
-        AutoSchedulerLock auto_lock(outer_->lock_);
+        CheckedAutoLock auto_lock(outer_->lock_);
         outer_->did_run_task_sequences_.push_back(std::move(sequence));
         EXPECT_LE(outer_->did_run_task_sequences_.size(),
                   outer_->created_sequences_.size());
@@ -234,19 +234,19 @@
     // Expect a call to DidRunTask() before the next call to any other method of
     // this delegate.
     void ExpectCallToDidRunTask() {
-      AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
+      CheckedAutoLock auto_lock(expect_did_run_task_lock_);
       expect_did_run_task_ = true;
     }
 
     bool IsCallToDidRunTaskExpected() const {
-      AutoSchedulerLock auto_lock(expect_did_run_task_lock_);
+      CheckedAutoLock auto_lock(expect_did_run_task_lock_);
       return expect_did_run_task_;
     }
 
     ThreadPoolWorkerTest* outer_;
 
     // Synchronizes access to |expect_did_run_task_|.
-    mutable SchedulerLock expect_did_run_task_lock_;
+    mutable CheckedLock expect_did_run_task_lock_;
 
     // Whether the next method called on this delegate should be DidRunTask().
     bool expect_did_run_task_ = false;
@@ -255,7 +255,7 @@
   };
 
   void RunTaskCallback() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     ++num_run_tasks_;
     EXPECT_LE(num_run_tasks_, created_sequences_.size());
   }
@@ -263,7 +263,7 @@
   TaskTracker task_tracker_ = {"Test"};
 
   // Synchronizes access to all members below.
-  mutable SchedulerLock lock_;
+  mutable CheckedLock lock_;
 
   // Signaled once OnMainEntry() has been called.
   WaitableEvent main_entry_called_;
@@ -710,7 +710,7 @@
 
  private:
   void VerifyThreadPriority() {
-    AutoSchedulerLock auto_lock(expected_thread_priority_lock_);
+    CheckedAutoLock auto_lock(expected_thread_priority_lock_);
     EXPECT_EQ(expected_thread_priority_,
               PlatformThread::GetCurrentThreadPriority());
   }
@@ -719,7 +719,7 @@
   WaitableEvent priority_verified_in_get_work_event_;
 
   // Synchronizes access to |expected_thread_priority_|.
-  SchedulerLock expected_thread_priority_lock_;
+  CheckedLock expected_thread_priority_lock_;
 
   // Expected thread priority for the next call to OnMainEntry() or GetWork().
   ThreadPriority expected_thread_priority_;
diff --git a/base/task/thread_pool/task_source.h b/base/task/thread_pool/task_source.h
index 92f1fda..b61ad8d7 100644
--- a/base/task/thread_pool/task_source.h
+++ b/base/task/thread_pool/task_source.h
@@ -12,9 +12,9 @@
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
 #include "base/sequence_token.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/common/intrusive_heap.h"
 #include "base/task/task_traits.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/sequence_sort_key.h"
 #include "base/task/thread_pool/task.h"
 #include "base/threading/sequence_local_storage_map.h"
@@ -173,7 +173,7 @@
   friend class RefCountedThreadSafe<TaskSource>;
 
   // Synchronizes access to all members.
-  mutable SchedulerLock lock_{UniversalPredecessor()};
+  mutable CheckedLock lock_{UniversalPredecessor()};
 
   // The TaskSource's position in its current PriorityQueue. Access is protected
   // by the PriorityQueue's lock.
diff --git a/base/task/thread_pool/task_tracker.cc b/base/task/thread_pool/task_tracker.cc
index 88cec79..b258169 100644
--- a/base/task/thread_pool/task_tracker.cc
+++ b/base/task/thread_pool/task_tracker.cc
@@ -300,7 +300,7 @@
 TaskTracker::~TaskTracker() = default;
 
 void TaskTracker::StartShutdown() {
-  AutoSchedulerLock auto_lock(shutdown_lock_);
+  CheckedAutoLock auto_lock(shutdown_lock_);
 
   // This method can only be called once.
   DCHECK(!shutdown_event_);
@@ -337,14 +337,14 @@
   // Unblock FlushForTesting() and perform the FlushAsyncForTesting callback
   // when shutdown completes.
   {
-    AutoSchedulerLock auto_lock(flush_lock_);
+    CheckedAutoLock auto_lock(flush_lock_);
     flush_cv_->Signal();
   }
   CallFlushCallbackForTesting();
 }
 
 void TaskTracker::FlushForTesting() {
-  AutoSchedulerLock auto_lock(flush_lock_);
+  CheckedAutoLock auto_lock(flush_lock_);
   while (subtle::Acquire_Load(&num_incomplete_undelayed_tasks_) != 0 &&
          !IsShutdownComplete()) {
     flush_cv_->Wait();
@@ -354,7 +354,7 @@
 void TaskTracker::FlushAsyncForTesting(OnceClosure flush_callback) {
   DCHECK(flush_callback);
   {
-    AutoSchedulerLock auto_lock(flush_lock_);
+    CheckedAutoLock auto_lock(flush_lock_);
     DCHECK(!flush_callback_for_testing_)
         << "Only one FlushAsyncForTesting() may be pending at any time.";
     flush_callback_for_testing_ = std::move(flush_callback);
@@ -449,7 +449,7 @@
 }
 
 bool TaskTracker::IsShutdownComplete() const {
-  AutoSchedulerLock auto_lock(shutdown_lock_);
+  CheckedAutoLock auto_lock(shutdown_lock_);
   return shutdown_event_ && shutdown_event_->IsSignaled();
 }
 
@@ -587,7 +587,7 @@
     const bool shutdown_started = state_->IncrementNumTasksBlockingShutdown();
 
     if (shutdown_started) {
-      AutoSchedulerLock auto_lock(shutdown_lock_);
+      CheckedAutoLock auto_lock(shutdown_lock_);
 
       // A BLOCK_SHUTDOWN task posted after shutdown has completed is an
       // ordering bug. This aims to catch those early.
@@ -668,7 +668,7 @@
 }
 
 void TaskTracker::OnBlockingShutdownTasksComplete() {
-  AutoSchedulerLock auto_lock(shutdown_lock_);
+  CheckedAutoLock auto_lock(shutdown_lock_);
 
   // This method can only be called after shutdown has started.
   DCHECK(state_->HasShutdownStarted());
@@ -683,7 +683,7 @@
   DCHECK_GE(new_num_incomplete_undelayed_tasks, 0);
   if (new_num_incomplete_undelayed_tasks == 0) {
     {
-      AutoSchedulerLock auto_lock(flush_lock_);
+      CheckedAutoLock auto_lock(flush_lock_);
       flush_cv_->Signal();
     }
     CallFlushCallbackForTesting();
@@ -693,7 +693,7 @@
 void TaskTracker::CallFlushCallbackForTesting() {
   OnceClosure flush_callback;
   {
-    AutoSchedulerLock auto_lock(flush_lock_);
+    CheckedAutoLock auto_lock(flush_lock_);
     flush_callback = std::move(flush_callback_for_testing_);
   }
   if (flush_callback)
diff --git a/base/task/thread_pool/task_tracker.h b/base/task/thread_pool/task_tracker.h
index 91701e8..357ff20 100644
--- a/base/task/thread_pool/task_tracker.h
+++ b/base/task/thread_pool/task_tracker.h
@@ -20,9 +20,9 @@
 #include "base/sequence_checker.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/common/task_annotator.h"
 #include "base/task/task_traits.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/task.h"
 #include "base/task/thread_pool/task_source.h"
 #include "base/task/thread_pool/tracked_ref.h"
@@ -232,7 +232,7 @@
   // because it's atomic, but synchronization is needed to coordinate waking and
   // sleeping at the right time. Fully synchronizes access to
   // |flush_callback_for_testing_|.
-  mutable SchedulerLock flush_lock_;
+  mutable CheckedLock flush_lock_;
 
   // Signaled when |num_incomplete_undelayed_tasks_| is or reaches zero or when
   // shutdown completes.
@@ -243,7 +243,7 @@
   OnceClosure flush_callback_for_testing_;
 
   // Synchronizes access to shutdown related members below.
-  mutable SchedulerLock shutdown_lock_;
+  mutable CheckedLock shutdown_lock_;
 
   // Event instantiated when shutdown starts and signaled when shutdown
   // completes.
diff --git a/base/task/thread_pool/task_tracker_unittest.cc b/base/task/thread_pool/task_tracker_unittest.cc
index bf63f84..cbd5adc 100644
--- a/base/task/thread_pool/task_tracker_unittest.cc
+++ b/base/task/thread_pool/task_tracker_unittest.cc
@@ -25,8 +25,8 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/atomic_flag.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/common/checked_lock.h"
 #include "base/task/task_traits.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/task.h"
 #include "base/task/thread_pool/test_utils.h"
 #include "base/test/gtest_util.h"
@@ -216,7 +216,7 @@
   }
 
   size_t NumTasksExecuted() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     return num_tasks_executed_;
   }
 
@@ -224,7 +224,7 @@
 
  private:
   void RunTaskCallback() {
-    AutoSchedulerLock auto_lock(lock_);
+    CheckedAutoLock auto_lock(lock_);
     ++num_tasks_executed_;
   }
 
@@ -232,7 +232,7 @@
   std::unique_ptr<CallbackThread> thread_calling_flush_;
 
   // Synchronizes accesses to |num_tasks_executed_|.
-  SchedulerLock lock_;
+  CheckedLock lock_;
 
   size_t num_tasks_executed_ = 0;
 
diff --git a/base/task/thread_pool/test_utils.cc b/base/task/thread_pool/test_utils.cc
index 649ee80..db69497 100644
--- a/base/task/thread_pool/test_utils.cc
+++ b/base/task/thread_pool/test_utils.cc
@@ -26,19 +26,19 @@
 }
 
 void MockSchedulerWorkerObserver::AllowCallsOnMainExit(int num_calls) {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   EXPECT_EQ(0, allowed_calls_on_main_exit_);
   allowed_calls_on_main_exit_ = num_calls;
 }
 
 void MockSchedulerWorkerObserver::WaitCallsOnMainExit() {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   while (allowed_calls_on_main_exit_ != 0)
     on_main_exit_cv_->Wait();
 }
 
 void MockSchedulerWorkerObserver::OnSchedulerWorkerMainExit() {
-  AutoSchedulerLock auto_lock(lock_);
+  CheckedAutoLock auto_lock(lock_);
   EXPECT_GE(allowed_calls_on_main_exit_, 0);
   --allowed_calls_on_main_exit_;
   if (allowed_calls_on_main_exit_ == 0)
diff --git a/base/task/thread_pool/test_utils.h b/base/task/thread_pool/test_utils.h
index eb48c3eb..ee5835b 100644
--- a/base/task/thread_pool/test_utils.h
+++ b/base/task/thread_pool/test_utils.h
@@ -5,9 +5,9 @@
 #ifndef BASE_TASK_THREAD_POOL_TEST_UTILS_H_
 #define BASE_TASK_THREAD_POOL_TEST_UTILS_H_
 
+#include "base/task/common/checked_lock.h"
 #include "base/task/task_traits.h"
 #include "base/task/thread_pool/delayed_task_manager.h"
-#include "base/task/thread_pool/scheduler_lock.h"
 #include "base/task/thread_pool/scheduler_task_runner_delegate.h"
 #include "base/task/thread_pool/scheduler_worker_observer.h"
 #include "base/task/thread_pool/scheduler_worker_pool.h"
@@ -40,7 +40,7 @@
   void OnSchedulerWorkerMainExit() override;
 
  private:
-  SchedulerLock lock_;
+  CheckedLock lock_;
   std::unique_ptr<ConditionVariable> on_main_exit_cv_ GUARDED_BY(lock_);
   int allowed_calls_on_main_exit_ GUARDED_BY(lock_) = 0;
 
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
index 4c99ad9..8bfe84d9 100644
--- a/base/win/win_util.cc
+++ b/base/win/win_util.cc
@@ -22,6 +22,7 @@
 #include <signal.h>
 #include <stddef.h>
 #include <stdlib.h>
+#include <strsafe.h>
 #include <tchar.h>  // Must be before tpcshrd.h or for any use of _T macro
 #include <tpcshrd.h>
 #include <uiviewsettingsinterop.h>
@@ -71,13 +72,12 @@
   if (SUCCEEDED(result))
     return true;
 #if DCHECK_IS_ON()
-  ScopedCoMem<OLECHAR> guidString;
-  ::StringFromCLSID(property_key.fmtid, &guidString);
   if (HRESULT_FACILITY(result) == FACILITY_WIN32)
     ::SetLastError(HRESULT_CODE(result));
   // See third_party/perl/c/i686-w64-mingw32/include/propkey.h for GUID and
   // PID definitions.
-  DPLOG(ERROR) << "Failed to set property with GUID " << guidString << " PID "
+  DPLOG(ERROR) << "Failed to set property with GUID "
+               << String16FromGUID(property_key.fmtid) << " PID "
                << property_key.pid;
 #endif
   return false;
@@ -721,6 +721,21 @@
   }
 }
 
+string16 String16FromGUID(REFGUID rguid) {
+  // This constant counts the number of characters in the formatted string,
+  // including the null termination character.
+  constexpr int kGuidStringCharacters =
+      1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1 + 1;
+  wchar_t guid_string[kGuidStringCharacters];
+  CHECK(SUCCEEDED(StringCchPrintfW(
+      guid_string, kGuidStringCharacters,
+      L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", rguid.Data1,
+      rguid.Data2, rguid.Data3, rguid.Data4[0], rguid.Data4[1], rguid.Data4[2],
+      rguid.Data4[3], rguid.Data4[4], rguid.Data4[5], rguid.Data4[6],
+      rguid.Data4[7])));
+  return string16(as_u16cstr(guid_string), kGuidStringCharacters - 1);
+}
+
 ScopedDomainStateForTesting::ScopedDomainStateForTesting(bool state)
     : initial_state_(IsEnrolledToDomain()) {
   *GetDomainEnrollmentStateStorage() = state;
diff --git a/base/win/win_util.h b/base/win/win_util.h
index 1806689..fcbca51 100644
--- a/base/win/win_util.h
+++ b/base/win/win_util.h
@@ -184,6 +184,9 @@
 // Enable high-DPI support for the current process.
 BASE_EXPORT void EnableHighDPISupport();
 
+// Returns a string representation of |rguid|.
+BASE_EXPORT string16 String16FromGUID(REFGUID rguid);
+
 // Allows changing the domain enrolled state for the life time of the object.
 // The original state is restored upon destruction.
 class BASE_EXPORT ScopedDomainStateForTesting {
diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc
index 7d63027..a9d98fd 100644
--- a/base/win/win_util_unittest.cc
+++ b/base/win/win_util_unittest.cc
@@ -4,12 +4,15 @@
 
 #include "base/win/win_util.h"
 
+#include <objbase.h>
+
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/scoped_native_library.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
+#include "base/win/scoped_co_mem.h"
 #include "base/win/win_client_metrics.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -80,5 +83,22 @@
   EXPECT_EQ(INVALID_HANDLE_VALUE, base::win::Uint32ToHandle(invalid_handle));
 }
 
+TEST(BaseWinUtilTest, String16FromGUID) {
+  const GUID kGuid = {0x7698f759,
+                      0xf5b0,
+                      0x4328,
+                      {0x92, 0x38, 0xbd, 0x70, 0x8a, 0x6d, 0xc9, 0x63}};
+  const base::StringPiece16 kGuidStr(
+      STRING16_LITERAL("{7698F759-F5B0-4328-9238-BD708A6DC963}"));
+  auto guid_string16 = String16FromGUID(kGuid);
+  EXPECT_EQ(guid_string16, kGuidStr);
+  wchar_t guid_wchar[39];
+  ::StringFromGUID2(kGuid, guid_wchar, base::size(guid_wchar));
+  EXPECT_STREQ(as_wcstr(guid_string16), guid_wchar);
+  ScopedCoMem<OLECHAR> clsid_string;
+  ::StringFromCLSID(kGuid, &clsid_string);
+  EXPECT_STREQ(as_wcstr(guid_string16), clsid_string.get());
+}
+
 }  // namespace win
 }  // namespace base
diff --git a/base/win/windows_types.h b/base/win/windows_types.h
index 13067d5..a57277a7 100644
--- a/base/win/windows_types.h
+++ b/base/win/windows_types.h
@@ -68,6 +68,11 @@
 typedef DWORD ACCESS_MASK;
 typedef ACCESS_MASK REGSAM;
 
+// As defined in guiddef.h.
+#ifndef _REFGUID_DEFINED
+#define _REFGUID_DEFINED
+#define REFGUID const GUID&
+#endif
 
 // Forward declare Windows compatible handles.
 
diff --git a/build/android/pylib/gtest/filter/unit_tests_disabled b/build/android/pylib/gtest/filter/unit_tests_disabled
index 6a7340d..706e1ab 100644
--- a/build/android/pylib/gtest/filter/unit_tests_disabled
+++ b/build/android/pylib/gtest/filter/unit_tests_disabled
@@ -70,9 +70,6 @@
 # crbug.com/147500
 ManifestTest.RestrictedKeys
 
-# crbug.com/152599
-SyncSearchEngineDataTypeControllerTest.*
-
 # crbug.com/256259
 DiagnosticsModelTest.RunAll
 
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index ce5f2a79..f07e025 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -223,9 +223,8 @@
     self._suite_name = args.suite_name
     self._tests = args.tests
     self._conditional = args.conditional
-    self._use_host_tast = args.use_host_tast_bin
 
-    if self._use_host_tast and not self._logs_dir:
+    if not self._llvm_profile_var and not self._logs_dir:
       # The host-side Tast bin returns 0 when tests fail, so we need to capture
       # and parse its json results to reliably determine if tests fail.
       raise TestFormatError(
@@ -269,16 +268,14 @@
     # Coverage tests require some special pre-test setup, so use an
     # on_device_script in that case. For all other tests, use cros_run_test's
     # built-in '--tast' option. This gives us much better results reporting.
-    # TODO(bpastene): s/True/self._llvm_profile_var/ once we parse Tast results.
-    if not self._use_host_tast:
+    if self._llvm_profile_var:
       # Build the shell script that will be used on the device to invoke the
       # test.
       device_test_script_contents = self.BASIC_SHELL_SCRIPT[:]
-      if self._llvm_profile_var:
-        device_test_script_contents += [
-            'echo "LLVM_PROFILE_FILE=%s" >> /etc/chrome_dev.conf' % (
-                self._llvm_profile_var)
-        ]
+      device_test_script_contents += [
+          'echo "LLVM_PROFILE_FILE=%s" >> /etc/chrome_dev.conf' % (
+              self._llvm_profile_var)
+      ]
 
       local_test_runner_cmd = ['local_test_runner', '-waituntilready']
       if self._use_vm:
@@ -324,7 +321,7 @@
   def post_run(self, return_code):
     # If we don't need to parse the host-side Tast tool's results, fall back to
     # the parent method's default behavior.
-    if not self._use_host_tast:
+    if self._llvm_profile_var:
       return super(TastTest, self).post_run(return_code)
 
     tast_results_path = os.path.join(self._logs_dir, 'streamed_results.jsonl')
@@ -794,10 +791,6 @@
   tast_test_parser.add_argument(
       '--test', '-t', action='append', dest='tests',
       help='A Tast test to run in the device (eg: "ui.ChromeLogin").')
-  tast_test_parser.add_argument(
-      '--use-host-tast-bin', action='store_true',
-      help='Use the host-side Tast bin to run the tests instead of the '
-           'DUT-side local_test_runner. TODO(bpastene): Make this default.')
 
   add_common_args(gtest_parser, tast_test_parser, host_cmd_parser)
   args, unknown_args = parser.parse_known_args()
diff --git a/build/config/c++/c++.gni b/build/config/c++/c++.gni
index 4deaf03..40177f9 100644
--- a/build/config/c++/c++.gni
+++ b/build/config/c++/c++.gni
@@ -11,7 +11,7 @@
   # Don't check in changes that set this to false for more platforms; doing so
   # is not supported.
   use_custom_libcxx =
-      is_fuchsia || is_android || is_mac || is_ios ||
+      is_fuchsia || is_android || is_mac || (is_ios && !use_xcode_clang) ||
       (is_linux &&
        (!is_chromeos || default_toolchain != "//build/toolchain/cros:target"))
 
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 0300950..2ec7a7dd 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-8914758114324976032
\ No newline at end of file
+8914736426186138320
\ No newline at end of file
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index d634c9f4..5447882 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -257,6 +257,10 @@
   if (!display_item_list)
     return;
 
+  // We could run into this situation as CaptureContent could start at any time.
+  if (transform_tree_index() == TransformTree::kInvalidNodeId)
+    return;
+
   gfx::Transform inverse_screen_space_transform;
   if (!ScreenSpaceTransform().GetInverse(&inverse_screen_space_transform))
     return;
diff --git a/cc/trees/transform_node.cc b/cc/trees/transform_node.cc
index bf8f426..d91bf1d6 100644
--- a/cc/trees/transform_node.cc
+++ b/cc/trees/transform_node.cc
@@ -30,8 +30,6 @@
       node_and_ancestors_have_only_integer_translation(true),
       scrolls(false),
       should_be_snapped(false),
-      moved_by_inner_viewport_bounds_delta_x(false),
-      moved_by_inner_viewport_bounds_delta_y(false),
       moved_by_outer_viewport_bounds_delta_x(false),
       moved_by_outer_viewport_bounds_delta_y(false),
       in_subtree_of_page_scale_layer(false),
@@ -64,10 +62,6 @@
              other.node_and_ancestors_have_only_integer_translation &&
          scrolls == other.scrolls &&
          should_be_snapped == other.should_be_snapped &&
-         moved_by_inner_viewport_bounds_delta_x ==
-             other.moved_by_inner_viewport_bounds_delta_x &&
-         moved_by_inner_viewport_bounds_delta_y ==
-             other.moved_by_inner_viewport_bounds_delta_y &&
          moved_by_outer_viewport_bounds_delta_x ==
              other.moved_by_outer_viewport_bounds_delta_x &&
          moved_by_outer_viewport_bounds_delta_y ==
diff --git a/cc/trees/transform_node.h b/cc/trees/transform_node.h
index 49e5f96..e15aa20 100644
--- a/cc/trees/transform_node.h
+++ b/cc/trees/transform_node.h
@@ -105,10 +105,8 @@
 
   bool should_be_snapped : 1;
 
-  // These are used to position nodes wrt the right or bottom of the inner or
-  // outer viewport.
-  bool moved_by_inner_viewport_bounds_delta_x : 1;
-  bool moved_by_inner_viewport_bounds_delta_y : 1;
+  // These are used by the cc property tree builder to position nodes w.r.t. the
+  // right and/or bottom of the outer viewport.
   bool moved_by_outer_viewport_bounds_delta_x : 1;
   bool moved_by_outer_viewport_bounds_delta_y : 1;
 
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 80c2791..d316c192 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -472,6 +472,7 @@
   "javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java",
   "javatests/src/org/chromium/chrome/browser/translate/TranslateOptionsTest.java",
   "javatests/src/org/chromium/chrome/browser/ui/system/NavigationBarColorControllerTest.java",
+  "javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java",
   "javatests/src/org/chromium/chrome/browser/util/ChromeFileProviderTest.java",
   "javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java",
   "javatests/src/org/chromium/chrome/browser/util/HashUtilTest.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java
index 45ba386..1145337 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java
@@ -7,7 +7,6 @@
 import android.Manifest;
 import android.content.pm.PackageManager;
 import android.location.Location;
-import android.location.LocationManager;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Process;
@@ -437,12 +436,9 @@
 
     /** Returns the location source. */
     @LocationSource
-    // We should replace our usage of LOCATION_PROVIDERS_ALLOWED when the min API is 19.
-    @SuppressWarnings("deprecation")
     private static int getLocationSource() {
         if (sUseLocationSourceForTesting) return sLocationSourceForTesting;
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
             int locationMode;
             try {
                 locationMode = Settings.Secure.getInt(
@@ -461,21 +457,6 @@
             } else {
                 return LocationSource.MASTER_OFF;
             }
-        } else {
-            String locationProviders = Settings.Secure.getString(
-                    ContextUtils.getApplicationContext().getContentResolver(),
-                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
-            if (locationProviders.contains(LocationManager.GPS_PROVIDER)
-                    && locationProviders.contains(LocationManager.NETWORK_PROVIDER)) {
-                return LocationSource.HIGH_ACCURACY;
-            } else if (locationProviders.contains(LocationManager.GPS_PROVIDER)) {
-                return LocationSource.GPS_ONLY;
-            } else if (locationProviders.contains(LocationManager.NETWORK_PROVIDER)) {
-                return LocationSource.BATTERY_SAVING;
-            } else {
-                return LocationSource.MASTER_OFF;
-            }
-        }
     }
 
     private static boolean isNetworkLocationEnabled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java
index 9290f9f8..827406f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManager.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.omnibox.geo;
 
 import android.Manifest;
-import android.annotation.TargetApi;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -13,8 +12,6 @@
 import android.net.wifi.ScanResult;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.os.Build;
-import android.os.Build.VERSION_CODES;
 import android.os.Process;
 import android.os.SystemClock;
 import android.support.annotation.Nullable;
@@ -129,34 +126,16 @@
             ScanResult scanResult = scanResults.get(i);
             String bssid = scanResult.BSSID;
             if (bssid == null) continue;
-            Long scanResultTimestamp = scanResultTimestamp(scanResult);
-            Long wifiTimestamp = null;
-            if (scanResultTimestamp != null) {
-                long ageMs = elapsedTime - TimeUnit.MICROSECONDS.toMillis(scanResultTimestamp);
-                wifiTimestamp = currentTime - ageMs;
-            }
+            long ageMs = elapsedTime - TimeUnit.MICROSECONDS.toMillis(scanResult.timestamp);
+            long wifiTimestamp = currentTime - ageMs;
             visibleWifis.add(
                     VisibleWifi.create(scanResult.SSID, bssid, scanResult.level, wifiTimestamp));
         }
         return visibleWifis;
     }
 
-    @TargetApi(VERSION_CODES.JELLY_BEAN_MR1)
-    @Nullable
-    private static Long scanResultTimestamp(ScanResult scanResult) {
-        if (Build.VERSION.SDK_INT < VERSION_CODES.JELLY_BEAN_MR1) {
-            return null;
-        }
-        return scanResult.timestamp;
-    }
-
     static void getAllVisibleCells(Context context, TelephonyManager telephonyManager,
             Callback<Set<VisibleCell>> callback) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            // CellInfo is only available JB MR1 upwards.
-            callback.onResult(Collections.emptySet());
-            return;
-        }
         if (!hasLocationPermission(context)) {
             callback.onResult(Collections.emptySet());
             return;
@@ -178,8 +157,7 @@
         long currentTime = sTimeProvider.getCurrentTime();
         for (int i = 0; i < cellInfos.size(); i++) {
             CellInfo cellInfo = cellInfos.get(i);
-            VisibleCell visibleCell =
-                    getVisibleCellPostJellyBeanMr1(cellInfo, elapsedTime, currentTime);
+            VisibleCell visibleCell = getVisibleCell(cellInfo, elapsedTime, currentTime);
             if (visibleCell.radioType() != VisibleCell.RadioType.UNKNOWN) {
                 visibleCells.add(visibleCell);
             }
@@ -207,24 +185,15 @@
     }
 
     static VisibleCell getConnectedCell(Context context, TelephonyManager telephonyManager) {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
-            // CellInfo is only available JB MR1 upwards.
-            return VisibleCell.UNKNOWN_VISIBLE_CELL;
-        }
-        return getConnectedCellPostJellyBeanMr1(context, telephonyManager);
-    }
-
-    private static VisibleCell getConnectedCellPostJellyBeanMr1(
-            Context context, TelephonyManager telephonyManager) {
         if (!hasLocationPermission(context)) {
             return VisibleCell.UNKNOWN_MISSING_LOCATION_PERMISSION_VISIBLE_CELL;
         }
         CellInfo cellInfo = getActiveCellInfo(telephonyManager);
-        return getVisibleCellPostJellyBeanMr1(
+        return getVisibleCell(
                 cellInfo, sTimeProvider.getElapsedRealtime(), sTimeProvider.getCurrentTime());
     }
 
-    private static VisibleCell getVisibleCellPostJellyBeanMr1(
+    private static VisibleCell getVisibleCell(
             @Nullable CellInfo cellInfo, long elapsedTime, long currentTime) {
         if (cellInfo == null) {
             return VisibleCell.UNKNOWN_VISIBLE_CELL;
@@ -261,9 +230,7 @@
                     .setTimestamp(cellTimestamp)
                     .build();
         }
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2
-                && cellInfo instanceof CellInfoWcdma) {
-            // CellInfoWcdma is only usable JB MR2 upwards.
+        if (cellInfo instanceof CellInfoWcdma) {
             CellIdentityWcdma cellIdentityWcdma = ((CellInfoWcdma) cellInfo).getCellIdentity();
             return VisibleCell.builder(VisibleCell.RadioType.WCDMA)
                     .setCellId(cellIdentityWcdma.getCid())
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottle.java b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottle.java
index 0b4ea2f..d66d856f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottle.java
@@ -4,11 +4,11 @@
 
 package org.chromium.chrome.browser.partnerbookmarks;
 
-import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.text.format.DateUtils;
 
+import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 
@@ -29,13 +29,13 @@
     private Map<String, Long> mCurrentEntries;
     private Map<String, Long> mNewEntries;
 
-    public PartnerBookmarksFaviconThrottle(Context context) {
-        this(context, PREFERENCES_NAME);
+    public PartnerBookmarksFaviconThrottle() {
+        this(PREFERENCES_NAME);
     }
 
     @VisibleForTesting
-    PartnerBookmarksFaviconThrottle(Context context, String name) {
-        mSharedPreferences = context.getSharedPreferences(name, 0);
+    PartnerBookmarksFaviconThrottle(String name) {
+        mSharedPreferences = ContextUtils.getApplicationContext().getSharedPreferences(name, 0);
         init();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java
index 6fc7f5a6..91e8f03 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksReader.java
@@ -226,7 +226,7 @@
             if (mFaviconThrottle == null) {
                 // Initialize the throttle here since we need to load shared preferences on the
                 // background thread as well.
-                mFaviconThrottle = new PartnerBookmarksFaviconThrottle(mContext);
+                mFaviconThrottle = new PartnerBookmarksFaviconThrottle();
             }
             PartnerBookmark.BookmarkIterator bookmarkIterator =
                     AppHooks.get().getPartnerBookmarkIterator();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
index d6ebcb6..24f6322 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -349,6 +349,12 @@
      */
     public static final String IMMERSIVE_UI_MODE_ENABLED = "immersive_ui_mode_enabled";
 
+    /**
+     * The total number of browsing sessions in touchless mode.
+     */
+    public static final String TOUCHLESS_BROWSING_SESSION_COUNT =
+            "touchless_browsing_session_count";
+
     private static class LazyHolder {
         static final ChromePreferenceManager INSTANCE = new ChromePreferenceManager();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
index 7513e1f..7cee9c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/PageViewObserver.java
@@ -13,9 +13,11 @@
 
 import org.chromium.base.Log;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.SadTab;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
 import org.chromium.chrome.browser.tab.TabObserver;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabSelectionType;
@@ -66,21 +68,36 @@
             @Override
             public void onUpdateUrl(Tab tab, String url) {
                 assert tab == mCurrentTab;
+                String newFqdn = getValidFqdnOrEmptyString(url);
+                // We don't call updateUrl() here to avoid reporting start events for domains
+                // that never paint, e.g. link shorteners. We still need to check the SuspendedTab
+                // state because a tab that's suspended can't paint, and the user could be
+                // navigating away from a suspended domain.
+                checkSuspendedTabState(mSuspensionTracker.isWebsiteSuspended(newFqdn), newFqdn);
+            }
 
-                updateUrl(url);
+            @Override
+            public void didFirstVisuallyNonEmptyPaint(Tab tab) {
+                assert tab == mCurrentTab;
+
+                updateUrl(tab.getUrl());
+            }
+
+            @Override
+            public void onCrash(Tab tab) {
+                updateUrl(null);
             }
         };
 
         mTabModelObserver = new TabModelSelectorTabModelObserver(tabModelSelector) {
             @Override
             public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
-                assert tab != null;
-                if (tab == mCurrentTab) return;
+                activeTabChanged(tab);
+            }
 
-                switchObserverToTab(tab);
-                if (mCurrentTab != null) {
-                    updateUrl(mCurrentTab.getUrl());
-                }
+            @Override
+            public void didAddTab(Tab tab, @TabLaunchType int type) {
+                activeTabChanged(tab);
             }
 
             @Override
@@ -107,50 +124,86 @@
 
     /** Notify PageViewObserver that {@code fqdn} was just suspended or un-suspended. */
     public void notifySiteSuspensionChanged(String fqdn, boolean isSuspended) {
-        if (fqdn.equals(mLastFqdn)) {
-            SuspendedTab suspendedTab = SuspendedTab.from(mCurrentTab);
-            if (isSuspended) {
-                suspendedTab.show(fqdn);
-                return;
-            } else if (!isSuspended && suspendedTab.isShowing()
-                    && fqdn.equals(suspendedTab.getFqdn())) {
-                suspendedTab.removeIfPresent();
-                mCurrentTab.reload();
+        SuspendedTab suspendedTab = SuspendedTab.from(mCurrentTab);
+        if (fqdn.equals(mLastFqdn) || fqdn.equals(suspendedTab.getFqdn())) {
+            if (checkSuspendedTabState(isSuspended, fqdn)) {
+                reportStop();
             }
         }
     }
 
+    /**
+     * Updates our state from the previous url to {@code newUrl}. This can result in any/all of the
+     * following:
+     * 1. Suspension or un-suspension of mCurrentTab.
+     * 2. Reporting a stop event for mLastFqdn.
+     * 3. Reporting a start event for the fqdn of {@code newUrl}.
+     */
     private void updateUrl(String newUrl) {
-        String newFqdn = newUrl == null ? "" : Uri.parse(newUrl).getHost();
-        boolean didSuspend = false;
-        boolean sameDomain = mLastFqdn != null && mLastFqdn.equals(newFqdn);
+        String newFqdn = getValidFqdnOrEmptyString(newUrl);
+        boolean isSameDomain = newFqdn.equals(mLastFqdn);
+        boolean isValidProtocol = URLUtil.isHttpUrl(newUrl) || URLUtil.isHttpsUrl(newUrl);
 
+        boolean didSuspend =
+                checkSuspendedTabState(mSuspensionTracker.isWebsiteSuspended(newFqdn), newFqdn);
+
+        if (mLastFqdn != null && (didSuspend || !isSameDomain)) {
+            reportStop();
+        }
+
+        if (isValidProtocol && !didSuspend && !isSameDomain) {
+            mLastFqdn = newFqdn;
+            mEventTracker.addWebsiteEvent(new WebsiteEvent(
+                    System.currentTimeMillis(), mLastFqdn, WebsiteEvent.EventType.START));
+            reportToPlatformIfDomainIsTracked("reportUsageStart", mLastFqdn);
+        }
+    }
+
+    /**
+     * Hides or shows the SuspendedTab for mCurrentTab, based on:
+     * 1. If it is currently shown or hidden
+     * 2. Its current fqdn, if any.
+     * 3. If fqdn is newly suspended or not.
+     * There are really only two important cases; either the SuspendedTab is showing and should be
+     * hidden, or it's hidden and should be shown.
+     */
+    private boolean checkSuspendedTabState(boolean isNewlySuspended, String fqdn) {
         SuspendedTab suspendedTab = SuspendedTab.from(mCurrentTab);
-        if (mSuspensionTracker.isWebsiteSuspended(newFqdn)) {
-            suspendedTab.show(newFqdn);
-            didSuspend = true;
-        } else if (suspendedTab.isShowing()) {
+        // We don't need to do anything in situations where the current state matches the desired;
+        // i.e. either the suspended tab is already showing with the correct fqdn, or the suspended
+        // tab is hidden and should be hidden.
+        if (isNewlySuspended && fqdn.equals(suspendedTab.getFqdn())) return false;
+        if (!isNewlySuspended && !suspendedTab.isShowing()) return false;
+
+        if (isNewlySuspended) {
+            suspendedTab.show(fqdn);
+            return true;
+        } else {
             suspendedTab.removeIfPresent();
-            if (!mCurrentTab.isLoading()) {
+            if (!mCurrentTab.isLoading() && !SadTab.isShowing(mCurrentTab)) {
                 mCurrentTab.reload();
             }
         }
+        return false;
+    }
 
-        if (sameDomain) return;
-
-        if (mLastFqdn != null) {
-            mEventTracker.addWebsiteEvent(new WebsiteEvent(
-                    System.currentTimeMillis(), mLastFqdn, WebsiteEvent.EventType.STOP));
-            reportToPlatformIfDomainIsTracked("reportUsageStop", mLastFqdn);
-        }
-
-        mLastFqdn = newFqdn;
-
-        if (!URLUtil.isHttpUrl(newUrl) && !URLUtil.isHttpsUrl(newUrl) || didSuspend) return;
-
+    private void reportStop() {
         mEventTracker.addWebsiteEvent(new WebsiteEvent(
-                System.currentTimeMillis(), mLastFqdn, WebsiteEvent.EventType.START));
-        reportToPlatformIfDomainIsTracked("reportUsageStart", mLastFqdn);
+                System.currentTimeMillis(), mLastFqdn, WebsiteEvent.EventType.STOP));
+        reportToPlatformIfDomainIsTracked("reportUsageStop", mLastFqdn);
+        mLastFqdn = null;
+    }
+
+    private void activeTabChanged(Tab tab) {
+        assert tab != null;
+        if (tab == mCurrentTab || mTabModelSelector.getCurrentTab() != tab) return;
+
+        switchObserverToTab(tab);
+        // If the newly active tab is hidden, we don't want to check its URL yet; we'll wait until
+        // the onShown event fires.
+        if (mCurrentTab != null && !tab.isHidden()) {
+            updateUrl(mCurrentTab.getUrl());
+        }
     }
 
     private void switchObserverToTab(Tab tab) {
@@ -185,4 +238,10 @@
             }
         });
     }
+
+    private static String getValidFqdnOrEmptyString(String url) {
+        if (url == null) return "";
+        String host = Uri.parse(url).getHost();
+        return host == null ? "" : host;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java
index 9ebf611b..98f78a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspendedTab.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.content.Intent;
-import android.net.Uri;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -16,10 +15,11 @@
 import android.widget.TextView;
 
 import org.chromium.base.UserData;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.WebContents;
 
 /**
  * Represents the suspension page presented when a user tries to visit a site whose fully-qualified
@@ -59,6 +59,12 @@
         mFqdn = fqdn;
         mTab.addObserver(this);
         mTab.stopLoading();
+
+        WebContents webContents = mTab.getWebContents();
+        if (webContents != null) {
+            webContents.onHide();
+        }
+
         if (isViewAttached()) {
             updateFqdnText();
         } else {
@@ -70,7 +76,11 @@
     public void removeIfPresent() {
         removeViewIfPresent();
 
-        mTab.removeObserver(this);
+        WebContents webContents = mTab.getWebContents();
+        if (webContents != null) {
+            webContents.onShow();
+        }
+
         mView = null;
         mFqdn = null;
     }
@@ -85,6 +95,11 @@
         return mFqdn != null;
     }
 
+    @VisibleForTesting
+    boolean isViewAttached() {
+        return mView != null && mView.getParent() == mTab.getContentView();
+    }
+
     private View createView() {
         Context context = mTab.getContext();
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -121,10 +136,6 @@
                         LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
     }
 
-    private boolean isViewAttached() {
-        return mView != null && mView.getParent() == mTab.getContentView();
-    }
-
     private void updateFqdnText() {
         Context context = mTab.getContext();
         TextView explanationText = (TextView) mView.findViewById(R.id.suspended_tab_explanation);
@@ -135,34 +146,12 @@
     private void removeViewIfPresent() {
         if (isViewAttached()) {
             mTab.getContentView().removeView(mView);
-        }
-    }
-
-    private void removeSelfIfFqdnChanged(String url) {
-        String newFqdn = Uri.parse(url).getHost();
-        if (newFqdn == null || !newFqdn.equals(mFqdn)) {
-            removeIfPresent();
+            mView = null;
         }
     }
 
     // TabObserver implementation.
     @Override
-    public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) {
-        removeSelfIfFqdnChanged(params.getUrl());
-    }
-
-    @Override
-    public void onPageLoadStarted(Tab tab, String url) {
-        removeSelfIfFqdnChanged(url);
-    }
-
-    @Override
-    public void onDestroyed(Tab tab) {
-        removeIfPresent();
-    }
-
-    // TODO(pnoland): Add integration tests for SuspendedTab that exercise this multi-window logic.
-    @Override
     public void onActivityAttachmentChanged(Tab tab, boolean isAttached) {
         if (!isAttached) {
             removeViewIfPresent();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
index 250cf173..ec423d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/usage_stats/SuspensionTracker.java
@@ -80,7 +80,7 @@
     public boolean isWebsiteSuspended(String fqdn) {
         // We special case isWebsiteSuspended to return a value immediately because its only
         // consumer(PageViewOsberver) only cares about immediate results.
-        if (mRootPromise.isFulfilled()) {
+        if (mRootPromise != null && mRootPromise.isFulfilled()) {
             return mRootPromise.getResult().contains(fqdn);
         }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java
new file mode 100644
index 0000000..83bdbb1
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/usage_stats/TabSuspensionTest.java
@@ -0,0 +1,353 @@
+// 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.
+
+package org.chromium.chrome.browser.usage_stats;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.base.test.util.ScalableTimeout;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
+import org.chromium.chrome.browser.ChromeTabbedActivity2;
+import org.chromium.chrome.browser.MockSafeBrowsingApiHandler;
+import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule;
+import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils;
+import org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper;
+import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tab.TabTestUtils;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
+import org.chromium.chrome.browser.tabmodel.TabSelectionType;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
+import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.chrome.test.util.MenuUtils;
+import org.chromium.components.safe_browsing.SafeBrowsingApiBridge;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.content_public.common.ContentSwitches;
+import org.chromium.net.test.EmbeddedTestServer;
+import org.chromium.ui.base.PageTransition;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Integration tests for {@link PageViewObserver} and {@link SuspendedTab}
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
+        // Direct all hostnames to EmbeddedTestServer running on 127.0.0.1.
+        ContentSwitches.HOST_RESOLVER_RULES + "=MAP * 127.0.0.1", "ignore-certificate-errors"})
+@MinAndroidSdkLevel(Build.VERSION_CODES.P)
+public class TabSuspensionTest {
+    private static final String STARTING_FQDN = "example.com";
+    private static final String DIFFERENT_FQDN = "www.google.com";
+
+    @Rule
+    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
+    @Rule
+    public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule();
+
+    @Mock
+    private UsageStatsBridge mUsageStatsBridge;
+    @Mock
+    private EventTracker mEventTracker;
+    @Mock
+    private SuspensionTracker mSuspensionTracker;
+
+    private ChromeTabbedActivity mActivity;
+    private PageViewObserver mPageViewObserver;
+    private TokenTracker mTokenTracker;
+    private Tab mTab;
+    private EmbeddedTestServer mTestServer;
+    private String mStartingUrl;
+    private String mDifferentUrl;
+
+    @Before
+    public void setUp() throws InterruptedException {
+        MockitoAnnotations.initMocks(this);
+        // TokenTracker holds a promise, and Promises can only be used on a single thread, so we
+        // have to initialize it on the thread where it will be used.
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { mTokenTracker = new TokenTracker(mUsageStatsBridge); });
+        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+        mStartingUrl = mTestServer.getURLWithHostName(STARTING_FQDN, "/defaultresponse");
+        mDifferentUrl = mTestServer.getURLWithHostName(DIFFERENT_FQDN, "/defaultresponse");
+
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mActivity = mActivityTestRule.getActivity();
+        mTab = mActivity.getActivityTab();
+        mPageViewObserver = new PageViewObserver(mActivity, mActivity.getTabModelSelector(),
+                mEventTracker, mTokenTracker, mSuspensionTracker);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mTestServer.stopAndDestroyServer();
+    }
+
+    @Test
+    @MediumTest
+    public void testNavigateToSuspended() throws InterruptedException {
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        startLoadingUrl(mTab, mStartingUrl);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+
+        startLoadingUrl(mTab, mDifferentUrl);
+        ChromeTabUtils.waitForTabPageLoaded(mTab, mDifferentUrl);
+        assertSuspendedTabHidden(mTab);
+    }
+
+    @Test
+    @MediumTest
+    public void testNavigateToSuspendedDomain_differentPage() throws InterruptedException {
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        startLoadingUrl(mTab, mStartingUrl);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+
+        startLoadingUrl(mTab, mStartingUrl + "foo.html");
+        assertSuspendedTabShowing(mTab, STARTING_FQDN);
+    }
+
+    @Test
+    @MediumTest
+    public void testNewTabSuspended() throws InterruptedException {
+        mActivityTestRule.loadUrl(mStartingUrl);
+
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
+        // We can't use loadUrlInNewTab because the site being suspended will prevent loading from
+        // completing, and loadUrlInNewTab expects loading to succeed.
+        ChromeTabUtils.newTabFromMenu(
+                InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
+        Tab tab2 = mActivity.getActivityTab();
+
+        startLoadingUrl(tab2, mDifferentUrl);
+        waitForSuspendedTabToShow(tab2, DIFFERENT_FQDN);
+    }
+
+    @Test
+    @MediumTest
+    public void testTabSwitchBackToSuspended() throws InterruptedException {
+        mActivityTestRule.loadUrl(mStartingUrl);
+        final int originalTabIndex =
+                mActivity.getTabModelSelector().getCurrentModel().indexOf(mTab);
+        Tab tab2 = mActivityTestRule.loadUrlInNewTab(mDifferentUrl);
+
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mActivity.getTabModelSelector().getCurrentModel().setIndex(
+                    originalTabIndex, TabSelectionType.FROM_USER);
+        });
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+    }
+
+    @Test
+    @MediumTest
+    public void testEagerSuspension() throws InterruptedException {
+        mActivityTestRule.loadUrl(mStartingUrl);
+        suspendDomain(STARTING_FQDN);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+
+        // Suspending again shouldn't crash or otherwise affect the state of the world.
+        suspendDomain(STARTING_FQDN);
+        assertSuspendedTabShowing(mTab, STARTING_FQDN);
+
+        // A single un-suspend should be sufficient even though we triggered suspension twice.
+        unsuspendDomain(STARTING_FQDN);
+        assertSuspendedTabHidden(mTab);
+    }
+
+    @Test
+    @MediumTest
+    public void testMultiWindow() throws InterruptedException {
+        mActivityTestRule.loadUrl(mStartingUrl);
+        Tab tab2 = mActivityTestRule.loadUrlInNewTab(mDifferentUrl);
+        suspendDomain(DIFFERENT_FQDN);
+        waitForSuspendedTabToShow(tab2, DIFFERENT_FQDN);
+
+        MultiWindowUtils.getInstance().setIsInMultiWindowModeForTesting(true);
+
+        MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
+                mActivity, R.id.move_to_other_window_menu_id);
+        final ChromeTabbedActivity2 activity2 =
+                MultiWindowTestHelper.waitForSecondChromeTabbedActivity();
+        MultiWindowTestHelper.waitForTabs("CTA", activity2, 1, tab2.getId());
+        waitForSuspendedTabToShow(tab2, DIFFERENT_FQDN);
+
+        // Each PageViewObserver is associated with a single ChromeTabbedActivity, so we need to
+        // create a new one for the other window.
+        PageViewObserver pageViewObserver2 = new PageViewObserver(activity2,
+                activity2.getTabModelSelector(), mEventTracker, mTokenTracker, mSuspensionTracker);
+
+        suspendDomain(STARTING_FQDN);
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { pageViewObserver2.notifySiteSuspensionChanged(DIFFERENT_FQDN, false); });
+        // Suspending and un-suspending should work in both activities/windows.
+        assertSuspendedTabHidden(tab2);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+    }
+
+    @Test
+    @MediumTest
+    public void testTabAddedFromCustomTab() throws InterruptedException {
+        mCustomTabActivityTestRule.startCustomTabActivityWithIntent(
+                CustomTabsTestUtils.createMinimalCustomTabIntent(
+                        InstrumentationRegistry.getTargetContext(), mStartingUrl));
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+
+        MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
+                mCustomTabActivityTestRule.getActivity(), R.id.open_in_browser_id);
+        MultiWindowTestHelper.waitForTabs("CustomTab", mActivity, 2, Tab.INVALID_TAB_ID);
+        waitForSuspendedTabToShow(mActivity.getActivityTab(), STARTING_FQDN);
+    }
+
+    @Test
+    @MediumTest
+    public void testTabAddedInBackground() throws InterruptedException, ExecutionException {
+        Tab bgTab = TestThreadUtils.runOnUiThreadBlocking(() -> {
+            return mActivity.getCurrentTabCreator().createNewTab(
+                    new LoadUrlParams(mStartingUrl), TabLaunchType.FROM_LONGPRESS_BACKGROUND, mTab);
+        });
+        ChromeTabUtils.waitForTabPageLoaded(bgTab, mStartingUrl);
+
+        suspendDomain(STARTING_FQDN);
+        assertSuspendedTabHidden(bgTab);
+    }
+
+    @Test
+    @MediumTest
+    public void testTabUnsuspendedInBackground() throws InterruptedException {
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        mActivityTestRule.loadUrl(mStartingUrl);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+        final int originalTabIndex =
+                mActivity.getTabModelSelector().getCurrentModel().indexOf(mTab);
+        Tab tab2 = mActivityTestRule.loadUrlInNewTab(mDifferentUrl);
+
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mPageViewObserver.notifySiteSuspensionChanged(STARTING_FQDN, false);
+            doReturn(false).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+            mActivity.getTabModelSelector().getCurrentModel().setIndex(
+                    originalTabIndex, TabSelectionType.FROM_USER);
+        });
+
+        assertSuspendedTabHidden(mTab);
+    }
+
+    @Test
+    @MediumTest
+    public void testNavigationFromSuspendedTabToInterstitial() throws InterruptedException {
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        mActivityTestRule.loadUrl(mStartingUrl);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+
+        SafeBrowsingApiBridge.setSafeBrowsingHandlerType(
+                new MockSafeBrowsingApiHandler().getClass());
+        MockSafeBrowsingApiHandler.addMockResponse(
+                mDifferentUrl, "{\"matches\":[{\"threat_type\":\"5\"}]}");
+        mActivityTestRule.loadUrl(mDifferentUrl);
+
+        assertSuspendedTabHidden(mTab);
+    }
+
+    @Test
+    @MediumTest
+    public void testRendererCrashOnSuspendedTab() throws InterruptedException {
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        mActivityTestRule.loadUrl(mStartingUrl);
+        waitForSuspendedTabToShow(mTab, STARTING_FQDN);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            TabTestUtils.simulateCrash(mTab, true);
+            assertSuspendedTabHidden(mTab);
+        });
+    }
+
+    private void startLoadingUrl(Tab tab, String url) {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { tab.loadUrl(new LoadUrlParams(url, PageTransition.TYPED)); });
+    }
+
+    private void assertSuspendedTabHidden(Tab tab) {
+        assertSuspendedTabState(tab, false, null);
+    }
+
+    private void assertSuspendedTabShowing(Tab tab, String fqdn) {
+        assertSuspendedTabState(tab, true, fqdn);
+    }
+
+    private void assertSuspendedTabState(Tab tab, boolean showing, String fqdn) {
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            SuspendedTab suspendedTab = SuspendedTab.from(tab);
+            assertEquals(suspendedTab.isShowing(), showing);
+            assertEquals(suspendedTab.isViewAttached(), showing);
+            assertTrue((suspendedTab.getFqdn() == null && fqdn == null)
+                    || fqdn.equals(suspendedTab.getFqdn()));
+        });
+    }
+
+    private void suspendDomain(String domain) {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { mPageViewObserver.notifySiteSuspensionChanged(domain, true); });
+    }
+
+    private void unsuspendDomain(String domain) {
+        TestThreadUtils.runOnUiThreadBlocking(
+                () -> { mPageViewObserver.notifySiteSuspensionChanged(domain, false); });
+    }
+
+    private void waitForSuspendedTabToShow(Tab tab, String fqdn) throws InterruptedException {
+        final CallbackHelper startedCallback = new CallbackHelper();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            SuspendedTab suspendedTab = SuspendedTab.from(tab);
+            if (suspendedTab.isShowing()) {
+                startedCallback.notifyCalled();
+                return;
+            }
+
+            tab.addObserver(new EmptyTabObserver() {
+                @Override
+                public void onUpdateUrl(Tab tab, String url) {
+                    startedCallback.notifyCalled();
+                    tab.removeObserver(this);
+                }
+
+                @Override
+                public void onShown(Tab tab, @TabSelectionType int type) {
+                    startedCallback.notifyCalled();
+                    tab.removeObserver(this);
+                }
+            });
+        });
+
+        try {
+            startedCallback.waitForCallback(
+                    0, 1, ScalableTimeout.scaleTimeout(10), TimeUnit.SECONDS);
+            assertSuspendedTabShowing(tab, fqdn);
+        } catch (TimeoutException e) {
+            Assert.fail("Tab never painted. url at failure: " + tab.getUrl());
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java
index 38ae952..e572ac65 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/geo/PlatformNetworksManagerTest.java
@@ -257,16 +257,6 @@
     }
 
     @Test
-    public void testGetConnectedCell_preJBMR1() {
-        ReflectionHelpers.setStaticField(
-                Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN);
-        VisibleCell visibleCell =
-                PlatformNetworksManager.getConnectedCell(mContext, mTelephonyManager);
-        assertEquals(UNKNOWN_VISIBLE_CELL, visibleCell);
-        assertNull(visibleCell.timestampMs());
-    }
-
-    @Test
     public void testGetConnectedCell_allPermissionsDenied() {
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.M);
         allPermissionsDenied();
@@ -319,39 +309,6 @@
     }
 
     @Test
-    public void testGetAllVisibleCells_JBMR1() {
-        ReflectionHelpers.setStaticField(
-                Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN_MR1);
-        PlatformNetworksManager.getAllVisibleCells(
-                mContext, mTelephonyManager, mVisibleCellCallback);
-        verify(mVisibleCellCallback).onResult(mVisibleCellsArgument.capture());
-
-        // WCDMA should be ignored for pre-JBMR1
-        assertEquals(mVisibleCellsArgument.getValue().size(), 3);
-        for (VisibleCell visibleCell : mVisibleCellsArgument.getValue()) {
-            switch (visibleCell.radioType()) {
-                case RadioType.LTE:
-                    assertEquals(LTE_CELL, visibleCell);
-                    assertEquals(Long.valueOf(CURRENT_TIME_MS - LTE_CELL_AGE),
-                            visibleCell.timestampMs());
-                    break;
-                case RadioType.GSM:
-                    assertEquals(visibleCell, GSM_CELL);
-                    assertEquals(Long.valueOf(CURRENT_TIME_MS - GSM_CELL_AGE),
-                            visibleCell.timestampMs());
-                    break;
-                case RadioType.CDMA:
-                    assertEquals(visibleCell, CDMA_CELL);
-                    assertEquals(Long.valueOf(CURRENT_TIME_MS - CDMA_CELL_AGE),
-                            visibleCell.timestampMs());
-                    break;
-                default:
-                    break;
-            }
-        }
-    }
-
-    @Test
     public void testGetAllVisibleCells_JBMR1_nullResult() {
         ReflectionHelpers.setStaticField(
                 Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN_MR1);
@@ -365,18 +322,6 @@
     }
 
     @Test
-    public void testGetAllVisibleCells_preJBMR1() {
-        ReflectionHelpers.setStaticField(
-                Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN);
-        PlatformNetworksManager.getAllVisibleCells(
-                mContext, mTelephonyManager, mVisibleCellCallback);
-        verify(mVisibleCellCallback).onResult(mVisibleCellsArgument.capture());
-
-        // Empty set expected
-        assertEquals(0, mVisibleCellsArgument.getValue().size());
-    }
-
-    @Test
     public void testGetAllVisibleCells_allPermissionsDenied() {
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.M);
         allPermissionsDenied();
@@ -458,24 +403,6 @@
     }
 
     @Test
-    public void testGetAllVisibleWifis_preJBMR1() {
-        ReflectionHelpers.setStaticField(
-                Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.JELLY_BEAN);
-        Set<VisibleWifi> visibleWifis =
-                PlatformNetworksManager.getAllVisibleWifis(mContext, mWifiManager);
-        assertEquals(2, visibleWifis.size());
-        for (VisibleWifi visibleWifi : visibleWifis) {
-            if (visibleWifi.bssid().equals(CONNECTED_WIFI.bssid())) {
-                assertEquals(CONNECTED_WIFI, visibleWifi);
-            } else {
-                assertEquals(NOT_CONNECTED_WIFI, visibleWifi);
-            }
-            // We should get null timestamp in Pre-JBMR1.
-            assertNull(visibleWifi.timestampMs());
-        }
-    }
-
-    @Test
     public void testGetAllVisibleWifis_allPermissionsDenied() {
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.M);
         allPermissionsDenied();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottleTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottleTest.java
index df84880d..d9f15542 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottleTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/partnerbookmarks/PartnerBookmarksFaviconThrottleTest.java
@@ -10,7 +10,6 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 import org.chromium.base.test.BaseRobolectricTestRunner;
@@ -31,8 +30,7 @@
 
     @Before
     public void setUp() throws Exception {
-        mFaviconThrottle = new PartnerBookmarksFaviconThrottle(
-                RuntimeEnvironment.application, TEST_PREFERENCES_NAME);
+        mFaviconThrottle = new PartnerBookmarksFaviconThrottle(TEST_PREFERENCES_NAME);
     }
 
     @After
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
index 82ca60b..a51f37d8 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/usage_stats/PageViewObserverTest.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.usage_stats;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Matchers.any;
@@ -15,6 +16,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
+import android.os.Build;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -29,9 +31,11 @@
 import org.chromium.base.Promise;
 import org.chromium.base.UserDataHost;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.Tab.TabHidingType;
 import org.chromium.chrome.browser.tab.TabObserver;
+import org.chromium.chrome.browser.tabmodel.TabLaunchType;
 import org.chromium.chrome.browser.tabmodel.TabModel;
 import org.chromium.chrome.browser.tabmodel.TabModelObserver;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
@@ -43,6 +47,7 @@
 /** Unit tests for PageViewObserver. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
+@MinAndroidSdkLevel(Build.VERSION_CODES.P)
 public final class PageViewObserverTest {
     private static final String STARTING_URL = "http://starting.url";
     private static final String DIFFERENT_URL = "http://different.url";
@@ -100,47 +105,58 @@
     }
 
     @Test
-    public void onUpdateUrl_currentlyNull_startReported() {
+    public void updateUrl_currentlyNull_startReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
     }
 
     @Test
-    public void onUpdateUrl_nullUrl() {
+    public void updateUrl_nullUrl() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, null);
+        updateUrl(mTab, null);
         onHidden(mTab, TabHidingType.ACTIVITY_HIDDEN);
         verify(mEventTracker, times(0)).addWebsiteEvent(any());
     }
 
     @Test
-    public void onUpdateUrl_startStopReported() {
+    public void updateUrl_startStopReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
         reset(mEventTracker);
-        onUpdateUrl(mTab, DIFFERENT_URL);
+        updateUrl(mTab, DIFFERENT_URL);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(DIFFERENT_FQDN)));
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStopEvent(STARTING_FQDN)));
     }
 
     @Test
-    public void onUpdateUrl_sameDomain_startStopNotReported() {
+    public void updateUrl_sameDomain_startStopNotReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
-        onUpdateUrl(mTab, STARTING_URL + "/some_other_page.html");
+        updateUrl(mTab, STARTING_URL + "/some_other_page.html");
+        verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
+    }
+
+    @Test
+    public void updateUrl_noPaint_doesNotReportStart() {
+        PageViewObserver observer = createPageViewObserver();
+        updateUrlNoPaint(mTab, STARTING_URL);
+        verify(mEventTracker, times(0)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
+        reportPaint(mTab, STARTING_URL);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
     }
 
     @Test
     public void switchTabs_startStopReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         reset(mEventTracker);
 
         doReturn(DIFFERENT_URL).when(mTab2).getUrl();
+        doReturn(mTab2).when(mTabModelSelector).getCurrentTab();
+        doReturn(false).when(mTab2).isHidden();
         didSelectTab(mTab2, TabSelectionType.FROM_USER);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(DIFFERENT_FQDN)));
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStopEvent(STARTING_FQDN)));
@@ -149,7 +165,7 @@
     @Test
     public void switchTabs_sameDomain_startStopNotReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
 
         doReturn(STARTING_URL).when(mTab2).getUrl();
@@ -158,9 +174,21 @@
     }
 
     @Test
+    public void switchToHiddenTab_startNotReported() {
+        PageViewObserver observer = createPageViewObserver();
+        updateUrl(mTab, STARTING_URL);
+        reset(mEventTracker);
+
+        doReturn(DIFFERENT_URL).when(mTab2).getUrl();
+        doReturn(true).when(mTab2).isHidden();
+        didSelectTab(mTab2, TabSelectionType.FROM_USER);
+        verify(mEventTracker, times(0)).addWebsiteEvent(argThat(isStartEvent(DIFFERENT_FQDN)));
+    }
+
+    @Test
     public void tabHidden_stopReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         onHidden(mTab, TabHidingType.ACTIVITY_HIDDEN);
 
         verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
@@ -179,7 +207,7 @@
     @Test
     public void tabClosed_switchToNew_startStopReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         onHidden(mTab, TabHidingType.ACTIVITY_HIDDEN);
 
         doReturn(DIFFERENT_URL).when(mTab2).getUrl();
@@ -191,9 +219,40 @@
     }
 
     @Test
+    public void tabAdded_startReported() {
+        PageViewObserver observer = createPageViewObserver();
+        doReturn(STARTING_URL).when(mTab2).getUrl();
+        doReturn(mTab2).when(mTabModelSelector).getCurrentTab();
+        didAddTab(mTab2, TabLaunchType.FROM_EXTERNAL_APP);
+
+        verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
+    }
+
+    @Test
+    public void tabAdded_notSelected_startNotReported() {
+        PageViewObserver observer = createPageViewObserver();
+        doReturn(STARTING_URL).when(mTab).getUrl();
+        doReturn(null).when(mTabModelSelector).getCurrentTab();
+        didAddTab(mTab, TabLaunchType.FROM_EXTERNAL_APP);
+
+        verify(mEventTracker, times(0)).addWebsiteEvent(argThat(isStartEvent(STARTING_FQDN)));
+    }
+
+    @Test
+    public void tabAdded_suspendedDomain() {
+        PageViewObserver observer = createPageViewObserver();
+        doReturn(STARTING_URL).when(mTab2).getUrl();
+        doReturn(mTab2).when(mTabModelSelector).getCurrentTab();
+        doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
+        didAddTab(mTab2, TabLaunchType.FROM_EXTERNAL_APP);
+
+        assertEquals(SuspendedTab.from(mTab2).getFqdn(), STARTING_FQDN);
+    }
+
+    @Test
     public void tabClosed_inBackground_stopNotReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
         getTabModelObserver().willCloseTab(mTab2, true);
         getTabModelObserver().tabRemoved(mTab2);
 
@@ -206,7 +265,7 @@
     @Test
     public void tabIncognito_eventsNotReported() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(true).when(mTab2).isIncognito();
         doReturn(DIFFERENT_URL).when(mTab2).getUrl();
@@ -218,123 +277,137 @@
     @Test
     public void navigationToSuspendedDomain_suspendedTabShown() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(DIFFERENT_URL).when(mTab).getUrl();
         doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
-        onUpdateUrl(mTab, DIFFERENT_URL);
+        updateUrl(mTab, DIFFERENT_URL);
 
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        assertTrue(mTabObserverCaptor.getValue() instanceof SuspendedTab);
+        SuspendedTab suspendedTab = SuspendedTab.from(mTab);
+        assertEquals(suspendedTab.getFqdn(), DIFFERENT_FQDN);
     }
 
     @Test
     public void navigationToUnsuspendedDomain_suspendedTabRemoved() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(DIFFERENT_URL).when(mTab).getUrl();
         doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
-        onUpdateUrl(mTab, DIFFERENT_URL);
+        updateUrl(mTab, DIFFERENT_URL);
 
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+        SuspendedTab suspendedTab = SuspendedTab.from(mTab);
+        assertTrue(suspendedTab.isShowing());
 
-        suspendedTab.onPageLoadStarted(mTab, STARTING_URL);
-        verify(mTab, times(1)).removeObserver(suspendedTab);
+        updateUrl(mTab, STARTING_URL);
+        assertFalse(suspendedTab.isShowing());
     }
 
     @Test
     public void eagerSuspension() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(STARTING_URL).when(mTab).getUrl();
         observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+        assertTrue(SuspendedTab.from(mTab).isShowing());
 
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        assertTrue(mTabObserverCaptor.getValue() instanceof SuspendedTab);
+        // Trying to suspend the site again shouldn't have an effect.
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+        assertTrue(SuspendedTab.from(mTab).isShowing());
     }
 
     @Test
     public void eagerSuspension_navigateToDifferentSuspended() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(STARTING_URL).when(mTab).getUrl();
         observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
 
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+        SuspendedTab suspendedTab = SuspendedTab.from(mTab);
         assertEquals(STARTING_FQDN, suspendedTab.getFqdn());
 
         doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
-        onUpdateUrl(mTab, DIFFERENT_URL);
+        updateUrl(mTab, DIFFERENT_URL);
 
-        verify(mTab, times(3)).addObserver(any());
         assertEquals(DIFFERENT_FQDN, suspendedTab.getFqdn());
     }
 
     @Test
     public void eagerSuspension_reshowSameDomain_nowUnsuspended() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(STARTING_URL).when(mTab).getUrl();
         observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
 
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        assertTrue(mTabObserverCaptor.getValue() instanceof SuspendedTab);
-        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+        SuspendedTab suspendedTab = SuspendedTab.from(mTab);
+        assertTrue(suspendedTab.isShowing());
 
         doReturn(false).when(mSuspensionTracker).isWebsiteSuspended(STARTING_FQDN);
         onShown(mTab, TabSelectionType.FROM_USER);
-        verify(mTab, times(1)).removeObserver(suspendedTab);
+        assertFalse(suspendedTab.isShowing());
     }
 
     @Test
     public void eagerUnsuspension() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(STARTING_URL).when(mTab).getUrl();
         observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
 
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        assertTrue(mTabObserverCaptor.getValue() instanceof SuspendedTab);
-        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+        SuspendedTab suspendedTab = SuspendedTab.from(mTab);
+        assertTrue(suspendedTab.isShowing());
 
         observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
-        verify(mTab, times(1)).removeObserver(suspendedTab);
+        assertFalse(suspendedTab.isShowing());
+
+        // Trying to un-suspend again should have no effect.
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
+        assertFalse(suspendedTab.isShowing());
     }
 
     @Test
     public void eagerUnsuspension_otherDomainActiveAndSuspended() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         doReturn(STARTING_URL).when(mTab).getUrl();
         observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
-        verify(mTab, times(2)).addObserver(mTabObserverCaptor.capture());
-        SuspendedTab suspendedTab = (SuspendedTab) mTabObserverCaptor.getValue();
+
+        SuspendedTab suspendedTab = SuspendedTab.from(mTab);
+        assertTrue(suspendedTab.isShowing());
 
         doReturn(true).when(mSuspensionTracker).isWebsiteSuspended(DIFFERENT_FQDN);
-        onUpdateUrl(mTab, DIFFERENT_URL);
+        updateUrl(mTab, DIFFERENT_URL);
 
         // Notifying that STARTING_FQDN is no longer suspended shouldn't remove the active
         // SuspendedTab for DIFFERENT_FQDN.
         observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
-        verify(mTab, times(0)).removeObserver(suspendedTab);
+        assertTrue(suspendedTab.isShowing());
     }
 
     @Test
     public void eagerUnsuspension_notAlreadySuspended() {
         PageViewObserver observer = createPageViewObserver();
-        onUpdateUrl(mTab, STARTING_URL);
+        updateUrl(mTab, STARTING_URL);
 
         observer.notifySiteSuspensionChanged(STARTING_FQDN, false);
-        verify(mTab, times(1)).addObserver(any());
-        verify(mTab, times(0)).removeObserver(any());
+        assertFalse(SuspendedTab.from(mTab).isShowing());
+    }
+
+    @Test
+    public void alreadySuspendedDomain_doesNotReportStopEventAgain() {
+        PageViewObserver observer = createPageViewObserver();
+        updateUrl(mTab, STARTING_URL);
+
+        observer.notifySiteSuspensionChanged(STARTING_FQDN, true);
+        verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStopEvent(STARTING_FQDN)));
+
+        updateUrl(mTab, DIFFERENT_URL);
+        verify(mEventTracker, times(1)).addWebsiteEvent(argThat(isStopEvent(STARTING_FQDN)));
     }
 
     private PageViewObserver createPageViewObserver() {
@@ -348,10 +421,20 @@
         return observer;
     }
 
-    private void onUpdateUrl(Tab tab, String url) {
+    private void updateUrl(Tab tab, String url) {
+        updateUrlNoPaint(tab, url);
+        reportPaint(tab, url);
+    }
+
+    private void updateUrlNoPaint(Tab tab, String url) {
         getTabObserver().onUpdateUrl(tab, url);
     }
 
+    private void reportPaint(Tab tab, String url) {
+        doReturn(url).when(tab).getUrl();
+        getTabObserver().didFirstVisuallyNonEmptyPaint(tab);
+    }
+
     private void onHidden(Tab tab, @TabHidingType int hidingType) {
         getTabObserver().onHidden(tab, hidingType);
     }
@@ -364,6 +447,10 @@
         getTabModelObserver().didSelectTab(tab, selectionType, 0);
     }
 
+    private void didAddTab(Tab tab, @TabLaunchType int launchType) {
+        getTabModelObserver().didAddTab(tab, launchType);
+    }
+
     private TabObserver getTabObserver() {
         if (mTabObserver == null) {
             mTabObserver = mTabObserverCaptor.getValue();
diff --git a/chrome/android/touchless/java/res/layout/touchless_dialog_view.xml b/chrome/android/touchless/java/res/layout/touchless_dialog_view.xml
index 954a1ab..a0b83ef 100644
--- a/chrome/android/touchless/java/res/layout/touchless_dialog_view.xml
+++ b/chrome/android/touchless/java/res/layout/touchless_dialog_view.xml
@@ -41,6 +41,8 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:padding="8dp"
+        android:divider="@android:color/transparent"
+        android:dividerHeight="8dp"
         android:layout_gravity="center" />
 
 </LinearLayout>
diff --git a/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml b/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml
index 8259302..bc1dcd9 100644
--- a/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml
+++ b/chrome/android/touchless/java/res/layout/touchless_suggestions_tile_view.xml
@@ -18,11 +18,14 @@
         android:background="@drawable/tile_view_icon_background_modern" />
 
     <!-- The main icon. -->
-    <ImageView
+    <org.chromium.chrome.browser.touchless.QuantizedSizeIconView
         android:id="@+id/tile_view_icon"
-        android:layout_width="@dimen/tile_view_icon_size_modern"
-        android:layout_height="@dimen/tile_view_icon_size_modern"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
         android:layout_gravity="center"
+	app:smallSize="@dimen/most_likely_quantized_icon_size_small"
+	app:largeSize="@dimen/most_likely_quantized_icon_size_large"
+        android:layout_margin="@dimen/most_likely_quantized_icon_margin"
         android:importantForAccessibility="no" />
 
     <!-- Focus highlight. -->
diff --git a/chrome/android/touchless/java/res/values-v17/attrs.xml b/chrome/android/touchless/java/res/values-v17/attrs.xml
new file mode 100644
index 0000000..029600d
--- /dev/null
+++ b/chrome/android/touchless/java/res/values-v17/attrs.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2014 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<resources>
+    <declare-styleable name="QuantizedSizeIconView">
+        <attr name="smallSize" format="dimension"/>
+        <attr name="largeSize" format="dimension"/>
+    </declare-styleable>
+</resources>
diff --git a/chrome/android/touchless/java/res/values-v17/colors.xml b/chrome/android/touchless/java/res/values-v17/colors.xml
index c76b22e..d198266 100644
--- a/chrome/android/touchless/java/res/values-v17/colors.xml
+++ b/chrome/android/touchless/java/res/values-v17/colors.xml
@@ -4,7 +4,8 @@
      found in the LICENSE file. -->
 
 <resources>
-    <color name="notouch_progress_bar_foreground">@color/google_blue_50</color>
+    <color name="modern_blue_100">#D2E3FC</color>
+    <color name="notouch_progress_bar_foreground">@color/modern_blue_100</color>
     <color name="notouch_progress_bar_text">@color/modern_grey_800</color>
     <color name="notouch_tooltip_background">@color/modern_grey_800</color>
     <color name="notouch_key_functions_iph_item_border">@android:color/white</color>
diff --git a/chrome/android/touchless/java/res/values-v17/dimens.xml b/chrome/android/touchless/java/res/values-v17/dimens.xml
index ccbe0d6fa..da89f73a 100644
--- a/chrome/android/touchless/java/res/values-v17/dimens.xml
+++ b/chrome/android/touchless/java/res/values-v17/dimens.xml
@@ -31,6 +31,12 @@
     <dimen name="most_likely_tile_size">40dp</dimen>
     <!-- Desired 24dp, but the edge spacer is also in effect. 8 + 16 = 24 -->
     <dimen name="above_the_fold_bottom_margin">16dp</dimen>
+    <dimen name="most_likely_quantized_icon_size_large">24dp</dimen>
+    <dimen name="most_likely_quantized_icon_size_small">18dp</dimen>
+    <!-- 6dp chosen so that the icon is large in the inner 3 positions and small in
+         the outer two positions. -->
+    <dimen name="most_likely_quantized_icon_margin">6dp</dimen>
+
 
     <!-- Article specific dimensions. -->
     <dimen name="touchless_snippets_padding">12dp</dimen>
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
index 821fad1..f303a2d 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/NoTouchActivity.java
@@ -26,6 +26,7 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabRedirectHandler;
 import org.chromium.chrome.browser.tab.TabState;
@@ -284,6 +285,13 @@
     }
 
     @Override
+    public void onStart() {
+        super.onStart();
+        ChromePreferenceManager.getInstance().incrementInt(
+                ChromePreferenceManager.TOUCHLESS_BROWSING_SESSION_COUNT);
+    }
+
+    @Override
     public void onStopWithNative() {
         super.onStopWithNative();
         getFullscreenManager().exitPersistentFullscreenMode();
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/QuantizedSizeIconView.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/QuantizedSizeIconView.java
new file mode 100644
index 0000000..c4fe1206
--- /dev/null
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/QuantizedSizeIconView.java
@@ -0,0 +1,79 @@
+// 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.
+
+package org.chromium.chrome.browser.touchless;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.support.annotation.Nullable;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import org.chromium.chrome.touchless.R;
+
+/** ImageView that keeps its image square and limited to a static set of sizes. */
+public class QuantizedSizeIconView extends ImageView {
+    private int[] mSizes;
+
+    public QuantizedSizeIconView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        Resources res = context.getResources();
+        TypedArray styledAttrs =
+                context.obtainStyledAttributes(attrs, R.styleable.QuantizedSizeIconView);
+        // Defaults are MAX_VALUE, in other words do not quantize.
+        mSizes = new int[] {styledAttrs.getDimensionPixelOffset(
+                                    R.styleable.QuantizedSizeIconView_largeSize, Integer.MAX_VALUE),
+                styledAttrs.getDimensionPixelOffset(
+                        R.styleable.QuantizedSizeIconView_smallSize, Integer.MAX_VALUE)};
+        styledAttrs.recycle();
+    }
+
+    public void setSizes(int[] sizes) {
+        mSizes = sizes;
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
+        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
+
+        int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
+
+        if (widthSpecMode == MeasureSpec.UNSPECIFIED && heightSpecMode != MeasureSpec.UNSPECIFIED) {
+            measuredWidth = measuredHeight;
+        } else if (heightSpecMode == MeasureSpec.UNSPECIFIED
+                && widthSpecMode != MeasureSpec.UNSPECIFIED) {
+            measuredHeight = measuredWidth;
+        } else if (heightSpecMode == MeasureSpec.UNSPECIFIED) {
+            // If both are UNSPECIFIED, take up as much room as possible.
+            measuredWidth = Integer.MAX_VALUE;
+            measuredHeight = Integer.MAX_VALUE;
+        } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.EXACTLY) {
+            measuredWidth = Math.min(measuredHeight, measuredWidth);
+        } else if (heightSpecMode == MeasureSpec.AT_MOST && widthSpecMode == MeasureSpec.EXACTLY) {
+            measuredHeight = Math.min(measuredWidth, measuredHeight);
+        } else if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {
+            int minimumDimension = Math.min(measuredHeight, measuredWidth);
+            measuredWidth = minimumDimension;
+            measuredHeight = minimumDimension;
+        }
+        // else keep values from the MeasureSpec because both modes are EXACTLY.
+
+        measuredHeight = quantizeDimension(measuredHeight);
+        measuredWidth = quantizeDimension(measuredWidth);
+
+        setMeasuredDimension(measuredWidth, measuredHeight);
+    }
+
+    private int quantizeDimension(int dimension) {
+        for (int sizeOption : mSizes) {
+            if (sizeOption <= dimension) {
+                return sizeOption;
+            }
+        }
+        return dimension;
+    }
+}
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHMediator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHMediator.java
index 418d8ca..4db876d 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHMediator.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/ui/iph/KeyFunctionsIPHMediator.java
@@ -6,8 +6,12 @@
 
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.ActivityTabProvider;
+import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.native_page.NativePageFactory;
+import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
+import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.components.feature_engagement.Tracker.DisplayLockHandle;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.touchless.CursorObserver;
@@ -22,10 +26,14 @@
     private final PropertyModel mModel;
     private final KeyFunctionsIPHTabObserver mKeyFunctionsIPHTabObserver;
     private FutureTask mHideTask;
-    private boolean mHasShownOnSpatNav;
-    private boolean mHasShownOnFallback;
+    private int mPageLoadCount;
 
-    private static final long DISPLAY_DURATION_MS = 1500;
+    private static final long DISPLAY_DURATION_MS = 3000;
+
+    // For the first INTRODUCTORY_SESSIONS sessions, show the IPH every INTRODUCTORY_PAGE_LOAD_CYCLE
+    // page loads.
+    private static final int INTRODUCTORY_SESSIONS = 6;
+    private static final int INTRODUCTORY_PAGE_LOAD_CYCLE = 3;
 
     KeyFunctionsIPHMediator(PropertyModel model, ActivityTabProvider activityTabProvider) {
         mModel = model;
@@ -38,25 +46,32 @@
 
     @Override
     public void onFallbackCursorModeToggled(boolean isOn) {
-        show(isOn);
+        show(isOn, false);
     }
 
-    private void show(boolean isFallbackCursorModeOn) {
+    private void show(boolean isFallbackCursorModeOn, boolean fromPageLoadStarted) {
         // TODO(crbug.com/942665): Populate this.
         boolean pageOptimizedForMobile = true;
-        if ((!isFallbackCursorModeOn && mHasShownOnSpatNav && pageOptimizedForMobile)
-                || (isFallbackCursorModeOn && mHasShownOnFallback)) {
-            return;
+        if (fromPageLoadStarted && pageOptimizedForMobile) {
+            int totalSessionCount = ChromePreferenceManager.getInstance().readInt(
+                    ChromePreferenceManager.TOUCHLESS_BROWSING_SESSION_COUNT);
+            if (totalSessionCount <= INTRODUCTORY_SESSIONS
+                    && mPageLoadCount % INTRODUCTORY_PAGE_LOAD_CYCLE != 1) {
+                return;
+            }
+            if (totalSessionCount > INTRODUCTORY_SESSIONS && mPageLoadCount > 1) return;
         }
 
-        if (isFallbackCursorModeOn) {
-            mHasShownOnFallback = true;
-        } else {
-            mHasShownOnSpatNav = true;
-        }
+        // This ensures that no other in-product help UI is currently shown.
+        DisplayLockHandle displayLockHandle =
+                TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile())
+                        .acquireDisplayLock();
+        if (displayLockHandle == null) return;
+
         if (mHideTask != null) mHideTask.cancel(false);
         mHideTask = new FutureTask<Void>(() -> {
             mModel.set(KeyFunctionsIPHProperties.IS_VISIBLE, false);
+            displayLockHandle.release();
             return null;
         });
         PostTask.postDelayedTask(UiThreadTaskTraits.DEFAULT, mHideTask, DISPLAY_DURATION_MS);
@@ -79,7 +94,8 @@
         public void onPageLoadStarted(Tab tab, String url) {
             if (NativePageFactory.isNativePageUrl(url, tab.isIncognito())) return;
 
-            show(false);
+            mPageLoadCount++;
+            show(false, true);
         }
     }
 }
diff --git a/chrome/android/touchless/touchless_java_sources.gni b/chrome/android/touchless/touchless_java_sources.gni
index 17c0ad62..9074b299 100644
--- a/chrome/android/touchless/touchless_java_sources.gni
+++ b/chrome/android/touchless/touchless_java_sources.gni
@@ -14,6 +14,7 @@
   "touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabViewBinder.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabView.java",
+  "touchless/java/src/org/chromium/chrome/browser/touchless/QuantizedSizeIconView.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/ScrollPositionInfo.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionModel.java",
   "touchless/java/src/org/chromium/chrome/browser/touchless/SiteSuggestionsAdapter.java",
diff --git a/chrome/android/webapk/shell_apk/current_version/current_version.gni b/chrome/android/webapk/shell_apk/current_version/current_version.gni
index 062cab9d..9d55305 100644
--- a/chrome/android/webapk/shell_apk/current_version/current_version.gni
+++ b/chrome/android/webapk/shell_apk/current_version/current_version.gni
@@ -12,4 +12,4 @@
 # //chrome/android/webapk/shell_apk:webapk is changed. This includes
 # Java files, Android resource files and AndroidManifest.xml. Does not affect
 # Chrome.apk
-current_shell_apk_version = 86
+current_shell_apk_version = 87
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
index 91f57b4..5ba26f0 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/WebApkUtils.java
@@ -7,6 +7,7 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -21,6 +22,8 @@
 import android.os.Bundle;
 import android.text.TextUtils;
 import android.util.TypedValue;
+import android.view.Display;
+import android.view.Surface;
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
@@ -290,4 +293,44 @@
     public static int getNotificationSmallIconId() {
         return R.drawable.notification_badge;
     }
+
+    /** Computes the screen lock orientation from the passed-in metadata and the display size.  */
+    public static int computeScreenLockOrientationFromMetaData(Context context, Bundle metadata) {
+        String orientation = metadata.getString(WebApkMetaDataKeys.ORIENTATION);
+        if (orientation == null) {
+            return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        } else if (orientation.equals("portrait-primary")) {
+            return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+        } else if (orientation.equals("portrait-secondary")) {
+            return ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+        } else if (orientation.equals("landscape-primary")) {
+            return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+        } else if (orientation.equals("landscape-secondary")) {
+            return ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
+        } else if (orientation.equals("portrait")) {
+            return ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
+        } else if (orientation.equals("landscape")) {
+            return ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
+        } else if (orientation.equals("any")) {
+            return ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+        } else if (orientation.equals("natural")) {
+            WindowManager windowManager =
+                    (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+            Display display = windowManager.getDefaultDisplay();
+            int rotation = display.getRotation();
+            if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
+                if (display.getHeight() >= display.getWidth()) {
+                    return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+                }
+                return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+            } else {
+                if (display.getHeight() < display.getWidth()) {
+                    return ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+                }
+                return ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+            }
+        } else {
+            return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+        }
+    }
 }
diff --git a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/h2o/SplashActivity.java b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/h2o/SplashActivity.java
index 22ef40c..6db22a1 100644
--- a/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/h2o/SplashActivity.java
+++ b/chrome/android/webapk/shell_apk/src/org/chromium/webapk/shell_apk/h2o/SplashActivity.java
@@ -8,6 +8,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
@@ -115,6 +116,11 @@
                 metadata, WebApkMetaDataKeys.THEME_COLOR, Color.BLACK);
         WebApkUtils.setStatusBarColor(
                 getWindow(), WebApkUtils.getDarkenedColorForStatusBar(themeColor));
+
+        int orientation = WebApkUtils.computeScreenLockOrientationFromMetaData(this, metadata);
+        if (orientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
+            setRequestedOrientation(orientation);
+        }
     }
 
     /** Called once the host browser has been selected. */
diff --git a/chrome/app/chrome_main_delegate.cc b/chrome/app/chrome_main_delegate.cc
index 5d9b16cf..4362562 100644
--- a/chrome/app/chrome_main_delegate.cc
+++ b/chrome/app/chrome_main_delegate.cc
@@ -543,6 +543,12 @@
   return false;
 }
 
+#if defined(OS_ANDROID)
+void ChromeMainDelegate::PostTaskSchedulerStart() {
+  startup_data_->CreateProfilePrefService();
+}
+#endif
+
 #endif
 
 void ChromeMainDelegate::PostFieldTrialInitialization() {
diff --git a/chrome/app/chrome_main_delegate.h b/chrome/app/chrome_main_delegate.h
index b2f71b92..108a1a5 100644
--- a/chrome/app/chrome_main_delegate.h
+++ b/chrome/app/chrome_main_delegate.h
@@ -66,6 +66,9 @@
 #if !defined(CHROME_MULTIPLE_DLL_CHILD)
   void PostEarlyInitialization(bool is_running_tests) override;
   bool ShouldCreateFeatureList() override;
+#if defined(OS_ANDROID)
+  void PostTaskSchedulerStart() override;
+#endif  // defined(OS_ANDROID)
 #endif  // !defined(CHROME_MULTIPLE_DLL_CHILD)
   void PostFieldTrialInitialization() override;
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index a8c0e0c..19e0174 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9605,7 +9605,7 @@
         Unknown account
       </message>
       <message name="IDS_WEBAUTHN_RESIDENT_KEY_PRIVACY" desc="A message included in dialogs when activating a security key (an external physical device for user authentication) may cause information about a site visit to be recorded on that security key. Since this is a privacy concern, a message is shown to the user.">
-        This will leave a record of your visit to <ph name="WEBSITE"><ex>accounts.google.com</ex>$1</ph> on your security key.
+        This will leave a record of your visit to this site on your security key.
       </message>
       <message name="IDS_WEBAUTHN_ERROR_MISSING_CAPABILITY_TITLE" desc="Title of the dialog informing the user that the security key (an external physical device for user authentication) that they selected does not support some capability that the site requested.">
         Your security key can't be used with this site
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 8c58418..5db3001 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1207,8 +1207,8 @@
     "policy/profile_policy_connector_builder.h",
     "policy/schema_registry_service.cc",
     "policy/schema_registry_service.h",
-    "policy/schema_registry_service_profile_builder.cc",
-    "policy/schema_registry_service_profile_builder.h",
+    "policy/schema_registry_service_builder.cc",
+    "policy/schema_registry_service_builder.h",
     "policy/webusb_allow_devices_for_urls_policy_handler.cc",
     "policy/webusb_allow_devices_for_urls_policy_handler.h",
     "predictors/autocomplete_action_predictor.cc",
@@ -1364,6 +1364,8 @@
     "profiles/off_the_record_profile_impl.h",
     "profiles/off_the_record_profile_io_data.cc",
     "profiles/off_the_record_profile_io_data.h",
+    "profiles/pref_service_builder_utils.cc",
+    "profiles/pref_service_builder_utils.h",
     "profiles/profile.cc",
     "profiles/profile.h",
     "profiles/profile_attributes_entry.cc",
@@ -2470,6 +2472,8 @@
       "android/preferences/preferences_launcher.h",
       "android/preferences/prefs.h",
       "android/preferences/website_preference_bridge.cc",
+      "android/profile_key_startup_accessor.cc",
+      "android/profile_key_startup_accessor.h",
       "android/profiles/profile_downloader_android.cc",
       "android/profiles/profile_manager_utils.cc",
       "android/provider/blocking_ui_thread_async_request.cc",
@@ -3219,16 +3223,10 @@
       "ssl/ssl_client_auth_observer.h",
       "status_icons/desktop_notification_balloon.cc",
       "status_icons/desktop_notification_balloon.h",
-      "sync/glue/extension_data_type_controller.cc",
-      "sync/glue/extension_data_type_controller.h",
       "sync/glue/extension_model_type_controller.cc",
       "sync/glue/extension_model_type_controller.h",
-      "sync/glue/extension_setting_data_type_controller.cc",
-      "sync/glue/extension_setting_data_type_controller.h",
       "sync/glue/extension_setting_model_type_controller.cc",
       "sync/glue/extension_setting_model_type_controller.h",
-      "sync/glue/theme_data_type_controller.cc",
-      "sync/glue/theme_data_type_controller.h",
       "sync/sessions/browser_list_router_helper.cc",
       "sync/sessions/browser_list_router_helper.h",
       "sync/sync_ui_util.cc",
@@ -4846,8 +4844,6 @@
       "supervised_user/supervised_user_settings_service_factory.h",
       "supervised_user/supervised_user_site_list.cc",
       "supervised_user/supervised_user_site_list.h",
-      "supervised_user/supervised_user_sync_data_type_controller.cc",
-      "supervised_user/supervised_user_sync_data_type_controller.h",
       "supervised_user/supervised_user_sync_model_type_controller.cc",
       "supervised_user/supervised_user_sync_model_type_controller.h",
       "supervised_user/supervised_user_url_filter.cc",
diff --git a/chrome/browser/android/profile_key_startup_accessor.cc b/chrome/browser/android/profile_key_startup_accessor.cc
new file mode 100644
index 0000000..7558aca
--- /dev/null
+++ b/chrome/browser/android/profile_key_startup_accessor.cc
@@ -0,0 +1,25 @@
+// 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 "chrome/browser/android/profile_key_startup_accessor.h"
+
+#include "base/logging.h"
+#include "base/no_destructor.h"
+
+ProfileKeyStartupAccessor::ProfileKeyStartupAccessor() : key_(nullptr) {}
+
+// static
+ProfileKeyStartupAccessor* ProfileKeyStartupAccessor::GetInstance() {
+  static base::NoDestructor<ProfileKeyStartupAccessor> instance;
+  return instance.get();
+}
+
+void ProfileKeyStartupAccessor::SetProfileKey(ProfileKey* key) {
+  DCHECK(!key_);
+  key_ = key;
+}
+
+void ProfileKeyStartupAccessor::Reset() {
+  key_ = nullptr;
+}
diff --git a/chrome/browser/android/profile_key_startup_accessor.h b/chrome/browser/android/profile_key_startup_accessor.h
new file mode 100644
index 0000000..b660550
--- /dev/null
+++ b/chrome/browser/android/profile_key_startup_accessor.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_ANDROID_PROFILE_KEY_STARTUP_ACCESSOR_H_
+#define CHROME_BROWSER_ANDROID_PROFILE_KEY_STARTUP_ACCESSOR_H_
+
+#include "base/macros.h"
+
+class ProfileKey;
+
+// The ProfileKeyStartupAccessor is a singleton class that exposes the
+// pointer of the ProfileKey of the associated Profile in the ServiceManager
+// only mode on Android. On Android, there is only one Profile, thus it is
+// possible to use this accessor to get the associated ProfileKey in the reduced
+// mode.
+//
+// Note: after the Profile is created, the ProfileKey should be obtained from
+// Profile.
+class ProfileKeyStartupAccessor {
+ public:
+  ProfileKeyStartupAccessor();
+
+  static ProfileKeyStartupAccessor* GetInstance();
+
+  // The |key_| should NOT be used after Profile is created.
+  ProfileKey* profile_key() { return key_; }
+  void SetProfileKey(ProfileKey* key);
+
+  // Resets the |key_| when the Profile is created.
+  void Reset();
+
+ private:
+  ProfileKey* key_;
+};
+
+#endif  // CHROME_BROWSER_ANDROID_PROFILE_KEY_STARTUP_ACCESSOR_H_
diff --git a/chrome/browser/autofill/legacy_strike_database_factory.cc b/chrome/browser/autofill/legacy_strike_database_factory.cc
index ce66f6b4..ab3d7fa 100644
--- a/chrome/browser/autofill/legacy_strike_database_factory.cc
+++ b/chrome/browser/autofill/legacy_strike_database_factory.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/browser/payments/legacy_strike_database.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/leveldb_proto/content/proto_database_provider_factory.h"
 
 namespace autofill {
 
@@ -27,18 +28,24 @@
 LegacyStrikeDatabaseFactory::LegacyStrikeDatabaseFactory()
     : BrowserContextKeyedServiceFactory(
           "AutofillLegacyStrikeDatabase",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
+}
 
 LegacyStrikeDatabaseFactory::~LegacyStrikeDatabaseFactory() {}
 
 KeyedService* LegacyStrikeDatabaseFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
+
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::ProtoDatabaseProviderFactory::GetInstance()->GetForKey(
+          profile->GetProfileKey());
+
   // Note: This instance becomes owned by an object that never gets destroyed,
   // effectively leaking it until browser close. Only one is created per
   // profile, and closing-then-opening a profile returns the same instance.
-  return new LegacyStrikeDatabase(
-      profile->GetPath().Append(FILE_PATH_LITERAL("AutofillStrikeDatabase")));
+  return new LegacyStrikeDatabase(db_provider, profile->GetPath());
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/autofill/strike_database_factory.cc b/chrome/browser/autofill/strike_database_factory.cc
index 475de2a7..30777b4 100644
--- a/chrome/browser/autofill/strike_database_factory.cc
+++ b/chrome/browser/autofill/strike_database_factory.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/autofill/core/browser/payments/strike_database.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/leveldb_proto/content/proto_database_provider_factory.h"
 
 namespace autofill {
 
@@ -26,18 +27,24 @@
 StrikeDatabaseFactory::StrikeDatabaseFactory()
     : BrowserContextKeyedServiceFactory(
           "AutofillStrikeDatabase",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
+}
 
 StrikeDatabaseFactory::~StrikeDatabaseFactory() {}
 
 KeyedService* StrikeDatabaseFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = Profile::FromBrowserContext(context);
+
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::ProtoDatabaseProviderFactory::GetInstance()->GetForKey(
+          profile->GetProfileKey());
+
   // Note: This instance becomes owned by an object that never gets destroyed,
   // effectively leaking it until browser close. Only one is created per
   // profile, and closing-then-opening a profile returns the same instance.
-  return new StrikeDatabase(
-      profile->GetPath().Append(FILE_PATH_LITERAL("AutofillStrikeDatabase")));
+  return new StrikeDatabase(db_provider, profile->GetPath());
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index cac72c6..761d300 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -38,6 +38,7 @@
 class SystemNetworkContextManager;
 class WatchDogThread;
 class WebRtcLogUploader;
+class StartupData;
 
 namespace network {
 class NetworkQualityTracker;
@@ -253,6 +254,10 @@
   virtual optimization_guide::OptimizationGuideService*
   optimization_guide_service() = 0;
 
+  // Returns the StartupData which owns any pre-created objects in //chrome
+  // before the full browser starts.
+  virtual StartupData* startup_data() = 0;
+
 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
   // This will start a timer that, if Chrome is in persistent mode, will check
   // whether an update is available, and if that's the case, restart the
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 0b15890..b18b11d4 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -232,6 +232,7 @@
   g_browser_process = this;
 
   DCHECK(startup_data);
+  startup_data_ = startup_data;
 
   chrome_feature_list_creator_ = startup_data->chrome_feature_list_creator();
   browser_policy_connector_ =
@@ -1040,6 +1041,10 @@
   return optimization_guide_service_.get();
 }
 
+StartupData* BrowserProcessImpl::startup_data() {
+  return startup_data_;
+}
+
 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
 void BrowserProcessImpl::StartAutoupdateTimer() {
   autoupdate_timer_.Start(FROM_HERE,
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index 6c8e21f6..52ca84f 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -181,6 +181,8 @@
   optimization_guide::OptimizationGuideService* optimization_guide_service()
       override;
 
+  StartupData* startup_data() override;
+
 #if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
   void StartAutoupdateTimer() override;
 #endif
@@ -352,6 +354,8 @@
   // BrowserProcessImpl to create the |local_state_|.
   ChromeFeatureListCreator* chrome_feature_list_creator_;
 
+  StartupData* startup_data_;
+
   // Ensures that the observers of plugin/print disable/enable state
   // notifications are properly added and removed.
   PrefChangeRegistrar pref_change_registrar_;
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index e05de2cd..f4994b94 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -44,6 +44,7 @@
 #include "chrome/browser/conflicts/module_database_win.h"
 #include "chrome/browser/conflicts/module_event_sink_impl_win.h"
 #include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/memory/memory_pressure_monitor.h"
 #include "chrome/browser/memory/swap_thrashing_monitor.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_shortcut_manager.h"
@@ -613,6 +614,9 @@
   // it easier to experiment with this monitor.
   if (base::FeatureList::IsEnabled(features::kSwapThrashingMonitor))
     memory::SwapThrashingMonitor::Initialize();
+
+  if (base::FeatureList::IsEnabled(features::kNewMemoryPressureMonitor))
+    memory_pressure_monitor_ = memory::MemoryPressureMonitor::Create();
 }
 
 // static
diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h
index 70639aec..382216c 100644
--- a/chrome/browser/chrome_browser_main_win.h
+++ b/chrome/browser/chrome_browser_main_win.h
@@ -19,6 +19,10 @@
 class CommandLine;
 }
 
+namespace memory {
+class MemoryPressureMonitor;
+}
+
 // Handle uninstallation when given the appropriate the command-line switch.
 // If |chrome_still_running| is true a modal dialog will be shown asking the
 // user to close the other chrome instance.
@@ -74,6 +78,11 @@
   // Watches module load events and forwards them to the ModuleDatabase.
   std::unique_ptr<ModuleWatcher> module_watcher_;
 
+  // The memory pressure monitor. This is currently only being used to record
+  // metrics, the base::MemoryPressureMonitor is still being used to emit memory
+  // pressure signals.
+  std::unique_ptr<memory::MemoryPressureMonitor> memory_pressure_monitor_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainPartsWin);
 };
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index b144befd..9df8b7c2 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -344,6 +344,7 @@
 #include "services/service_manager/sandbox/sandbox_type.h"
 #include "services/viz/public/interfaces/constants.mojom.h"
 #include "storage/browser/fileapi/external_mount_points.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/mojom/installedapp/installed_app_provider.mojom.h"
 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
 #include "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom.h"
@@ -1078,6 +1079,12 @@
     LOG(WARNING) << "Ignored invalid value for flag --" << switches::kUserAgent;
   }
 
+  if (base::FeatureList::IsEnabled(blink::features::kFreezeUserAgent)) {
+    return content::GetFrozenUserAgent(
+               command_line->HasSwitch(switches::kUseMobileUserAgent))
+        .as_string();
+  }
+
   std::string product = GetProduct();
 #if defined(OS_ANDROID)
   if (command_line->HasSwitch(switches::kUseMobileUserAgent))
@@ -1088,7 +1095,6 @@
 
 blink::UserAgentMetadata GetUserAgentMetadata() {
   blink::UserAgentMetadata metadata;
-
   metadata.brand = version_info::GetProductName();
   metadata.full_version = version_info::GetVersionNumber();
   metadata.major_version = version_info::GetMajorVersionNumber();
@@ -1212,10 +1218,16 @@
   main_parts = new ChromeBrowserMainParts(parameters, startup_data_);
 #endif
 
-  chrome::AddProfilesExtraParts(main_parts);
+  bool add_profiles_extra_parts = true;
+#if defined(OS_ANDROID)
+  if (startup_data_->HasBuiltProfilePrefService())
+    add_profiles_extra_parts = false;
+#endif
+  if (add_profiles_extra_parts)
+    chrome::AddProfilesExtraParts(main_parts);
 
-  // Construct additional browser parts. Stages are called in the order in
-  // which they are added.
+    // Construct additional browser parts. Stages are called in the order in
+    // which they are added.
 #if defined(TOOLKIT_VIEWS)
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(USE_OZONE)
   main_parts->AddParts(new ChromeBrowserMainExtraPartsViewsLinux());
@@ -5409,6 +5421,17 @@
     content::PreviewsState initial_state,
     content::NavigationHandle* navigation_handle,
     const GURL& current_navigation_url) {
+  content::PreviewsState state = DetermineAllowedPreviewsWithoutHoldback(
+      initial_state, navigation_handle, current_navigation_url);
+
+  return previews::MaybeCoinFlipHoldbackBeforeCommit(state, navigation_handle);
+}
+
+content::PreviewsState
+ChromeContentBrowserClient::DetermineAllowedPreviewsWithoutHoldback(
+    content::PreviewsState initial_state,
+    content::NavigationHandle* navigation_handle,
+    const GURL& current_navigation_url) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!navigation_handle->HasCommitted());
 
@@ -5574,6 +5597,17 @@
     content::PreviewsState initial_state,
     content::NavigationHandle* navigation_handle,
     const net::HttpResponseHeaders* response_headers) {
+  content::PreviewsState state = DetermineCommittedPreviewsWithoutHoldback(
+      initial_state, navigation_handle, response_headers);
+
+  return previews::MaybeCoinFlipHoldbackAfterCommit(state, navigation_handle);
+}
+
+content::PreviewsState
+ChromeContentBrowserClient::DetermineCommittedPreviewsWithoutHoldback(
+    content::PreviewsState initial_state,
+    content::NavigationHandle* navigation_handle,
+    const net::HttpResponseHeaders* response_headers) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   // Only support HTTP and HTTPS.
   if (navigation_handle->IsErrorPage() ||
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 3a469a5..7926733 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -571,6 +571,7 @@
       content::PreviewsState initial_state,
       content::NavigationHandle* navigation_handle,
       const net::HttpResponseHeaders* response_headers) override;
+
   void LogWebFeatureForCurrentPage(content::RenderFrameHost* render_frame_host,
                                    blink::mojom::WebFeature feature) override;
 
@@ -595,6 +596,16 @@
   base::flat_set<std::string> GetMimeHandlerViewMimeTypes(
       content::ResourceContext* resource_context) override;
 
+  content::PreviewsState DetermineAllowedPreviewsWithoutHoldback(
+      content::PreviewsState initial_state,
+      content::NavigationHandle* navigation_handle,
+      const GURL& current_navigation_url);
+
+  content::PreviewsState DetermineCommittedPreviewsWithoutHoldback(
+      content::PreviewsState initial_state,
+      content::NavigationHandle* navigation_handle,
+      const net::HttpResponseHeaders* response_headers);
+
   // Determines the committed previews state for the passed in params.
   static content::PreviewsState DetermineCommittedPreviewsForURL(
       const GURL& url,
diff --git a/chrome/browser/chrome_content_browser_client_unittest.cc b/chrome/browser/chrome_content_browser_client_unittest.cc
index 1f88cc14..f1f986b3 100644
--- a/chrome/browser/chrome_content_browser_client_unittest.cc
+++ b/chrome/browser/chrome_content_browser_client_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/browsing_data_helper.h"
 #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h"
@@ -34,10 +35,12 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/user_agent.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "media/media_buildflags.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "url/gurl.h"
 
@@ -431,6 +434,45 @@
                     GURL("https://www.google.com/search?notaquery=nope")));
 }
 
+TEST(ChromeContentBrowserClient, UserAgentStringFrozen) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(blink::features::kFreezeUserAgent);
+
+#if defined(OS_ANDROID)
+  // Verify the correct user agent is returned when the UseMobileUserAgent
+  // command line flag is present.
+  const char* const kArguments[] = {"chrome"};
+  base::test::ScopedCommandLine scoped_command_line;
+  base::CommandLine* command_line = scoped_command_line.GetProcessCommandLine();
+  command_line->InitFromArgv(1, kArguments);
+
+  // Verify the mobile user agent string is not returned when not using a mobile
+  // user agent.
+  ASSERT_FALSE(command_line->HasSwitch(switches::kUseMobileUserAgent));
+  {
+    ChromeContentBrowserClient content_browser_client;
+    std::string buffer = content_browser_client.GetUserAgent();
+    EXPECT_EQ(buffer, content::frozen_user_agent_strings::kAndroid);
+  }
+
+  // Verify the mobile user agent string is returned when using a mobile user
+  // agent.
+  command_line->AppendSwitch(switches::kUseMobileUserAgent);
+  ASSERT_TRUE(command_line->HasSwitch(switches::kUseMobileUserAgent));
+  {
+    ChromeContentBrowserClient content_browser_client;
+    std::string buffer = content_browser_client.GetUserAgent();
+    EXPECT_EQ(buffer, content::frozen_user_agent_strings::kAndroidMobile);
+  }
+#else
+  {
+    ChromeContentBrowserClient content_browser_client;
+    std::string buffer = content_browser_client.GetUserAgent();
+    EXPECT_EQ(buffer, content::frozen_user_agent_strings::kDesktop);
+  }
+#endif
+}
+
 TEST(ChromeContentBrowserClient, UserAgentStringOrdering) {
 #if defined(OS_ANDROID)
   const char* const kArguments[] = {"chrome"};
diff --git a/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc b/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc
index d905cbb..cc49e90 100644
--- a/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc
+++ b/chrome/browser/chromeos/accessibility/ax_remote_host_delegate.cc
@@ -6,8 +6,8 @@
 
 #include "base/bind.h"
 #include "chrome/browser/chromeos/accessibility/ax_host_service.h"
-#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 #include "chrome/common/extensions/chrome_extension_messages.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
 #include "ui/accessibility/ax_event.h"
 #include "ui/accessibility/ax_tree_update.h"
 #include "ui/aura/env.h"
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
index 32f36d2..50feda9a 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_browsertest.cc
@@ -27,7 +27,6 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 #include "chrome/browser/ui/ash/ksv/keyboard_shortcut_viewer_util.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
@@ -49,6 +48,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
 #include "extensions/browser/extension_host.h"
 #include "extensions/browser/process_manager.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
index 4bcd8cc..5da1670 100644
--- a/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
+++ b/chrome/browser/chromeos/arc/accessibility/ax_tree_source_arc.cc
@@ -10,9 +10,9 @@
 #include "chrome/browser/chromeos/arc/accessibility/accessibility_node_info_data_wrapper.h"
 #include "chrome/browser/chromeos/arc/accessibility/accessibility_window_info_data_wrapper.h"
 #include "chrome/browser/chromeos/arc/accessibility/arc_accessibility_util.h"
-#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
 #include "chrome/common/extensions/chrome_extension_messages.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
 #include "extensions/common/extension_messages.h"
 #include "ui/accessibility/platform/ax_android_constants.h"
 #include "ui/aura/window.h"
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
index 82506ff..cb0e6510 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service.cc
@@ -154,17 +154,27 @@
          user->GetAccountId().GetGaiaId() == gaia_id;
 }
 
-std::string GetGaiaIdFromAccountName(
+bool IsPrimaryOrDeviceLocalAccount(
     const identity::IdentityManager* identity_manager,
     const std::string& account_name) {
-  std::string gaia_id =
+  // |GetPrimaryUser| is fine because ARC is only available on the first
+  // (Primary) account that participates in multi-signin.
+  const user_manager::User* user =
+      user_manager::UserManager::Get()->GetPrimaryUser();
+  DCHECK(user);
+
+  // There is no Gaia user for device local accounts, but in this case there is
+  // always only a primary account.
+  if (user->IsDeviceLocalAccount())
+    return true;
+
+  const std::string gaia_id =
       identity_manager
           ->FindAccountInfoForAccountWithRefreshTokenByEmailAddress(
               account_name)
           ->gaia;
   DCHECK(!gaia_id.empty());
-
-  return gaia_id;
+  return IsPrimaryGaiaAccount(gaia_id);
 }
 
 }  // namespace
@@ -251,9 +261,14 @@
     return;
   }
 
+  // Re-auth shouldn't be triggered for non-Gaia device local accounts.
+  if (!user_manager::UserManager::Get()->IsLoggedInAsUserWithGaiaAccount()) {
+    NOTREACHED() << "Shouldn't re-auth for non-Gaia accounts";
+    return;
+  }
+
   if (!account_name.has_value() ||
-      IsPrimaryGaiaAccount(
-          GetGaiaIdFromAccountName(identity_manager_, account_name.value()))) {
+      IsPrimaryOrDeviceLocalAccount(identity_manager_, account_name.value())) {
     // Reauthorization for the Primary Account.
     // The check for |!account_name.has_value()| is for backwards compatibility
     // with older ARC versions, for which Mojo will set |account_name| to
@@ -368,8 +383,7 @@
   // ARC, or for signing in a new Secondary Account.
 
   // Check if |account_name| points to a Secondary Account.
-  if (!IsPrimaryGaiaAccount(
-          GetGaiaIdFromAccountName(identity_manager_, account_name))) {
+  if (!IsPrimaryOrDeviceLocalAccount(identity_manager_, account_name)) {
     FetchSecondaryAccountInfo(account_name, std::move(callback));
     return;
   }
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
index d3887fa9..e3f1ce86 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_service_browsertest.cc
@@ -29,6 +29,7 @@
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/chrome_device_id_helper.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -827,6 +828,30 @@
   EXPECT_TRUE(auth_instance().account_info()->is_managed);
 }
 
+IN_PROC_BROWSER_TEST_F(ArcRobotAccountAuthServiceTest,
+                       RequestPublicAccountInfo) {
+  SetAccountAndProfile(user_manager::USER_TYPE_PUBLIC_ACCOUNT);
+  profile()->GetProfilePolicyConnector()->OverrideIsManagedForTesting(true);
+
+  test_url_loader_factory()->SetInterceptor(
+      base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
+        ResponseJob(request, test_url_loader_factory());
+      }));
+
+  base::RunLoop run_loop;
+  auth_instance().RequestAccountInfo(kFakeUserName, run_loop.QuitClosure());
+  run_loop.Run();
+
+  ASSERT_TRUE(auth_instance().account_info());
+  EXPECT_EQ(kFakeUserName,
+            auth_instance().account_info()->account_name.value());
+  EXPECT_EQ(kFakeAuthCode, auth_instance().account_info()->auth_code.value());
+  EXPECT_EQ(mojom::ChromeAccountType::ROBOT_ACCOUNT,
+            auth_instance().account_info()->account_type);
+  EXPECT_FALSE(auth_instance().account_info()->enrollment_token);
+  EXPECT_TRUE(auth_instance().account_info()->is_managed);
+}
+
 class ArcAuthServiceChildAccountTest : public ArcAuthServiceTest {
  protected:
   ArcAuthServiceChildAccountTest() = default;
diff --git a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.cc b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.cc
index 4a713cf..07d6440 100644
--- a/chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.cc
+++ b/chrome/browser/chromeos/arc/optin/arc_terms_of_service_oobe_negotiator.cc
@@ -23,7 +23,7 @@
   chromeos::LoginDisplayHost* host = chromeos::LoginDisplayHost::default_host();
   DCHECK(host);
   DCHECK(host->GetOobeUI());
-  return host->GetOobeUI()->GetArcTermsOfServiceScreenView();
+  return host->GetOobeUI()->GetView<chromeos::ArcTermsOfServiceScreenHandler>();
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 9ec534e0..16117c26 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -215,7 +215,6 @@
 bool ShouldAutoLaunchKioskApp(const base::CommandLine& command_line) {
   KioskAppManager* app_manager = KioskAppManager::Get();
   return command_line.HasSwitch(switches::kLoginManager) &&
-         !command_line.HasSwitch(switches::kForceLoginManagerInTests) &&
          app_manager->IsAutoLaunchEnabled() &&
          KioskAppLaunchError::Get() == KioskAppLaunchError::NONE;
 }
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index 97d09ae..ec92b3c 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -153,8 +153,8 @@
       diagnostic_mode_(diagnostic_mode),
       host_(host),
       oobe_ui_(oobe_ui),
-      app_launch_splash_screen_view_(oobe_ui_->GetAppLaunchSplashScreenView()) {
-}
+      app_launch_splash_screen_view_(
+          oobe_ui_->GetView<AppLaunchSplashScreenHandler>()) {}
 
 AppLaunchController::~AppLaunchController() {
   if (app_launch_splash_screen_view_)
diff --git a/chrome/browser/chromeos/login/app_launch_controller.h b/chrome/browser/chromeos/login/app_launch_controller.h
index bdc1295..e014080 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.h
+++ b/chrome/browser/chromeos/login/app_launch_controller.h
@@ -23,6 +23,7 @@
 
 namespace chromeos {
 
+class AppLaunchSplashScreenView;
 class LoginDisplayHost;
 class OobeUI;
 
diff --git a/chrome/browser/chromeos/login/arc_kiosk_controller.cc b/chrome/browser/chromeos/login/arc_kiosk_controller.cc
index 178a0f7..238a170 100644
--- a/chrome/browser/chromeos/login/arc_kiosk_controller.cc
+++ b/chrome/browser/chromeos/login/arc_kiosk_controller.cc
@@ -31,7 +31,8 @@
 
 ArcKioskController::ArcKioskController(LoginDisplayHost* host, OobeUI* oobe_ui)
     : host_(host),
-      arc_kiosk_splash_screen_view_(oobe_ui->GetArcKioskSplashScreenView()),
+      arc_kiosk_splash_screen_view_(
+          oobe_ui->GetView<ArcKioskSplashScreenHandler>()),
       weak_ptr_factory_(this) {}
 
 ArcKioskController::~ArcKioskController() {
diff --git a/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc b/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
index f0766d98..5d65bba3 100644
--- a/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
+++ b/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
@@ -21,6 +21,9 @@
 #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/login/app_launch_controller.h"
+#include "chrome/browser/chromeos/login/mixin_based_in_process_browser_test.h"
+#include "chrome/browser/chromeos/login/test/embedded_test_server_mixin.h"
+#include "chrome/browser/chromeos/login/test/login_manager_mixin.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
@@ -31,11 +34,11 @@
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "chromeos/dbus/cryptohome/cryptohome_client.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
 #include "chromeos/dbus/shill/shill_manager_client.h"
 #include "chromeos/tpm/stub_install_attributes.h"
+#include "components/crx_file/crx_verifier.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/notification_service.h"
@@ -47,7 +50,6 @@
 #include "extensions/test/extension_test_message_listener.h"
 #include "extensions/test/result_catcher.h"
 #include "net/dns/mock_host_resolver.h"
-#include "third_party/cros_system_api/switches/chrome_switches.h"
 
 namespace em = enterprise_management;
 
@@ -93,168 +95,6 @@
 
 constexpr char kTestAccountId[] = "enterprise-kiosk-app@localhost";
 
-constexpr char kSessionManagerStateCache[] = "test_session_manager_state.json";
-
-// Keys for values in dictionary used to preserve session manager state.
-constexpr char kLoginArgsKey[] = "login_args";
-constexpr char kExtraArgsKey[] = "extra_args";
-constexpr char kArgNameKey[] = "name";
-constexpr char kArgValueKey[] = "value";
-
-// Default set policy switches.
-constexpr struct {
-  const char* name;
-  const char* value;
-} kDefaultPolicySwitches[] = {{"test_switch_1", ""},
-                              {"test_switch_2", "test_switch_2_value"}};
-
-// Fake session manager implementation that persists its state in local file.
-// It can be used to preserve session state in PRE_ browser tests.
-// Primarily used for testing user/login switches.
-class PersistentSessionManagerClient : public FakeSessionManagerClient {
- public:
-  PersistentSessionManagerClient() {}
-
-  ~PersistentSessionManagerClient() override {
-    PersistFlagsToFile(backing_file_);
-  }
-
-  // Initializes session state (primarily session flags)- if |backing_file|
-  // exists, the session state is restored from the file value. Otherwise it's
-  // set to the default session state.
-  void Initialize(const base::FilePath& backing_file) {
-    backing_file_ = backing_file;
-
-    if (ExtractFlagsFromFile(backing_file_))
-      return;
-
-    // Failed to extract ached flags - set the default values.
-    login_args_ = {{"login-manager", ""}};
-
-    extra_args_ = {{switches::kPolicySwitchesBegin, ""}};
-    for (size_t i = 0; i < base::size(kDefaultPolicySwitches); ++i) {
-      extra_args_.push_back(
-          {kDefaultPolicySwitches[i].name, kDefaultPolicySwitches[i].value});
-    }
-    extra_args_.push_back({switches::kPolicySwitchesEnd, ""});
-  }
-
-  void AppendSwitchesToCommandLine(base::CommandLine* command_line) {
-    for (const auto& flag : login_args_)
-      command_line->AppendSwitchASCII(flag.name, flag.value);
-    for (const auto& flag : extra_args_)
-      command_line->AppendSwitchASCII(flag.name, flag.value);
-  }
-
-  void StartSession(
-      const cryptohome::AccountIdentifier& cryptohome_id) override {
-    FakeSessionManagerClient::StartSession(cryptohome_id);
-
-    std::string user_id_hash =
-        CryptohomeClient::GetStubSanitizedUsername(cryptohome_id);
-    login_args_ = {{"login-user", cryptohome_id.account_id()},
-                   {"login-profile", user_id_hash}};
-  }
-
-  void StopSession() override {
-    FakeSessionManagerClient::StopSession();
-
-    login_args_ = {{"login-manager", ""}};
-  }
-
-  bool SupportsRestartToApplyUserFlags() const override { return true; }
-
-  void SetFlagsForUser(const cryptohome::AccountIdentifier& identification,
-                       const std::vector<std::string>& flags) override {
-    extra_args_.clear();
-    FakeSessionManagerClient::SetFlagsForUser(identification, flags);
-
-    std::vector<std::string> argv = {"" /* Empty program */};
-    argv.insert(argv.end(), flags.begin(), flags.end());
-
-    // Parse flag name-value pairs using command line initialization.
-    base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
-    cmd_line.InitFromArgv(argv);
-
-    for (const auto& flag : cmd_line.GetSwitches())
-      extra_args_.push_back({flag.first, flag.second});
-  }
-
- private:
-  // Keeps information about a switch - its name and value.
-  struct Switch {
-    std::string name;
-    std::string value;
-  };
-
-  bool ExtractFlagsFromFile(const base::FilePath& backing_file) {
-    JSONFileValueDeserializer deserializer(backing_file);
-
-    int error_code = 0;
-    std::unique_ptr<base::Value> value =
-        deserializer.Deserialize(&error_code, nullptr);
-    if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR)
-      return false;
-
-    std::unique_ptr<base::DictionaryValue> value_dict =
-        base::DictionaryValue::From(std::move(value));
-    CHECK(value_dict);
-
-    CHECK(InitArgListFromCachedValue(*value_dict, kLoginArgsKey, &login_args_));
-    CHECK(InitArgListFromCachedValue(*value_dict, kExtraArgsKey, &extra_args_));
-    return true;
-  }
-
-  bool PersistFlagsToFile(const base::FilePath& backing_file) {
-    base::DictionaryValue cached_state;
-    cached_state.Set(kLoginArgsKey, GetArgListValue(login_args_));
-    cached_state.Set(kExtraArgsKey, GetArgListValue(extra_args_));
-
-    JSONFileValueSerializer serializer(backing_file);
-    return serializer.Serialize(cached_state);
-  }
-
-  std::unique_ptr<base::ListValue> GetArgListValue(
-      const std::vector<Switch>& args) {
-    std::unique_ptr<base::ListValue> result(new base::ListValue());
-    for (const auto& arg : args) {
-      result->Append(extensions::DictionaryBuilder()
-                         .Set(kArgNameKey, arg.name)
-                         .Set(kArgValueKey, arg.value)
-                         .Build());
-    }
-    return result;
-  }
-
-  bool InitArgListFromCachedValue(const base::DictionaryValue& cache_value,
-                                  const std::string& list_key,
-                                  std::vector<Switch>* arg_list_out) {
-    arg_list_out->clear();
-    const base::ListValue* arg_list_value;
-    if (!cache_value.GetList(list_key, &arg_list_value))
-      return false;
-    for (size_t i = 0; i < arg_list_value->GetSize(); ++i) {
-      const base::DictionaryValue* arg_value;
-      if (!arg_list_value->GetDictionary(i, &arg_value))
-        return false;
-      Switch arg;
-      if (!arg_value->GetStringASCII(kArgNameKey, &arg.name) ||
-          !arg_value->GetStringASCII(kArgValueKey, &arg.value)) {
-        return false;
-      }
-      arg_list_out->push_back(arg);
-    }
-    return true;
-  }
-
-  std::vector<Switch> login_args_;
-  std::vector<Switch> extra_args_;
-
-  base::FilePath backing_file_;
-
-  DISALLOW_COPY_AND_ASSIGN(PersistentSessionManagerClient);
-};
-
 // Used to listen for app termination notification.
 class TerminationObserver : public content::NotificationObserver {
  public:
@@ -284,15 +124,13 @@
 
 }  // namespace
 
-class AutoLaunchedKioskTest : public extensions::ExtensionApiTest {
+class AutoLaunchedKioskTest : public MixinBasedInProcessBrowserTest {
  public:
   AutoLaunchedKioskTest()
       : install_attributes_(
             chromeos::StubInstallAttributes::CreateCloudManaged("domain.com",
                                                                 "device_id")),
-        fake_cws_(new FakeCWS) {
-    set_chromeos_user_ = false;
-  }
+        verifier_format_override_(crx_file::VerifierFormat::CRX3) {}
 
   ~AutoLaunchedKioskTest() override = default;
 
@@ -302,22 +140,23 @@
   }
 
   void SetUp() override {
-    // Will be destroyed in ChromeBrowserMain.
-    fake_session_manager_ = new PersistentSessionManagerClient();
-
-    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
     AppLaunchController::SkipSplashWaitForTesting();
-
-    extensions::ExtensionApiTest::SetUp();
+    login_manager_.set_session_restore_enabled();
+    login_manager_.SetDefaultLoginSwitches(
+        {std::make_pair("test_switch_1", ""),
+         std::make_pair("test_switch_2", "test_switch_2_value")});
+    MixinBasedInProcessBrowserTest::SetUp();
   }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
-    fake_cws_->Init(embedded_test_server());
-    fake_cws_->SetUpdateCrx(GetTestAppId(), GetTestAppId() + ".crx", "1.0.0");
+    fake_cws_.Init(embedded_test_server());
+    fake_cws_.SetUpdateCrx(GetTestAppId(), GetTestAppId() + ".crx", "1.0.0");
+
     std::vector<std::string> secondary_apps = GetTestSecondaryAppIds();
     for (const auto& secondary_app : secondary_apps)
-      fake_cws_->SetUpdateCrx(secondary_app, secondary_app + ".crx", "1.0.0");
-    extensions::ExtensionApiTest::SetUpCommandLine(command_line);
+      fake_cws_.SetUpdateCrx(secondary_app, secondary_app + ".crx", "1.0.0");
+
+    MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
   }
 
   bool SetUpUserDataDirectory() override {
@@ -332,28 +171,25 @@
     if (!CacheDevicePolicyToLocalState(user_data_path))
       return false;
 
-    // Restore session_manager state and ensure session manager flags are
-    // applied.
-    fake_session_manager_->Initialize(
-        user_data_path.Append(kSessionManagerStateCache));
-    fake_session_manager_->AppendSwitchesToCommandLine(
-        base::CommandLine::ForCurrentProcess());
-
-    return true;
+    return MixinBasedInProcessBrowserTest::SetUpUserDataDirectory();
   }
 
   void SetUpInProcessBrowserTestFixture() override {
     host_resolver()->AddRule("*", "127.0.0.1");
 
-    fake_session_manager_->set_device_policy(
+    SessionManagerClient::InitializeFakeInMemory();
+
+    FakeSessionManagerClient::Get()->set_supports_restart_to_apply_user_flags(
+        true);
+    FakeSessionManagerClient::Get()->set_device_policy(
         device_policy_helper_.device_policy()->GetBlob());
-    fake_session_manager_->set_device_local_account_policy(
+    FakeSessionManagerClient::Get()->set_device_local_account_policy(
         kTestAccountId, device_local_account_policy_.GetBlob());
 
     // Arbitrary non-empty state keys.
-    fake_session_manager_->set_server_backed_state_keys({"1"});
+    FakeSessionManagerClient::Get()->set_server_backed_state_keys({"1"});
 
-    extensions::ExtensionApiTest::SetUpInProcessBrowserTestFixture();
+    MixinBasedInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
   }
 
   void PreRunTestOnMainThread() override {
@@ -370,17 +206,14 @@
 
   void SetUpOnMainThread() override {
     extensions::browsertest_util::CreateAndInitializeLocalCache();
-
-    embedded_test_server()->StartAcceptingConnections();
-
-    extensions::ExtensionApiTest::SetUpOnMainThread();
+    MixinBasedInProcessBrowserTest::SetUpOnMainThread();
   }
 
   void TearDownOnMainThread() override {
     app_window_loaded_listener_.reset();
     termination_observer_.reset();
 
-    extensions::ExtensionApiTest::TearDownOnMainThread();
+    MixinBasedInProcessBrowserTest::TearDownOnMainThread();
   }
 
   void InitDevicePolicy() {
@@ -478,13 +311,11 @@
 
   void ExpectCommandLineHasDefaultPolicySwitches(
       const base::CommandLine& cmd_line) {
-    for (size_t i = 0u; i < base::size(kDefaultPolicySwitches); ++i) {
-      EXPECT_TRUE(cmd_line.HasSwitch(kDefaultPolicySwitches[i].name))
-          << "Missing flag " << kDefaultPolicySwitches[i].name;
-      EXPECT_EQ(kDefaultPolicySwitches[i].value,
-                cmd_line.GetSwitchValueASCII(kDefaultPolicySwitches[i].name))
-          << "Invalid value for switch " << kDefaultPolicySwitches[i].name;
-    }
+    EXPECT_TRUE(cmd_line.HasSwitch("test_switch_1"));
+    EXPECT_EQ("", cmd_line.GetSwitchValueASCII("test_switch_1"));
+    EXPECT_TRUE(cmd_line.HasSwitch("test_switch_2"));
+    EXPECT_EQ("test_switch_2_value",
+              cmd_line.GetSwitchValueASCII("test_switch_2"));
   }
 
  protected:
@@ -495,9 +326,13 @@
   chromeos::ScopedStubInstallAttributes install_attributes_;
   policy::UserPolicyBuilder device_local_account_policy_;
   policy::DevicePolicyCrosTestHelper device_policy_helper_;
-  // Owned by SessionManagerClient global instance.
-  PersistentSessionManagerClient* fake_session_manager_;
-  std::unique_ptr<FakeCWS> fake_cws_;
+  FakeCWS fake_cws_;
+  extensions::SandboxedUnpacker::ScopedVerifierFormatOverrideForTest
+      verifier_format_override_;
+
+  EmbeddedTestServerSetupMixin embedded_test_server_setup_{
+      &mixin_host_, embedded_test_server()};
+  LoginManagerMixin login_manager_{&mixin_host_, {}};
 
   DISALLOW_COPY_AND_ASSIGN(AutoLaunchedKioskTest);
 };
diff --git a/chrome/browser/chromeos/login/crash_restore_browsertest.cc b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
index 14fc1c5..e5199c8 100644
--- a/chrome/browser/chromeos/login/crash_restore_browsertest.cc
+++ b/chrome/browser/chromeos/login/crash_restore_browsertest.cc
@@ -266,27 +266,10 @@
 // Tests crash restore flow for child user.
 class CrashRestoreChildUserTest : public MixinBasedInProcessBrowserTest {
  protected:
-  CrashRestoreChildUserTest() {
-    if (!content::IsPreTest())
-      login_manager_.set_skip_flags_setup(true);
-  }
+  CrashRestoreChildUserTest() { login_manager_.set_session_restore_enabled(); }
   ~CrashRestoreChildUserTest() override = default;
 
   // MixinBasedInProcessBrowserTest:
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    if (!content::IsPreTest()) {
-      const cryptohome::AccountIdentifier cryptohome_id =
-          cryptohome::CreateAccountIdentifierFromAccountId(
-              test_user_.account_id);
-      command_line->AppendSwitchASCII(switches::kLoginUser,
-                                      cryptohome_id.account_id());
-      command_line->AppendSwitchASCII(
-          switches::kLoginProfile,
-          CryptohomeClient::GetStubSanitizedUsername(cryptohome_id));
-    }
-    MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line);
-  }
-
   void SetUpInProcessBrowserTestFixture() override {
     // SessionManagerClient has to be in-memory to support setting sessionless
     // user policy blob.
diff --git a/chrome/browser/chromeos/login/encryption_migration_browsertest.cc b/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
index 09e258c..7826284 100644
--- a/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
+++ b/chrome/browser/chromeos/login/encryption_migration_browsertest.cc
@@ -78,8 +78,7 @@
     // Initialize OOBE UI, and configure encryption migration screen handler for
     // test.
     ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW);
-    auto* handler = static_cast<EncryptionMigrationScreenHandler*>(
-        GetOobeUI()->GetEncryptionMigrationScreenView());
+    auto* handler = GetOobeUI()->GetHandler<EncryptionMigrationScreenHandler>();
     handler->SetFreeDiskSpaceFetcherForTesting(base::BindRepeating(
         &EncryptionMigrationTest::GetFreeSpace, base::Unretained(this)));
     handler->SetTickClockForTesting(&tick_clock_);
diff --git a/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
index a7c6f1a..45e89ba 100644
--- a/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/app_downloading_screen_browsertest.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -45,7 +46,7 @@
     ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW);
 
     app_downloading_screen_ = std::make_unique<AppDownloadingScreen>(
-        GetOobeUI()->GetAppDownloadingScreenView(),
+        GetOobeUI()->GetView<AppDownloadingScreenHandler>(),
         base::BindRepeating(&AppDownloadingScreenTest::HandleScreenExit,
                             base::Unretained(this)));
 
diff --git a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
index 19fc10af..785853ec 100644
--- a/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc
@@ -25,6 +25,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/assistant/assistant_pref_util.h"
+#include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chrome/common/chrome_paths.h"
 #include "chromeos/constants/chromeos_switches.h"
@@ -367,7 +368,7 @@
         ->DeleteScreenForTesting(OobeScreen::SCREEN_ASSISTANT_OPTIN_FLOW);
     auto assistant_optin_flow_screen =
         std::make_unique<AssistantOptInFlowScreen>(
-            GetOobeUI()->GetAssistantOptInFlowScreenView(),
+            GetOobeUI()->GetView<AssistantOptInFlowScreenHandler>(),
             base::BindRepeating(&AssistantOptInFlowTest::HandleScreenExit,
                                 base::Unretained(this)));
     assistant_optin_flow_screen_ = assistant_optin_flow_screen.get();
diff --git a/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc b/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
index c40c48f..dc87a95 100644
--- a/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/fingerprint_setup_browsertest.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
+#include "chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
 #include "chromeos/dbus/biod/fake_biod_client.h"
 
@@ -36,7 +37,7 @@
     ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW);
 
     fingerprint_setup_screen_ = std::make_unique<FingerprintSetupScreen>(
-        GetOobeUI()->GetFingerprintSetupScreenView(),
+        GetOobeUI()->GetView<FingerprintSetupScreenHandler>(),
         base::BindRepeating(&FingerprintSetupTest::OnFingerprintSetupScreenExit,
                             base::Unretained(this)));
 
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
index a36945f8..62a7de5 100644
--- a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h"
 #include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/test/browser_test_utils.h"
@@ -120,7 +121,7 @@
         ->screen_manager()
         ->DeleteScreenForTesting(OobeScreen::SCREEN_RECOMMEND_APPS);
     auto recommend_apps_screen = std::make_unique<RecommendAppsScreen>(
-        GetOobeUI()->GetRecommendAppsScreenView(),
+        GetOobeUI()->GetView<RecommendAppsScreenHandler>(),
         base::BindRepeating(&RecommendAppsScreenTest::HandleScreenExit,
                             base::Unretained(this)));
     recommend_apps_screen_ = recommend_apps_screen.get();
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
index b86d0d9cc..2daf4d5e 100644
--- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
+++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -24,6 +24,7 @@
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -91,7 +92,8 @@
     error_screen_ = GetOobeUI()->GetErrorScreen();
     error_delegate_ = std::make_unique<TestErrorScreenDelegate>();
     update_screen_ = std::make_unique<UpdateScreen>(
-        error_delegate_.get(), GetOobeUI()->GetUpdateView(), error_screen_,
+        error_delegate_.get(), GetOobeUI()->GetView<UpdateScreenHandler>(),
+        error_screen_,
         base::BindRepeating(&UpdateScreenTest::HandleScreenExit,
                             base::Unretained(this)));
     update_screen_->set_tick_clock_for_testing(&tick_clock_);
@@ -174,7 +176,7 @@
   ASSERT_NE(GetOobeUI()->current_screen(), OobeScreen::SCREEN_OOBE_UPDATE);
 
   // Show another screen, and verify the Update screen in not shown before it.
-  GetOobeUI()->GetNetworkScreenView()->Show();
+  GetOobeUI()->GetView<NetworkScreenHandler>()->Show();
   OobeScreenWaiter network_screen_waiter(OobeScreen::SCREEN_OOBE_NETWORK);
   network_screen_waiter.set_assert_next_screen();
   network_screen_waiter.Wait();
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index 03bac8d..3b352c4 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -63,7 +63,6 @@
 bool ShouldAutoLaunchKioskApp(const base::CommandLine& command_line) {
   KioskAppManager* app_manager = KioskAppManager::Get();
   return command_line.HasSwitch(switches::kLoginManager) &&
-         !command_line.HasSwitch(switches::kForceLoginManagerInTests) &&
          app_manager->IsAutoLaunchEnabled() &&
          KioskAppLaunchError::Get() == KioskAppLaunchError::NONE &&
          // IsOobeCompleted() is needed to prevent kiosk session start in case
diff --git a/chrome/browser/chromeos/login/test/login_manager_mixin.cc b/chrome/browser/chromeos/login/test/login_manager_mixin.cc
index 0ca84c5..d47fdc8 100644
--- a/chrome/browser/chromeos/login/test/login_manager_mixin.cc
+++ b/chrome/browser/chromeos/login/test/login_manager_mixin.cc
@@ -136,12 +136,17 @@
 
 LoginManagerMixin::~LoginManagerMixin() = default;
 
-void LoginManagerMixin::SetUpCommandLine(base::CommandLine* command_line) {
-  if (skip_flags_setup_)
-    return;
+void LoginManagerMixin::SetDefaultLoginSwitches(
+    const std::vector<test::SessionFlagsManager::Switch>& switches) {
+  session_flags_manager_.SetDefaultLoginSwitches(switches);
+}
 
-  command_line->AppendSwitch(chromeos::switches::kLoginManager);
-  command_line->AppendSwitch(chromeos::switches::kForceLoginManagerInTests);
+bool LoginManagerMixin::SetUpUserDataDirectory() {
+  if (session_restore_enabled_)
+    session_flags_manager_.SetUpSessionRestore();
+  session_flags_manager_.AppendSwitchesToCommandLine(
+      base::CommandLine::ForCurrentProcess());
+  return true;
 }
 
 void LoginManagerMixin::CreatedBrowserMainParts(
@@ -158,6 +163,10 @@
   session_manager_test_api.SetShouldObtainTokenHandleInTests(false);
 }
 
+void LoginManagerMixin::TearDownOnMainThread() {
+  session_flags_manager_.Finalize();
+}
+
 void LoginManagerMixin::AttemptLoginUsingAuthenticator(
     const UserContext& user_context,
     std::unique_ptr<StubAuthenticatorBuilder> authenticator_builder) {
diff --git a/chrome/browser/chromeos/login/test/login_manager_mixin.h b/chrome/browser/chromeos/login/test/login_manager_mixin.h
index 536f2a7..3d079fb 100644
--- a/chrome/browser/chromeos/login/test/login_manager_mixin.h
+++ b/chrome/browser/chromeos/login/test/login_manager_mixin.h
@@ -10,6 +10,7 @@
 
 #include "base/macros.h"
 #include "chrome/browser/chromeos/login/mixin_based_in_process_browser_test.h"
+#include "chrome/browser/chromeos/login/test/session_flags_manager.h"
 #include "components/account_id/account_id.h"
 #include "components/user_manager/user_type.h"
 
@@ -48,11 +49,22 @@
 
   ~LoginManagerMixin() override;
 
+  // Enables session restore between multi-step test run (not very useful unless
+  // the browser test has PRE part).
+  // Should be called before mixin SetUp() is called to take effect.
+  void set_session_restore_enabled() { session_restore_enabled_ = true; }
+
+  // Sets the list of default policy switches to be added to command line on the
+  // login screen.
+  void SetDefaultLoginSwitches(
+      const std::vector<test::SessionFlagsManager::Switch>& swiches);
+
   // InProcessBrowserTestMixin:
-  void SetUpCommandLine(base::CommandLine* command_line) override;
+  bool SetUpUserDataDirectory() override;
   void CreatedBrowserMainParts(
       content::BrowserMainParts* browser_main_parts) override;
   void SetUpOnMainThread() override;
+  void TearDownOnMainThread() override;
 
   // Starts login attempt for a user, using the stub authenticator provided by
   // |authenticator_builder|.
@@ -75,15 +87,15 @@
   // Returns whether the newly logged in user is active when the method exits.
   bool LoginAndWaitForActiveSession(const UserContext& user_context);
 
-  // Allows to skip setup of command line switches. It can be used to test
-  // session restart after test, or restart to apply per-session flags, where
-  // the session should start with a user logged in.
-  void set_skip_flags_setup(bool value) { skip_flags_setup_ = value; }
-
  private:
-  bool skip_flags_setup_ = false;
   const std::vector<TestUserInfo> initial_users_;
 
+  // If set, session_flags_manager_ will be set up with session restore logic
+  // enabled (it will restore session state between test runs for multi-step
+  // browser tests).
+  bool session_restore_enabled_ = false;
+  test::SessionFlagsManager session_flags_manager_;
+
   DISALLOW_COPY_AND_ASSIGN(LoginManagerMixin);
 };
 
diff --git a/chrome/browser/chromeos/login/test/session_flags_manager.cc b/chrome/browser/chromeos/login/test/session_flags_manager.cc
new file mode 100644
index 0000000..fc801c0e
--- /dev/null
+++ b/chrome/browser/chromeos/login/test/session_flags_manager.cc
@@ -0,0 +1,181 @@
+// 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 "chrome/browser/chromeos/login/test/session_flags_manager.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/values.h"
+#include "chrome/common/chrome_paths.h"
+#include "chromeos/constants/chromeos_switches.h"
+#include "chromeos/cryptohome/cryptohome_parameters.h"
+#include "chromeos/dbus/session_manager/fake_session_manager_client.h"
+#include "third_party/cros_system_api/switches/chrome_switches.h"
+
+namespace chromeos {
+namespace test {
+
+namespace {
+
+// Keys for values in dictionary used to preserve session manager state.
+constexpr char kUserIdKey[] = "active_user_id";
+constexpr char kUserHashKey[] = "active_user_hash";
+constexpr char kUserFlagsKey[] = "user_flags";
+constexpr char kFlagNameKey[] = "name";
+constexpr char kFlagValueKey[] = "value";
+
+constexpr char kCachedSessionStateFile[] = "test_session_manager_state.json";
+
+}  // namespace
+
+SessionFlagsManager::SessionFlagsManager() = default;
+
+SessionFlagsManager::~SessionFlagsManager() {
+  Finalize();
+}
+
+void SessionFlagsManager::SetUpSessionRestore() {
+  DCHECK_EQ(mode_, Mode::LOGIN_SCREEN);
+  mode_ = Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE;
+
+  base::FilePath user_data_path;
+  CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path))
+      << "Unable to get used data dir";
+
+  backing_file_ = user_data_path.AppendASCII(kCachedSessionStateFile);
+  LoadStateFromBackingFile();
+}
+
+void SessionFlagsManager::SetDefaultLoginSwitches(
+    const std::vector<Switch>& switches) {
+  default_switches_ = {{switches::kPolicySwitchesBegin, ""}};
+  default_switches_.insert(default_switches_.end(), switches.begin(),
+                           switches.end());
+  default_switches_.emplace_back(
+      std::make_pair(switches::kPolicySwitchesEnd, ""));
+}
+
+void SessionFlagsManager::AppendSwitchesToCommandLine(
+    base::CommandLine* command_line) {
+  if (mode_ == Mode::LOGIN_SCREEN || user_id_.empty()) {
+    command_line->AppendSwitch(switches::kLoginManager);
+    command_line->AppendSwitch(switches::kForceLoginManagerInTests);
+  } else {
+    DCHECK_EQ(mode_, Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE);
+    command_line->AppendSwitchASCII(switches::kLoginUser, user_id_);
+    command_line->AppendSwitchASCII(switches::kLoginProfile, user_hash_);
+  }
+
+  // Session manager uses extra args to pass both default, login policy
+  // switches and user flag switches. If extra args are not explicitly set for
+  // current user before resarting chrome (which is represented by user_flags_
+  // not being set here), session manager will keep using extra args set by
+  // default login switches - simulate  this behavior.
+  const std::vector<Switch>& active_switches =
+      user_flags_.has_value() ? *user_flags_ : default_switches_;
+  for (const auto& item : active_switches) {
+    command_line->AppendSwitchASCII(item.first, item.second);
+  }
+}
+
+void SessionFlagsManager::Finalize() {
+  if (finalized_ || mode_ != Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE)
+    return;
+
+  finalized_ = true;
+  StoreStateToBackingFile();
+}
+
+void SessionFlagsManager::LoadStateFromBackingFile() {
+  DCHECK_EQ(mode_, Mode::LOGIN_SCREEN_WITH_SESSION_RESTORE);
+
+  JSONFileValueDeserializer deserializer(backing_file_);
+
+  int error_code = 0;
+  std::unique_ptr<base::Value> value =
+      deserializer.Deserialize(&error_code, nullptr);
+  if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR)
+    return;
+
+  DCHECK(value->is_dict());
+  const std::string* user_id = value->FindStringKey(kUserIdKey);
+  if (!user_id || user_id->empty())
+    return;
+
+  user_id_ = *user_id;
+  user_hash_ = *value->FindStringKey(kUserHashKey);
+
+  base::Value* user_flags = value->FindListKey(kUserFlagsKey);
+  if (!user_flags)
+    return;
+
+  user_flags_ = std::vector<Switch>();
+  for (const base::Value& flag : user_flags->GetList()) {
+    DCHECK(flag.is_dict());
+    user_flags_->emplace_back(std::make_pair(
+        *flag.FindStringKey(kFlagNameKey), *flag.FindStringKey(kFlagValueKey)));
+  }
+}
+
+void SessionFlagsManager::StoreStateToBackingFile() {
+  const SessionManagerClient::ActiveSessionsMap& sessions =
+      FakeSessionManagerClient::Get()->user_sessions();
+  const bool session_active =
+      !sessions.empty() && !FakeSessionManagerClient::Get()->session_stopped();
+
+  // If a user session is not active, clear the backing file so default flags
+  // are used next time.
+  if (!session_active) {
+    base::DeleteFile(backing_file_, false /*recursive*/);
+    return;
+  }
+
+  // Currently, only support single user sessions.
+  DCHECK_EQ(1u, sessions.size());
+  const auto& session = sessions.begin();
+
+  base::Value cached_state(base::Value::Type::DICTIONARY);
+  cached_state.SetKey(kUserIdKey, base::Value(session->first));
+  cached_state.SetKey(kUserHashKey, base::Value(session->second));
+
+  std::vector<Switch> user_flag_args;
+  std::vector<std::string> raw_flags;
+  const bool has_user_flags = FakeSessionManagerClient::Get()->GetFlagsForUser(
+      cryptohome::CreateAccountIdentifierFromIdentification(
+          cryptohome::Identification::FromString(session->first)),
+      &raw_flags);
+  if (has_user_flags) {
+    std::vector<std::string> argv = {"" /* Empty program */};
+    argv.insert(argv.end(), raw_flags.begin(), raw_flags.end());
+
+    // Parse flag name-value pairs using command line initialization.
+    base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
+    cmd_line.InitFromArgv(argv);
+
+    base::Value flag_list(base::Value::Type::LIST);
+    for (const auto& flag : cmd_line.GetSwitches()) {
+      base::Value flag_value(base::Value::Type::DICTIONARY);
+      flag_value.SetKey(kFlagNameKey, base::Value(flag.first));
+      flag_value.SetKey(kFlagValueKey, base::Value(flag.second));
+
+      flag_list.GetList().emplace_back(std::move(flag_value));
+    }
+    cached_state.SetKey(kUserFlagsKey, std::move(flag_list));
+  }
+
+  JSONFileValueSerializer serializer(backing_file_);
+  serializer.Serialize(cached_state);
+}
+
+}  // namespace test
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/test/session_flags_manager.h b/chrome/browser/chromeos/login/test/session_flags_manager.h
new file mode 100644
index 0000000..ef316660
--- /dev/null
+++ b/chrome/browser/chromeos/login/test/session_flags_manager.h
@@ -0,0 +1,109 @@
+// 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 CHROME_BROWSER_CHROMEOS_LOGIN_TEST_SESSION_FLAGS_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_TEST_SESSION_FLAGS_MANAGER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace chromeos {
+namespace test {
+
+// Test helper that sets up command line for login tests. By default, it
+// initializes the command line so tests start on the login manager.
+// It supports session restore mode, which can be used during multi step browser
+// tests (i.e. tests that have PRE_ test) to keep session state across test
+// runs. If a user session was active in the previous run, this will set up
+// command line to restore session for that user, which can be useful for
+// testing chrome restart to apply per-session flags, or session restore on
+// crash.
+class SessionFlagsManager {
+ public:
+  // Pair of switch name and value. The value can be empty.
+  using Switch = std::pair<std::string, std::string>;
+
+  SessionFlagsManager();
+  ~SessionFlagsManager();
+
+  // Sets the manager up for session restore.It should be called early in
+  // test setup, before calling AppendSwitchesToCommandLine().
+  //
+  // When session restore is enabled, SessionStateManager will load session
+  // state from a file in the test user data directory, and use it to initialize
+  // the test command line. The file will contain session information saved
+  // during the previous (PRE_) browser test step. The information includes:
+  // *   the active user information
+  // *   the active user's per-session flags.
+  //
+  // If the backing file is not found, or empty, command line will be
+  // set up with login manager flags so test starts on the login screen.
+  void SetUpSessionRestore();
+
+  // Sets the default login policy switches, that will be added to command line
+  // when initializing it for login screen.
+  // This should be called before chrome startup starts - i.e. before
+  // SetUpInProcessBrowserTestFixture().
+  void SetDefaultLoginSwitches(const std::vector<Switch>& switches);
+
+  // Sets up the test command line. If session restore is enabled, and
+  // persisted session state is found, the command line is set up according to
+  // that state. Otherwise, it's set up to force login screen.
+  //
+  // NOTE: If SetUpSessionRestore() was called, calling this requires the
+  // user data dir to be set up for test.
+  void AppendSwitchesToCommandLine(base::CommandLine* command_line);
+
+  // Finalizes this instance - if session restore is enabled, it will save
+  // current session manager information to a backing file in the user data
+  // directory.
+  void Finalize();
+
+ private:
+  enum class Mode {
+    // Sets up command line to start on login screen.
+    LOGIN_SCREEN,
+    // If saved user session state exists, sets up command line to continue the
+    // user session, otherwise sets up command line for login screen.
+    LOGIN_SCREEN_WITH_SESSION_RESTORE
+  };
+
+  void LoadStateFromBackingFile();
+  void StoreStateToBackingFile();
+
+  // The mode this manager is running in.
+  Mode mode_ = Mode::LOGIN_SCREEN;
+
+  // Whether Finalize has been called.
+  bool finalized_ = false;
+
+  // List of default switches that should be added to command line when setting
+  // up command line for login screen.
+  std::vector<Switch> default_switches_;
+
+  // If command line should be set up for a user session (e.g. when running in
+  // session restore mode), the logged in user information.
+  std::string user_id_;
+  std::string user_hash_;
+  base::Optional<std::vector<Switch>> user_flags_;
+
+  // If |session_restore_enabled_| is set, the path to the file where session
+  // state is saved.
+  base::FilePath backing_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionFlagsManager);
+};
+
+}  // namespace test
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LOGIN_TEST_SESSION_FLAGS_MANAGER_H_
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 55995f46..33498ff 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -89,10 +89,36 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/login_screen_client.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
+#include "chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/network_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
+#include "chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h"
 #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h"
+#include "chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h"
 #include "chrome/browser/ui/webui/help/help_utils_chromeos.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_features.h"
@@ -397,111 +423,112 @@
 
   if (oobe_ui->display_type() == OobeUI::kOobeDisplay) {
     append(std::make_unique<WelcomeScreen>(
-        oobe_ui->GetWelcomeView(),
+        oobe_ui->GetView<WelcomeScreenHandler>(),
         base::BindRepeating(&WizardController::OnWelcomeScreenExit,
                             weak_factory_.GetWeakPtr())));
   }
 
   append(std::make_unique<NetworkScreen>(
-      oobe_ui->GetNetworkScreenView(),
+      oobe_ui->GetView<NetworkScreenHandler>(),
       base::BindRepeating(&WizardController::OnNetworkScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<UpdateScreen>(
-      this, oobe_ui->GetUpdateView(), oobe_ui->GetErrorScreen(),
+      this, oobe_ui->GetView<UpdateScreenHandler>(), oobe_ui->GetErrorScreen(),
       base::BindRepeating(&WizardController::OnUpdateScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<EulaScreen>(
-      oobe_ui->GetEulaView(),
+      oobe_ui->GetView<EulaScreenHandler>(),
       base::BindRepeating(&WizardController::OnEulaScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<EnrollmentScreen>(
-      oobe_ui->GetEnrollmentScreenView(),
+      oobe_ui->GetView<EnrollmentScreenHandler>(),
       base::BindRepeating(&WizardController::OnEnrollmentScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<chromeos::ResetScreen>(
-      oobe_ui->GetResetView(), oobe_ui->GetErrorScreen(),
+      oobe_ui->GetView<ResetScreenHandler>(), oobe_ui->GetErrorScreen(),
       base::BindRepeating(&WizardController::OnResetScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<chromeos::DemoSetupScreen>(
-      oobe_ui->GetDemoSetupScreenView(),
+      oobe_ui->GetView<DemoSetupScreenHandler>(),
       base::BindRepeating(&WizardController::OnDemoSetupScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<chromeos::DemoPreferencesScreen>(
-      oobe_ui->GetDemoPreferencesScreenView(),
+      oobe_ui->GetView<DemoPreferencesScreenHandler>(),
       base::BindRepeating(&WizardController::OnDemoPreferencesScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<EnableDebuggingScreen>(
-      oobe_ui->GetEnableDebuggingScreenView(),
+      oobe_ui->GetView<EnableDebuggingScreenHandler>(),
       base::BindRepeating(&WizardController::OnEnableDebuggingScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<KioskEnableScreen>(
-      oobe_ui->GetKioskEnableScreenView(),
+      oobe_ui->GetView<KioskEnableScreenHandler>(),
       base::BindRepeating(&WizardController::OnKioskEnableScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<KioskAutolaunchScreen>(
-      oobe_ui->GetKioskAutolaunchScreenView(),
+      oobe_ui->GetView<KioskAutolaunchScreenHandler>(),
       base::BindRepeating(&WizardController::OnKioskAutolaunchScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<TermsOfServiceScreen>(
-      oobe_ui->GetTermsOfServiceScreenView(),
+      oobe_ui->GetView<TermsOfServiceScreenHandler>(),
       base::BindRepeating(&WizardController::OnTermsOfServiceScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<SyncConsentScreen>(
-      oobe_ui->GetSyncConsentScreenView(),
+      oobe_ui->GetView<SyncConsentScreenHandler>(),
       base::BindRepeating(&WizardController::OnSyncConsentScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<ArcTermsOfServiceScreen>(
-      oobe_ui->GetArcTermsOfServiceScreenView(),
+      oobe_ui->GetView<ArcTermsOfServiceScreenHandler>(),
       base::BindRepeating(&WizardController::OnArcTermsOfServiceScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<RecommendAppsScreen>(
-      oobe_ui->GetRecommendAppsScreenView(),
+      oobe_ui->GetView<RecommendAppsScreenHandler>(),
       base::BindRepeating(&WizardController::OnRecommendAppsScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<AppDownloadingScreen>(
-      oobe_ui->GetAppDownloadingScreenView(),
+      oobe_ui->GetView<AppDownloadingScreenHandler>(),
       base::BindRepeating(&WizardController::OnAppDownloadingScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<WrongHWIDScreen>(
-      oobe_ui->GetWrongHWIDScreenView(),
+      oobe_ui->GetView<WrongHWIDScreenHandler>(),
       base::BindRepeating(&WizardController::OnWrongHWIDScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<chromeos::HIDDetectionScreen>(
-      oobe_ui->GetHIDDetectionView(),
+      oobe_ui->GetView<HIDDetectionScreenHandler>(),
       base::BindRepeating(&WizardController::OnHidDetectionScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<AutoEnrollmentCheckScreen>(
-      oobe_ui->GetAutoEnrollmentCheckScreenView(), oobe_ui->GetErrorScreen(),
+      oobe_ui->GetView<AutoEnrollmentCheckScreenHandler>(),
+      oobe_ui->GetErrorScreen(),
       base::BindRepeating(&WizardController::OnAutoEnrollmentCheckScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<DeviceDisabledScreen>(
-      oobe_ui->GetDeviceDisabledScreenView()));
+      oobe_ui->GetView<DeviceDisabledScreenHandler>()));
   append(std::make_unique<EncryptionMigrationScreen>(
-      oobe_ui->GetEncryptionMigrationScreenView()));
+      oobe_ui->GetView<EncryptionMigrationScreenHandler>()));
   append(std::make_unique<SupervisionTransitionScreen>(
-      oobe_ui->GetSupervisionTransitionScreenView(),
+      oobe_ui->GetView<SupervisionTransitionScreenHandler>(),
       base::BindRepeating(&WizardController::OnSupervisionTransitionScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<UpdateRequiredScreen>(
-      oobe_ui->GetUpdateRequiredScreenView()));
+      oobe_ui->GetView<UpdateRequiredScreenHandler>()));
   append(std::make_unique<AssistantOptInFlowScreen>(
-      oobe_ui->GetAssistantOptInFlowScreenView(),
+      oobe_ui->GetView<AssistantOptInFlowScreenHandler>(),
       base::BindRepeating(&WizardController::OnAssistantOptInFlowScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<MultiDeviceSetupScreen>(
-      oobe_ui->GetMultiDeviceSetupScreenView(),
+      oobe_ui->GetView<MultiDeviceSetupScreenHandler>(),
       base::BindRepeating(&WizardController::OnMultiDeviceSetupScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<DiscoverScreen>(
-      oobe_ui->GetDiscoverScreenView(),
+      oobe_ui->GetView<DiscoverScreenHandler>(),
       base::BindRepeating(&WizardController::OnDiscoverScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<FingerprintSetupScreen>(
-      oobe_ui->GetFingerprintSetupScreenView(),
+      oobe_ui->GetView<FingerprintSetupScreenHandler>(),
       base::BindRepeating(&WizardController::OnFingerprintSetupScreenExit,
                           weak_factory_.GetWeakPtr())));
   append(std::make_unique<MarketingOptInScreen>(
-      oobe_ui->GetMarketingOptInScreenView(),
+      oobe_ui->GetView<MarketingOptInScreenHandler>(),
       base::BindRepeating(&WizardController::OnMarketingOptInScreenExit,
                           weak_factory_.GetWeakPtr())));
 
@@ -1437,7 +1464,9 @@
         base::Callback<void(bool)> on_check =
             base::Bind(&WizardController::OnHIDScreenNecessityCheck,
                        weak_factory_.GetWeakPtr());
-        GetOobeUI()->GetHIDDetectionView()->CheckIsScreenRequired(on_check);
+        GetOobeUI()
+            ->GetView<HIDDetectionScreenHandler>()
+            ->CheckIsScreenRequired(on_check);
       } else {
         ShowWelcomeScreen();
       }
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 52b57cd..991bc79c 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -584,7 +584,7 @@
     // Set up the mocks for all screens.
     mock_welcome_screen_ =
         MockScreenExpectLifecycle(std::make_unique<MockWelcomeScreen>(
-            GetOobeUI()->GetWelcomeView(),
+            GetOobeUI()->GetView<WelcomeScreenHandler>(),
             base::BindRepeating(&WizardController::OnWelcomeScreenExit,
                                 base::Unretained(wizard_controller))));
 
diff --git a/chrome/browser/component_updater/cros_component_installer_chromeos.cc b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
index e4daa94..0265663 100644
--- a/chrome/browser/component_updater/cros_component_installer_chromeos.cc
+++ b/chrome/browser/component_updater/cros_component_installer_chromeos.cc
@@ -37,9 +37,9 @@
      "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"},
     {"cros-termina", "760.1",
      "e9d960f84f628e1f42d05de4046bb5b3154b6f1f65c08412c6af57a29aecaffb"},
-    {"rtanalytics-light", "10.0",
+    {"rtanalytics-light", "11.0",
      "69f09d33c439c2ab55bbbe24b47ab55cb3f6c0bd1f1ef46eefea3216ec925038"},
-    {"rtanalytics-full", "10.0",
+    {"rtanalytics-full", "11.0",
      "c93c3e1013c52100a20038b405ac854d69fa889f6dc4fa6f188267051e05e444"},
     {"star-cups-driver", "1.1",
      "6d24de30f671da5aee6d463d9e446cafe9ddac672800a9defe86877dcde6c466"},
diff --git a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
index 0200943..2b6f348 100644
--- a/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
+++ b/chrome/browser/data_reduction_proxy/data_reduction_proxy_browsertest.cc
@@ -37,19 +37,26 @@
 #include "components/prefs/pref_service.h"
 #include "components/proxy_config/proxy_config_dictionary.h"
 #include "components/proxy_config/proxy_config_pref_names.h"
+#include "content/public/browser/browser_context.h"
 #include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
 #include "content/public/common/network_service_util.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "net/base/host_port_pair.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/default_handlers.h"
+#include "net/test/embedded_test_server/embedded_test_server_connection_listener.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/network_switches.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/network_service_test.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -129,6 +136,10 @@
                       false);
 }
 
+ClientConfig CreateEmptyConfig() {
+  return CreateEmptyProxyConfig(kSessionKey, 1000, 0, 0.5f, false);
+}
+
 }  // namespace
 
 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_CHROMEOS)
@@ -177,14 +188,58 @@
     host_resolver()->AddRule(kMockHost, "127.0.0.1");
 
     EnableDataSaver(true);
-    // Make sure initial config has been loaded.
-    WaitForConfig();
+    // Make sure initial config has been loaded. Config is fetched only if
+    // network service is not enabled, or if both network service and
+    // kDataReductionProxyEnabledWithNetworkService are enabled.
+    if (!IsNetworkServiceEnabled() ||
+        base::FeatureList::IsEnabled(
+            data_reduction_proxy::features::
+                kDataReductionProxyEnabledWithNetworkService)) {
+      WaitForConfig();
+    }
   }
 
   bool IsNetworkServiceEnabled() const {
     return base::FeatureList::IsEnabled(network::features::kNetworkService);
   }
 
+  // Verifies that the |request| has the Chrome-Proxy headers, and caches the
+  // URL of |request| in a local container. This can be added to any test that
+  // needs to verify if the proxy server is receiving the correct set of
+  // headers.
+  void MonitorAndVerifyRequestsToProxyServer(
+      const net::test_server::HttpRequest& request) {
+    // All requests to proxy server should have at least these headers.
+    EXPECT_NE(request.headers.end(),
+              request.headers.find(data_reduction_proxy::chrome_proxy_header()))
+        << " url=" << request.GetURL() << " path=" << request.GetURL().path();
+    EXPECT_NE(
+        request.headers.end(),
+        request.headers.find(data_reduction_proxy::chrome_proxy_ect_header()))
+        << " url=" << request.GetURL() << " path=" << request.GetURL().path();
+
+    base::AutoLock lock(lock_);
+    monitored_urls_.push_back(request.GetURL());
+  }
+
+  // Returns true if a request for URL with path |url_path| was observed by
+  // |this|. The method only compares the path instead of the full URL since the
+  // hostname may be different due to the use of mock host in the browsertests
+  // below.
+  bool WasUrlPathMonitored(const std::string& url_path) {
+    base::AutoLock lock(lock_);
+    for (const auto monitored_url : monitored_urls_)
+      if (monitored_url.path() == url_path)
+        return true;
+
+    return false;
+  }
+
+  void ResetMonitoredUrls() {
+    base::AutoLock lock(lock_);
+    monitored_urls_.clear();
+  }
+
  protected:
   void EnableDataSaver(bool enabled) {
     data_reduction_proxy::DataReductionProxySettings::
@@ -238,6 +293,11 @@
   net::EmbeddedTestServer secure_proxy_check_server_;
   net::EmbeddedTestServer config_server_;
   std::unique_ptr<net::test_server::ControllableHttpResponse> favicon_catcher_;
+
+  std::vector<GURL> monitored_urls_;
+
+  // |lock_| guards access to |monitored_urls_|.
+  base::Lock lock_;
 };
 
 class DataReductionProxyBrowsertest : public DataReductionProxyBrowsertestBase {
@@ -260,7 +320,9 @@
   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
   WaitForConfig();
 
-  ui_test_utils::NavigateToURL(browser(), GURL("http://does.not.resolve/foo"));
+  ui_test_utils::NavigateToURL(
+      browser(),
+      GetURLWithMockHost(original_server, "/echoheader?Chrome-Proxy"));
 
   EXPECT_EQ(GetBody(), kPrimaryResponse);
 
@@ -274,11 +336,58 @@
   SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_2G);
   WaitForConfig();
 
-  ui_test_utils::NavigateToURL(browser(), GURL("http://does.not.resolve/foo"));
+  ui_test_utils::NavigateToURL(
+      browser(),
+      GetURLWithMockHost(original_server, "/echoheader?Chrome-Proxy"));
 
   EXPECT_EQ(GetBody(), kSecondaryResponse);
 }
 
+// Verify that when a client config with no proxies is provided to Chrome,
+// then usage of proxy is disabled. Later, when the client config with valid
+// proxies is fetched, then the specified proxies are used.
+IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, EmptyConfig) {
+  net::EmbeddedTestServer origin_server;
+  origin_server.RegisterRequestHandler(
+      base::BindRepeating(&BasicResponse, kDummyBody));
+  ASSERT_TRUE(origin_server.Start());
+
+  // Set config to empty, and verify that the response comes from the
+  // |origin_server|.
+  SetConfig(CreateEmptyConfig());
+  // A network change forces the config to be fetched.
+  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_2G);
+  WaitForConfig();
+  ui_test_utils::NavigateToURL(
+      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
+  ASSERT_EQ(GetBody(), kDummyBody);
+
+  net::EmbeddedTestServer proxy_server;
+  proxy_server.RegisterRequestHandler(
+      base::BindRepeating(&BasicResponse, kPrimaryResponse));
+  ASSERT_TRUE(proxy_server.Start());
+
+  // Set config to |proxy_server|, and verify that the response comes from
+  // |proxy_server|.
+  SetConfig(CreateConfigForServer(proxy_server));
+  // A network change forces the config to be fetched.
+  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
+  WaitForConfig();
+  ui_test_utils::NavigateToURL(
+      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
+  EXPECT_EQ(GetBody(), kPrimaryResponse);
+
+  // Set config to empty again, and verify that the response comes from the
+  // |origin_server|.
+  SetConfig(CreateEmptyConfig());
+  // A network change forces the config to be fetched.
+  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_2G);
+  WaitForConfig();
+  ui_test_utils::NavigateToURL(
+      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
+  ASSERT_EQ(GetBody(), kDummyBody);
+}
+
 IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, ChromeProxyHeaderSet) {
   // Proxy will be used, so it shouldn't matter if the host cannot be resolved.
   ui_test_utils::NavigateToURL(
@@ -497,6 +606,9 @@
 IN_PROC_BROWSER_TEST_P(DataReductionProxyWithHoldbackBrowsertest,
                        UpdateConfig) {
   net::EmbeddedTestServer proxy_server;
+  proxy_server.RegisterRequestMonitor(base::BindRepeating(
+      &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+      base::Unretained(this)));
   proxy_server.RegisterRequestHandler(
       base::BindRepeating(&BasicResponse, kPrimaryResponse));
   ASSERT_TRUE(proxy_server.Start());
@@ -564,10 +676,16 @@
     primary_server_.RegisterRequestHandler(base::BindRepeating(
         &DataReductionProxyFallbackBrowsertest::AddChromeProxyHeader,
         base::Unretained(this)));
+    primary_server_.RegisterRequestMonitor(base::BindRepeating(
+        &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+        base::Unretained(this)));
     ASSERT_TRUE(primary_server_.Start());
 
     secondary_server_.RegisterRequestHandler(
         base::BindRepeating(&BasicResponse, kSecondaryResponse));
+    secondary_server_.RegisterRequestMonitor(base::BindRepeating(
+        &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+        base::Unretained(this)));
     ASSERT_TRUE(secondary_server_.Start());
 
     net::HostPortPair primary_host_port_pair = primary_server_.host_port_pair();
@@ -1068,12 +1186,18 @@
     primary_server_.RegisterRequestHandler(base::BindRepeating(
         &DataReductionProxyWarmupURLBrowsertest::WaitForWarmupRequest,
         base::Unretained(this), primary_server_loop_.get()));
+    primary_server_.RegisterRequestMonitor(base::BindRepeating(
+        &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+        base::Unretained(this)));
     ASSERT_TRUE(primary_server_.Start());
 
     secondary_server_loop_ = std::make_unique<base::RunLoop>();
     secondary_server_.RegisterRequestHandler(base::BindRepeating(
         &DataReductionProxyWarmupURLBrowsertest::WaitForWarmupRequest,
         base::Unretained(this), secondary_server_loop_.get()));
+    secondary_server_.RegisterRequestMonitor(base::BindRepeating(
+        &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+        base::Unretained(this)));
     ASSERT_TRUE(secondary_server_.Start());
 
     net::HostPortPair primary_host_port_pair = primary_server_.host_port_pair();
@@ -1191,6 +1315,7 @@
       EXPECT_THAT(body, HasSubstr(kSessionKey));
     }
   }
+  EXPECT_TRUE(WasUrlPathMonitored("/e2e_probe"));
 }
 
 // First parameter indicate proxy scheme for proxies that are being tested.
@@ -1259,6 +1384,127 @@
   return response;
 }
 
+// Verify that requests initiated by SimpleURLLoader use the proxy only if
+// render frame ID is set.
+IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest, SimpleURLLoader) {
+  if (!IsNetworkServiceEnabled())
+    return;
+
+  net::EmbeddedTestServer origin_server;
+  origin_server.RegisterRequestHandler(
+      base::BindRepeating(&BasicResponse, kDummyBody));
+  ASSERT_TRUE(origin_server.Start());
+
+  net::EmbeddedTestServer proxy_server;
+  proxy_server.RegisterRequestMonitor(base::BindRepeating(
+      &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+      base::Unretained(this)));
+  proxy_server.RegisterRequestHandler(
+      base::BindRepeating(&BasicResponse, kPrimaryResponse));
+  ASSERT_TRUE(proxy_server.Start());
+
+  for (const bool set_render_frame_id : {false, true}) {
+    // Set config to |proxy_server|.
+    SetConfig(CreateConfigForServer(proxy_server));
+    // A network change forces the config to be fetched.
+    SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
+    WaitForConfig();
+
+    auto resource_request = std::make_unique<network::ResourceRequest>();
+    if (set_render_frame_id)
+      resource_request->render_frame_id = MSG_ROUTING_CONTROL;
+    // Change the URL for different test cases because a bypassed URL may be
+    // added to the local cache by network service proxy delegate.
+    if (set_render_frame_id) {
+      resource_request->url = GetURLWithMockHost(
+          origin_server, "/echoheader?Chrome-Proxy&random=1");
+    } else {
+      resource_request->url = GetURLWithMockHost(
+          origin_server, "/echoheader?Chrome-Proxy&random=2");
+    }
+
+    auto simple_loader = network::SimpleURLLoader::Create(
+        std::move(resource_request), TRAFFIC_ANNOTATION_FOR_TESTS);
+
+    auto* storage_partition =
+        content::BrowserContext::GetDefaultStoragePartition(
+            browser()->profile());
+    auto url_loader_factory =
+        storage_partition->GetURLLoaderFactoryForBrowserProcess();
+
+    base::RunLoop loop;
+    simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+        url_loader_factory.get(),
+        base::BindLambdaForTesting(
+            [&](std::unique_ptr<std::string> response_body) {
+              loop.Quit();
+              ASSERT_TRUE(response_body);
+              EXPECT_EQ(set_render_frame_id ? kPrimaryResponse : kDummyBody,
+                        *response_body);
+            }));
+    loop.Run();
+  }
+}
+
+// Ensure that renderer initiated same-site navigations work.
+IN_PROC_BROWSER_TEST_F(DataReductionProxyBrowsertest,
+                       RendererInitiatedSameSiteNavigation) {
+  // Perform a browser-initiated navigation.
+  net::EmbeddedTestServer origin_server;
+  origin_server.ServeFilesFromSourceDirectory(
+      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
+  ASSERT_TRUE(origin_server.Start());
+
+  net::EmbeddedTestServer proxy_server;
+  proxy_server.ServeFilesFromSourceDirectory(
+      base::FilePath(FILE_PATH_LITERAL("content/test/data")));
+  proxy_server.RegisterRequestMonitor(base::BindRepeating(
+      &DataReductionProxyBrowsertest::MonitorAndVerifyRequestsToProxyServer,
+      base::Unretained(this)));
+  ASSERT_TRUE(proxy_server.Start());
+  // Set config to |proxy_server|.
+  SetConfig(CreateConfigForServer(proxy_server));
+  // A network change forces the config to be fetched.
+  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
+  WaitForConfig();
+
+  {
+    content::TestNavigationObserver observer(
+        browser()->tab_strip_model()->GetActiveWebContents());
+    GURL url(GetURLWithMockHost(origin_server, "/simple_links.html"));
+    ui_test_utils::NavigateToURL(browser(), url);
+    EXPECT_EQ(url, observer.last_navigation_url());
+    EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_FALSE(observer.last_initiator_origin().has_value());
+    EXPECT_TRUE(WasUrlPathMonitored(url.path()));
+  }
+
+  ResetMonitoredUrls();
+
+  // Simulate clicking on a same-site link.
+  {
+    content::TestNavigationObserver observer(
+        browser()->tab_strip_model()->GetActiveWebContents());
+    GURL url(GetURLWithMockHost(origin_server, "/title2.html"));
+    bool success = false;
+    EXPECT_TRUE(ExecuteScriptAndExtractBool(
+        browser()->tab_strip_model()->GetActiveWebContents(),
+        "window.domAutomationController.send(clickSameSiteLink());", &success));
+    EXPECT_TRUE(success);
+    EXPECT_TRUE(
+        WaitForLoadStop(browser()->tab_strip_model()->GetActiveWebContents()));
+    EXPECT_EQ(url, observer.last_navigation_url());
+    EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_EQ(browser()
+                  ->tab_strip_model()
+                  ->GetActiveWebContents()
+                  ->GetMainFrame()
+                  ->GetLastCommittedOrigin(),
+              observer.last_initiator_origin());
+    EXPECT_TRUE(WasUrlPathMonitored(url.path()));
+  }
+}
+
 // Tests that Chrome-Proxy response headers are respected after the
 // configuration is updated.
 //
@@ -1389,4 +1635,77 @@
   EXPECT_EQ(title_watcher.WaitAndGetTitle(), kExpectedTitle);
 }
 
+// Test that disabling the kDataReductionProxyEnabledWithNetworkService disables
+// the proxy.
+class DataReductionProxyEnabledWithNetworkServiceHoldbackBrowserTest
+    : public ::testing::WithParamInterface<bool>,
+      public DataReductionProxyBrowsertest {
+ public:
+  void SetUp() override {
+    if (GetParam()) {
+      // Enable NetworkService, and disable
+      // kDataReductionProxyEnabledWithNetworkService.
+      scoped_feature_list_.InitWithFeatures(
+          {network::features::kNetworkService},
+          {data_reduction_proxy::features::
+               kDataReductionProxyEnabledWithNetworkService});
+    } else {
+      // Enable both NetworkService and
+      // kDataReductionProxyEnabledWithNetworkService.
+      scoped_feature_list_.InitWithFeatures(
+          {network::features::kNetworkService,
+           data_reduction_proxy::features::
+               kDataReductionProxyEnabledWithNetworkService},
+          {});
+    }
+
+    InProcessBrowserTest::SetUp();
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+IN_PROC_BROWSER_TEST_P(
+    DataReductionProxyEnabledWithNetworkServiceHoldbackBrowserTest,
+    ProxyUsed) {
+  const bool holdback_enabled = GetParam();
+
+  net::EmbeddedTestServer origin_server;
+  origin_server.RegisterRequestHandler(
+      base::BindRepeating(&BasicResponse, kDummyBody));
+  ASSERT_TRUE(origin_server.Start());
+
+  net::EmbeddedTestServer proxy_server;
+  proxy_server.RegisterRequestHandler(
+      base::BindRepeating(&BasicResponse, kPrimaryResponse));
+  ASSERT_TRUE(proxy_server.Start());
+
+  SetConfig(CreateConfigForServer(proxy_server));
+  // A network change forces the config to be fetched.
+  SimulateNetworkChange(network::mojom::ConnectionType::CONNECTION_3G);
+  if (!holdback_enabled) {
+    WaitForConfig();
+  }
+
+  ui_test_utils::NavigateToURL(
+      browser(), GetURLWithMockHost(origin_server, "/echoheader?Chrome-Proxy"));
+
+  if (holdback_enabled) {
+    // Proxy should not be used.
+    EXPECT_EQ(GetBody(), kDummyBody);
+  } else {
+    // Proxy should be used.
+    EXPECT_EQ(GetBody(), kPrimaryResponse);
+  }
+}
+
+// Parameter is true if kDataReductionProxyEnabledWithNetworkService is
+// disabled. Disabling kDataReductionProxyEnabledWithNetworkService should
+// disable data reduction proxy when network servicification is enabled.
+INSTANTIATE_TEST_SUITE_P(
+    ,
+    DataReductionProxyEnabledWithNetworkServiceHoldbackBrowserTest,
+    ::testing::Bool());
+
 }  // namespace data_reduction_proxy
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 11c9e24..135cf585 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -62,10 +62,8 @@
     "api/autofill_private/autofill_private_event_router_factory.h",
     "api/autofill_private/autofill_util.cc",
     "api/autofill_private/autofill_util.h",
-    "api/automation_internal/automation_event_router.cc",
-    "api/automation_internal/automation_event_router.h",
-    "api/automation_internal/automation_internal_api.cc",
-    "api/automation_internal/automation_internal_api.h",
+    "api/automation_internal/chrome_automation_internal_api_delegate.cc",
+    "api/automation_internal/chrome_automation_internal_api_delegate.h",
     "api/bookmark_manager_private/bookmark_manager_private_api.cc",
     "api/bookmark_manager_private/bookmark_manager_private_api.h",
     "api/bookmarks/bookmark_api_constants.cc",
diff --git a/chrome/browser/extensions/api/automation/automation_apitest.cc b/chrome/browser/extensions/api/automation/automation_apitest.cc
index 8728681..c772e66 100644
--- a/chrome/browser/extensions/api/automation/automation_apitest.cc
+++ b/chrome/browser/extensions/api/automation/automation_apitest.cc
@@ -11,13 +11,11 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #include "chrome/browser/extensions/extension_apitest.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/common/extensions/api/automation_internal.h"
 #include "chrome/common/extensions/chrome_extension_messages.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -27,6 +25,8 @@
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/test/extension_test_message_listener.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
diff --git a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
new file mode 100644
index 0000000..b33da9f
--- /dev/null
+++ b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.cc
@@ -0,0 +1,110 @@
+// 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 "chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h"
+
+#include <memory>
+
+#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/chrome_extension_function_details.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/api/automation.h"
+#include "extensions/common/api/automation_internal.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handlers/automation.h"
+#include "extensions/common/permissions/permissions_data.h"
+
+#if defined(USE_AURA)
+#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
+#endif
+
+namespace extensions {
+
+ChromeAutomationInternalApiDelegate::ChromeAutomationInternalApiDelegate() {}
+
+ChromeAutomationInternalApiDelegate::~ChromeAutomationInternalApiDelegate() {}
+
+bool ChromeAutomationInternalApiDelegate::CanRequestAutomation(
+    const Extension* extension,
+    const AutomationInfo* automation_info,
+    content::WebContents* contents) {
+  if (automation_info->desktop)
+    return true;
+
+  const GURL& url = contents->GetURL();
+  // TODO(aboxhall): check for webstore URL
+  if (automation_info->matches.MatchesURL(url))
+    return true;
+
+  int tab_id = ExtensionTabUtil::GetTabId(contents);
+  std::string unused_error;
+  return extension->permissions_data()->CanAccessPage(url, tab_id,
+                                                      &unused_error);
+}
+
+bool ChromeAutomationInternalApiDelegate::GetTabById(
+    int tab_id,
+    content::BrowserContext* browser_context,
+    bool include_incognito,
+    content::WebContents** contents,
+    std::string* error_msg) {
+  *error_msg = tabs_constants::kTabNotFoundError;
+  return ExtensionTabUtil::GetTabById(
+      tab_id, browser_context, include_incognito,
+      nullptr, /* browser out param */
+      nullptr, /* tab strip out param */
+      contents, nullptr /* tab_index out param */);
+}
+
+int ChromeAutomationInternalApiDelegate::GetTabId(
+    content::WebContents* contents) {
+  return ExtensionTabUtil::GetTabId(contents);
+}
+
+content::WebContents* ChromeAutomationInternalApiDelegate::GetActiveWebContents(
+    UIThreadExtensionFunction* function) {
+  return ChromeExtensionFunctionDetails(function)
+      .GetCurrentBrowser()
+      ->tab_strip_model()
+      ->GetActiveWebContents();
+}
+
+void ChromeAutomationInternalApiDelegate::EnableDesktop() {
+#if defined(USE_AURA)
+  AutomationManagerAura::GetInstance()->Enable();
+#else
+  NOTIMPLEMENTED();
+#endif
+}
+
+ui::AXTreeID ChromeAutomationInternalApiDelegate::GetAXTreeID() {
+#if defined(USE_AURA)
+  return AutomationManagerAura::GetInstance()->ax_tree_id();
+#else
+  NOTIMPLEMENTED();
+  return ui::AXTreeIDUnknown();
+#endif
+}
+
+void ChromeAutomationInternalApiDelegate::SetEventBundleSink(
+    ui::AXEventBundleSink* sink) {
+#if defined(USE_AURA)
+  AutomationManagerAura::GetInstance()->set_event_bundle_sink(sink);
+#else
+  NOTIMPLEMENTED();
+#endif
+}
+
+content::BrowserContext*
+ChromeAutomationInternalApiDelegate::GetActiveUserContext() {
+  return ProfileManager::GetActiveUserProfile();
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h
new file mode 100644
index 0000000..474b575d
--- /dev/null
+++ b/chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h
@@ -0,0 +1,40 @@
+// 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 CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROME_AUTOMATION_INTERNAL_API_DELEGATE_H_
+#define CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROME_AUTOMATION_INTERNAL_API_DELEGATE_H_
+
+#include "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
+
+namespace extensions {
+
+// A delegate for chrome specific automation api logic.
+class ChromeAutomationInternalApiDelegate
+    : public AutomationInternalApiDelegate {
+ public:
+  ChromeAutomationInternalApiDelegate();
+  ~ChromeAutomationInternalApiDelegate() override;
+
+  bool CanRequestAutomation(const Extension* extension,
+                            const AutomationInfo* automation_info,
+                            content::WebContents* contents) override;
+  bool GetTabById(int tab_id,
+                  content::BrowserContext* browser_context,
+                  bool include_incognito,
+                  content::WebContents** contents,
+                  std::string* error_msg) override;
+  int GetTabId(content::WebContents* contents) override;
+  content::WebContents* GetActiveWebContents(
+      UIThreadExtensionFunction* function) override;
+  void EnableDesktop() override;
+  ui::AXTreeID GetAXTreeID() override;
+  void SetEventBundleSink(ui::AXEventBundleSink* sink) override;
+  content::BrowserContext* GetActiveUserContext() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeAutomationInternalApiDelegate);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROME_AUTOMATION_INTERNAL_API_DELEGATE_H_
diff --git a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
index c5b7c830..95240d0 100644
--- a/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
+++ b/chrome/browser/extensions/api/bluetooth_low_energy/bluetooth_low_energy_apitest.cc
@@ -1273,7 +1273,7 @@
       new testing::NiceMock<MockBluetoothGattNotifySession>(
           chrc1_->GetWeakPtr());
 
-  EXPECT_CALL(*session1, Stop(_))
+  EXPECT_CALL(*session1, Stop_(_))
       .Times(1)
       .WillOnce(InvokeCallbackArgument<0>());
 
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index 4e43c5bf..4b71741 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -13,6 +13,7 @@
 #include "base/task/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/data_use_measurement/data_use_web_contents_observer.h"
+#include "chrome/browser/extensions/api/automation_internal/chrome_automation_internal_api_delegate.h"
 #include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
 #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h"
 #include "chrome/browser/extensions/api/declarative_content/default_content_predicate_evaluators.h"
@@ -355,4 +356,13 @@
 }
 #endif
 
+AutomationInternalApiDelegate*
+ChromeExtensionsAPIClient::GetAutomationInternalApiDelegate() {
+  if (!extensions_automation_api_delegate_) {
+    extensions_automation_api_delegate_ =
+        std::make_unique<ChromeAutomationInternalApiDelegate>();
+  }
+  return extensions_automation_api_delegate_.get();
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index 61936f76..15b684a 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -11,6 +11,7 @@
 
 namespace extensions {
 
+class ChromeAutomationInternalApiDelegate;
 class ChromeMetricsPrivateDelegate;
 class ClipboardExtensionHelper;
 
@@ -76,6 +77,8 @@
       const base::Callback<void(const std::string&)>& error_callback) override;
 #endif
 
+  AutomationInternalApiDelegate* GetAutomationInternalApiDelegate() override;
+
  private:
   std::unique_ptr<ChromeMetricsPrivateDelegate> metrics_private_delegate_;
   std::unique_ptr<NetworkingCastPrivateDelegate>
@@ -89,6 +92,8 @@
   std::unique_ptr<NonNativeFileSystemDelegate> non_native_file_system_delegate_;
   std::unique_ptr<ClipboardExtensionHelper> clipboard_extension_helper_;
 #endif
+  std::unique_ptr<extensions::ChromeAutomationInternalApiDelegate>
+      extensions_automation_api_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeExtensionsAPIClient);
 };
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index 92de7ce7..8a2509dc 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -1105,6 +1105,7 @@
       {"def.com", 4, "block", base::nullopt},
       {"def.com", 5, "redirect", get_url_for_host("xyz.com")},
       {"ghi*", 6, "redirect", get_url_for_host("ghijk.com")},
+      {"ijk*", 7, "redirect", "/manifest.json"},
   };
 
   // Load the extension.
@@ -1125,13 +1126,13 @@
   struct {
     std::string hostname;
     bool expected_main_frame_loaded;
-    base::Optional<std::string> expected_final_hostname;
+    base::Optional<GURL> expected_final_url;
     base::Optional<size_t> expected_redirect_chain_length;
   } test_cases[] = {
       // example.com -> yahoo.com -> google.com.
-      {"example.com", true, std::string("google.com"), 3},
+      {"example.com", true, GURL(get_url_for_host("google.com")), 3},
       // yahoo.com -> google.com.
-      {"yahoo.com", true, std::string("google.com"), 2},
+      {"yahoo.com", true, GURL(get_url_for_host("google.com")), 2},
       // abc.com -> def.com (blocked).
       // Note def.com won't be redirected since blocking rules are given
       // priority over redirect rules.
@@ -1141,25 +1142,30 @@
       // ghi.com -> ghijk.com.
       // Though ghijk.com still matches the redirect rule for |ghi*|, it will
       // not redirect to itself.
-      {"ghi.com", true, std::string("ghijk.com"), 2},
-  };
+      {"ghi.com", true, GURL(get_url_for_host("ghijk.com")), 2},
+      // ijklm.com -> chrome-extension://<extension_id>/manifest.json.
+      // Since this redirects to a manifest.json, don't expect the frame with
+      // script to load.
+      {"ijklm.com", false,
+       GURL("chrome-extension://" + last_loaded_extension_id() +
+            "/manifest.json"),
+       2}};
 
   for (const auto& test_case : test_cases) {
     std::string url = get_url_for_host(test_case.hostname);
     SCOPED_TRACE(base::StringPrintf("Testing %s", url.c_str()));
 
     ui_test_utils::NavigateToURL(browser(), GURL(url));
+    EXPECT_EQ(test_case.expected_main_frame_loaded,
+              WasFrameWithScriptLoaded(GetMainFrame()));
 
-    if (!test_case.expected_main_frame_loaded) {
-      EXPECT_FALSE(WasFrameWithScriptLoaded(GetMainFrame()));
+    if (!test_case.expected_final_url) {
       EXPECT_EQ(content::PAGE_TYPE_ERROR, GetPageType());
     } else {
-      EXPECT_TRUE(WasFrameWithScriptLoaded(GetMainFrame()));
       EXPECT_EQ(content::PAGE_TYPE_NORMAL, GetPageType());
 
       GURL final_url = web_contents()->GetLastCommittedURL();
-      EXPECT_EQ(GURL(get_url_for_host(*test_case.expected_final_hostname)),
-                final_url);
+      EXPECT_EQ(*test_case.expected_final_url, final_url);
 
       EXPECT_EQ(*test_case.expected_redirect_chain_length,
                 web_contents()
diff --git a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
index efb0e32..bf010812 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc
@@ -2219,6 +2219,53 @@
   EXPECT_TRUE(request_headers_modified4);
 }
 
+// Ensure conflicts between different extensions are handled correctly with
+// header names being interpreted in a case insensitive manner. Regression test
+// for crbug.com/956795.
+TEST(ExtensionWebRequestHelpersTest,
+     TestMergeOnBeforeSendHeadersResponses_Conflicts) {
+  // Have two extensions which both modify header "key1".
+  EventResponseDeltas deltas;
+  {
+    EventResponseDelta d1("extid1", base::Time::FromInternalValue(2000));
+    d1.modified_request_headers.SetHeader("key1", "ext1");
+    deltas.push_back(std::move(d1));
+  }
+
+  {
+    EventResponseDelta d2("extid2", base::Time::FromInternalValue(1000));
+    d2.modified_request_headers.SetHeader("KEY1", "ext2");
+    deltas.push_back(std::move(d2));
+  }
+
+  deltas.sort(&InDecreasingExtensionInstallationTimeOrder);
+
+  WebRequestInfo info;
+  info.logger = std::make_unique<TestLogger>();
+  helpers::IgnoredActions ignored_actions;
+  std::set<std::string> removed_headers, set_headers;
+  bool request_headers_modified = false;
+
+  net::HttpRequestHeaders headers;
+  headers.SetHeader("key1", "value 1");
+
+  // Take a reference to TestLogger to simplify accessing TestLogger methods.
+  TestLogger& logger = static_cast<TestLogger&>(*info.logger);
+
+  MergeOnBeforeSendHeadersResponses(info, deltas, &headers, &ignored_actions,
+                                    &removed_headers, &set_headers,
+                                    &request_headers_modified);
+
+  std::string header_value;
+  ASSERT_TRUE(headers.GetHeader("key1", &header_value));
+  EXPECT_EQ("ext1", header_value);
+  EXPECT_EQ(1u, ignored_actions.size());
+  EXPECT_EQ(2u, logger.log_size());
+  EXPECT_TRUE(request_headers_modified);
+  EXPECT_THAT(removed_headers, ::testing::IsEmpty());
+  EXPECT_THAT(set_headers, ElementsAre("key1"));
+}
+
 TEST(ExtensionWebRequestHelpersTest,
      TestMergeOnBeforeSendHeadersResponses_Cookies) {
   net::HttpRequestHeaders base_headers;
diff --git a/chrome/browser/google/google_update_win.cc b/chrome/browser/google/google_update_win.cc
index dd2ff72b..3e1ab1a 100644
--- a/chrome/browser/google/google_update_win.cc
+++ b/chrome/browser/google/google_update_win.cc
@@ -33,6 +33,7 @@
 #include "base/version.h"
 #include "base/win/atl.h"
 #include "base/win/scoped_bstr.h"
+#include "base/win/win_util.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/install_static/install_util.h"
@@ -137,11 +138,10 @@
 
   // For Vista+, need to instantiate the class factory via the elevation
   // moniker. This ensures that the UAC dialog shows up.
-  wchar_t class_id_as_string[MAX_PATH] = {};
-  StringFromGUID2(class_id, class_id_as_string, base::size(class_id_as_string));
+  auto class_id_as_string = base::win::String16FromGUID(class_id);
 
   base::string16 elevation_moniker_name = base::StringPrintf(
-      L"Elevation:Administrator!clsid:%ls", class_id_as_string);
+      L"Elevation:Administrator!clsid:%ls", class_id_as_string.c_str());
 
   BIND_OPTS3 bind_opts;
   // An explicit memset is needed rather than relying on value initialization
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
index 9fbf2b1..bf86504 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -5,11 +5,11 @@
 #include "chrome/browser/media/router/providers/cast/cast_activity_manager.h"
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/optional.h"
-#include "base/values.h"
 #include "chrome/browser/media/router/data_decoder_util.h"
 #include "chrome/browser/media/router/providers/cast/cast_activity_record.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_client.h"
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.h b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
index 20c9c23..a42b6ca 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h
+++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -16,6 +16,7 @@
 #include "base/optional.h"
 #include "base/sequence_checker.h"
 #include "base/values.h"
+#include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_tracker.h"
 #include "chrome/common/media_router/mojo/media_router.mojom.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_record.cc b/chrome/browser/media/router/providers/cast/cast_activity_record.cc
index d7373df..328b247 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_record.cc
+++ b/chrome/browser/media/router/providers/cast/cast_activity_record.cc
@@ -63,14 +63,27 @@
 
 cast_channel::Result CastActivityRecord::SendAppMessageToReceiver(
     const CastInternalMessage& cast_message) {
+  CastSessionClient* client = GetClient(cast_message.client_id);
   const CastSession* session = GetSession();
-  if (!session)
-    return cast_channel::Result::kFailed;  // TODO(jrw): Send error code
-                                           // back to SDK client.
+  if (!session) {
+    if (client && cast_message.sequence_number) {
+      client->SendErrorCodeToClient(
+          *cast_message.sequence_number,
+          CastInternalMessage::ErrorCode::kSessionError,
+          "Invalid session ID: " + session_id_.value_or("<missing>"));
+    }
+
+    return cast_channel::Result::kFailed;
+  }
   const std::string& message_namespace = cast_message.app_message_namespace();
   if (!base::ContainsKey(session->message_namespaces(), message_namespace)) {
     DLOG(ERROR) << "Disallowed message namespace: " << message_namespace;
-    // TODO(jrw): Send error code back to SDK client.
+    if (client && cast_message.sequence_number) {
+      client->SendErrorCodeToClient(
+          *cast_message.sequence_number,
+          CastInternalMessage::ErrorCode::kInvalidParameter,
+          "Invalid namespace: " + message_namespace);
+    }
     return cast_channel::Result::kFailed;
   }
   return message_handler_->SendAppMessage(
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_record.h b/chrome/browser/media/router/providers/cast/cast_activity_record.h
index 7e6e7a4..a06d359 100644
--- a/chrome/browser/media/router/providers/cast/cast_activity_record.h
+++ b/chrome/browser/media/router/providers/cast/cast_activity_record.h
@@ -117,6 +117,11 @@
   CastSession* GetSession();
   int GetCastChannelId();
 
+  CastSessionClient* GetClient(const std::string& client_id) {
+    auto it = connected_clients_.find(client_id);
+    return it == connected_clients_.end() ? nullptr : it->second.get();
+  }
+
   MediaRoute route_;
   const std::string app_id_;
   base::flat_map<std::string, std::unique_ptr<CastSessionClient>>
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
index 4724a80a..d0c9e2fa 100644
--- a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
+++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
@@ -5,17 +5,57 @@
 #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h"
 
 #include <string>
+#include <utility>
 
 #include "base/base64url.h"
 #include "base/hash/sha1.h"
 #include "base/json/json_writer.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/string_piece.h"
 #include "chrome/common/media_router/discovery/media_sink_internal.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
 #include "components/cast_channel/cast_socket.h"
+#include "components/cast_channel/enum_table.h"
 #include "components/cast_channel/proto/cast_channel.pb.h"
 #include "net/base/escape.h"
 
+namespace cast_util {
+
+using namespace media_router;
+
+template <>
+const EnumTable<CastInternalMessage::Type>
+    EnumTable<CastInternalMessage::Type>::instance({
+        {CastInternalMessage::Type::kClientConnect, "client_connect"},
+        {CastInternalMessage::Type::kAppMessage, "app_message"},
+        {CastInternalMessage::Type::kV2Message, "v2_message"},
+        {CastInternalMessage::Type::kLeaveSession, "leave_session"},
+        {CastInternalMessage::Type::kReceiverAction, "receiver_action"},
+        {CastInternalMessage::Type::kNewSession, "new_session"},
+        {CastInternalMessage::Type::kUpdateSession, "update_session"},
+        {CastInternalMessage::Type::kError, "error"},
+        // kOther deliberately omitted
+    });
+
+template <>
+const EnumTable<CastInternalMessage::ErrorCode> EnumTable<
+    CastInternalMessage::ErrorCode>::instance({
+    {CastInternalMessage::ErrorCode::kInternalError, "internal_error"},
+    {CastInternalMessage::ErrorCode::kCancel, "cancel"},
+    {CastInternalMessage::ErrorCode::kTimeout, "timeout"},
+    {CastInternalMessage::ErrorCode::kApiNotInitialized, "api_not_initialized"},
+    {CastInternalMessage::ErrorCode::kInvalidParameter, "invalid_parameter"},
+    {CastInternalMessage::ErrorCode::kExtensionNotCompatible,
+     "extension_not_compatible"},
+    {CastInternalMessage::ErrorCode::kReceiverUnavailable,
+     "receiver_unavailable"},
+    {CastInternalMessage::ErrorCode::kSessionError, "session_error"},
+    {CastInternalMessage::ErrorCode::kChannelError, "channel_error"},
+    {CastInternalMessage::ErrorCode::kLoadMediaFailed, "load_media_failed"},
+});
+
+}  // namespace cast_util
+
 namespace media_router {
 
 namespace {
@@ -24,14 +64,6 @@
 // considered idle, and an active session should not be reported.
 constexpr char kBackdropAppId[] = "E8C28D3C";
 
-constexpr char kClientConnect[] = "client_connect";
-constexpr char kAppMessage[] = "app_message";
-constexpr char kV2Message[] = "v2_message";
-constexpr char kLeaveSession[] = "leave_session";
-constexpr char kReceiverAction[] = "receiver_action";
-constexpr char kNewSession[] = "new_session";
-constexpr char kUpdateSession[] = "update_session";
-
 bool GetString(const base::Value& value,
                const std::string& key,
                std::string* out) {
@@ -62,46 +94,14 @@
 
 CastInternalMessage::Type CastInternalMessageTypeFromString(
     const std::string& type) {
-  if (type == kClientConnect)
-    return CastInternalMessage::Type::kClientConnect;
-  if (type == kAppMessage)
-    return CastInternalMessage::Type::kAppMessage;
-  if (type == kV2Message)
-    return CastInternalMessage::Type::kV2Message;
-  if (type == kLeaveSession)
-    return CastInternalMessage::Type::kLeaveSession;
-  if (type == kReceiverAction)
-    return CastInternalMessage::Type::kReceiverAction;
-  if (type == kNewSession)
-    return CastInternalMessage::Type::kNewSession;
-  if (type == kUpdateSession)
-    return CastInternalMessage::Type::kUpdateSession;
-
-  return CastInternalMessage::Type::kOther;
+  return cast_util::StringToEnum<CastInternalMessage::Type>(type).value_or(
+      CastInternalMessage::Type::kOther);
 }
 
 std::string CastInternalMessageTypeToString(CastInternalMessage::Type type) {
-  switch (type) {
-    case CastInternalMessage::Type::kClientConnect:
-      return kClientConnect;
-    case CastInternalMessage::Type::kAppMessage:
-      return kAppMessage;
-    case CastInternalMessage::Type::kV2Message:
-      return kV2Message;
-    case CastInternalMessage::Type::kLeaveSession:
-      return kLeaveSession;
-    case CastInternalMessage::Type::kReceiverAction:
-      return kReceiverAction;
-    case CastInternalMessage::Type::kNewSession:
-      return kNewSession;
-    case CastInternalMessage::Type::kUpdateSession:
-      return kUpdateSession;
-    case CastInternalMessage::Type::kOther:
-      NOTREACHED();
-      return "";
-  }
-  NOTREACHED();
-  return "";
+  auto found = cast_util::EnumToString(type);
+  DCHECK(found);
+  return found.value_or(base::StringPiece()).as_string();
 }
 
 // Possible types in a receiver_action message.
@@ -504,6 +504,14 @@
                              base::Value(), client_id, sequence_number);
 }
 
+blink::mojom::PresentationConnectionMessagePtr CreateErrorMessage(
+    const std::string& client_id,
+    base::Value error,
+    base::Optional<int> sequence_number) {
+  return CreateMessageCommon(CastInternalMessage::Type::kError,
+                             std::move(error), client_id, sequence_number);
+}
+
 base::Value SupportedMediaRequestsToListValue(int media_requests) {
   base::Value value(base::Value::Type::LIST);
   auto& storage = value.GetList();
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util.h b/chrome/browser/media/router/providers/cast/cast_internal_message_util.h
index 0a78709..73335df 100644
--- a/chrome/browser/media/router/providers/cast/cast_internal_message_util.h
+++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util.h
@@ -34,8 +34,25 @@
                       // session.
     kUpdateSession,   // Message sent by MRP to inform SDK client of updated
                       // session.
-    kOther            // All other types of messages which are not considered
-                      // part of communication with Cast SDK.
+    kError,
+    kOther  // All other types of messages which are not considered
+            // part of communication with Cast SDK.
+  };
+
+  // Errors that may be returned by the SDK.
+  enum class ErrorCode {
+    kInternalError,           // Internal error.  (Not specified by Cast API.)
+    kCancel,                  // The operation was canceled by the user.
+    kTimeout,                 // The operation timed out.
+    kApiNotInitialized,       // The API is not initialized.
+    kInvalidParameter,        // The parameters to the operation were not valid.
+    kExtensionNotCompatible,  // The API script is not compatible with
+                              // this Cast implementation.
+    kReceiverUnavailable,     // No receiver was compatible with the session
+                              // request.
+    kSessionError,  // A session could not be created, or a session was invalid.
+    kChannelError,  // A channel to the receiver is not available.
+    kLoadMediaFailed,  // Load media failed.
   };
 
   // Returns a CastInternalMessage for |message|, or nullptr is |message| is not
@@ -184,6 +201,10 @@
     const std::string& client_id,
     const base::Value& payload,
     base::Optional<int> sequence_number);
+blink::mojom::PresentationConnectionMessagePtr CreateErrorMessage(
+    const std::string& client_id,
+    base::Value error,
+    base::Optional<int> sequence_number);
 blink::mojom::PresentationConnectionMessagePtr CreateLeaveSessionAckMessage(
     const std::string& client_id,
     base::Optional<int> sequence_number);
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client.cc b/chrome/browser/media/router/providers/cast/cast_session_client.cc
index a8b7a71..fd7bea2 100644
--- a/chrome/browser/media/router/providers/cast/cast_session_client.cc
+++ b/chrome/browser/media/router/providers/cast/cast_session_client.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "chrome/browser/media/router/data_decoder_util.h"
 #include "chrome/browser/media/router/providers/cast/cast_activity_record.h"
+#include "components/cast_channel/enum_table.h"
 
 using blink::mojom::PresentationConnectionCloseReason;
 using blink::mojom::PresentationConnectionMessagePtr;
@@ -107,6 +108,24 @@
   }
 }
 
+void CastSessionClient::SendErrorCodeToClient(
+    int sequence_number,
+    CastInternalMessage::ErrorCode error_code,
+    base::Optional<std::string> description) {
+  base::Value message(base::Value::Type::DICTIONARY);
+  message.SetKey("code", base::Value(*cast_util::EnumToString(error_code)));
+  message.SetKey("description",
+                 description ? base::Value(*description) : base::Value());
+  message.SetKey("details", base::Value());
+  SendErrorToClient(sequence_number, std::move(message));
+}
+
+void CastSessionClient::SendErrorToClient(int sequence_number,
+                                          base::Value error) {
+  SendMessageToClient(
+      CreateErrorMessage(client_id(), std::move(error), sequence_number));
+}
+
 void CastSessionClient::HandleParsedClientMessage(
     std::unique_ptr<base::Value> message) {
   std::unique_ptr<CastInternalMessage> cast_message =
@@ -199,11 +218,17 @@
 
 void CastSessionClient::SendResultResponse(int sequence_number,
                                            cast_channel::Result result) {
-  // TODO(jrw): Send error message on failure.
   if (result == cast_channel::Result::kOk) {
     // Send an empty message to let the client know the request succeeded.
     SendMessageToClient(
         CreateV2Message(client_id_, base::Value(), sequence_number));
+  } else {
+    // TODO(crbug.com/951089): Send correct error codes.  The original
+    // implementation isn't much help here because it sends incorrectly
+    // formatted error messages without a valid error code in a lot of cases.
+    SendErrorCodeToClient(sequence_number,
+                          CastInternalMessage::ErrorCode::kInternalError,
+                          "unknown error");
   }
 }
 
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client.h b/chrome/browser/media/router/providers/cast/cast_session_client.h
index 1965f61..7e21fa5f 100644
--- a/chrome/browser/media/router/providers/cast/cast_session_client.h
+++ b/chrome/browser/media/router/providers/cast/cast_session_client.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
+#include "base/values.h"
 #include "chrome/browser/media/router/providers/cast/cast_session_tracker.h"
 #include "chrome/common/media_router/mojo/media_router.mojom.h"
 #include "chrome/common/media_router/providers/cast/cast_media_source.h"
@@ -49,6 +50,9 @@
   mojom::RoutePresentationConnectionPtr Init();
 
   // Sends |message| to the Cast SDK client in Blink.
+  //
+  // TODO(jrw): Remove redundant "ToClient" in the name of this and other
+  // methods.
   void SendMessageToClient(
       blink::mojom::PresentationConnectionMessagePtr message);
 
@@ -88,6 +92,15 @@
   // case I believe this method would no longer be needed.
   bool MatchesAutoJoinPolicy(url::Origin origin, int tab_id) const;
 
+  void SendErrorCodeToClient(int sequence_number,
+                             CastInternalMessage::ErrorCode error_code,
+                             base::Optional<std::string> description);
+
+  // NOTE: This is current only called from SendErrorCodeToClient, but based on
+  // the old code this method based on, it seems likely it will have other
+  // callers once error handling for the Cast MRP is more fleshed out.
+  void SendErrorToClient(int sequence_number, base::Value error);
+
  private:
   void HandleParsedClientMessage(std::unique_ptr<base::Value> message);
   void HandleV2ProtocolMessage(const CastInternalMessage& cast_message);
diff --git a/chrome/browser/memory/memory_pressure_monitor_win.cc b/chrome/browser/memory/memory_pressure_monitor_win.cc
index 495f50f3..491a352 100644
--- a/chrome/browser/memory/memory_pressure_monitor_win.cc
+++ b/chrome/browser/memory/memory_pressure_monitor_win.cc
@@ -15,6 +15,8 @@
 namespace {
 
 using SamplingFrequency = performance_monitor::SystemMonitor::SamplingFrequency;
+using MetricsRefreshFrequencies = performance_monitor::SystemMonitor::
+    SystemObserver::MetricRefreshFrequencies;
 
 const DWORDLONG kMBBytes = 1024 * 1024;
 
@@ -118,10 +120,12 @@
       disk_idle_time_obs_window_(
           base::TimeDelta::FromSeconds(kDiskIdleTimeWindowLengthSeconds.Get()),
           kDiskIdleTimeLowThreshold.Get()) {
+  DCHECK(performance_monitor::SystemMonitor::Get());
   // The amount of free memory is always tracked.
-  refresh_frequencies_ = {
-      .free_phys_memory_mb_frequency = SamplingFrequency::kDefaultFrequency,
-  };
+  refresh_frequencies_ =
+      MetricsRefreshFrequencies::Builder()
+          .SetFreePhysMemoryMbFrequency(SamplingFrequency::kDefaultFrequency)
+          .Build();
   performance_monitor::SystemMonitor::Get()->AddOrUpdateObserver(
       this, refresh_frequencies_);
 }
diff --git a/chrome/browser/memory/memory_pressure_monitor_win.h b/chrome/browser/memory/memory_pressure_monitor_win.h
index 566c3c6..26daf5c 100644
--- a/chrome/browser/memory/memory_pressure_monitor_win.h
+++ b/chrome/browser/memory/memory_pressure_monitor_win.h
@@ -14,6 +14,9 @@
 namespace memory {
 
 // Windows implementation of the memory pressure monitor.
+//
+// The global performance_monitor::SystemMonitor instance should be initialized
+// before the creation of this object.
 class MemoryPressureMonitorWin
     : public MemoryPressureMonitor,
       public performance_monitor::SystemMonitor::SystemObserver {
diff --git a/chrome/browser/notifications/notification_schedule_service_factory.cc b/chrome/browser/notifications/notification_schedule_service_factory.cc
index 64a7c75..a6770e5 100644
--- a/chrome/browser/notifications/notification_schedule_service_factory.cc
+++ b/chrome/browser/notifications/notification_schedule_service_factory.cc
@@ -4,12 +4,16 @@
 
 #include "chrome/browser/notifications/notification_schedule_service_factory.h"
 
+#include <memory>
+#include <utility>
+
 #include "chrome/browser/notifications/notification_background_task_scheduler_impl.h"
 #include "chrome/browser/notifications/scheduler/notification_schedule_service.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
 #include "chrome/browser/notifications/scheduler/schedule_service_factory_helper.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_constants.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/leveldb_proto/content/proto_database_provider_factory.h"
 
@@ -40,14 +44,15 @@
 
 KeyedService* NotificationScheduleServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
-  // Pass all dependencies to notification scheduler and build the service
-  // instance.
+  auto* profile = Profile::FromBrowserContext(context);
+  base::FilePath storage_dir =
+      profile->GetPath().Append(chrome::kNotificationSchedulerStorageDirname);
   auto background_task_scheduler =
       std::make_unique<NotificationBackgroundTaskSchedulerImpl>();
   auto* db_provider = leveldb_proto::ProtoDatabaseProviderFactory::GetForKey(
-      Profile::FromBrowserContext(context)->GetProfileKey());
+      profile->GetProfileKey());
   return notifications::CreateNotificationScheduleService(
-      std::move(background_task_scheduler), db_provider);
+      std::move(background_task_scheduler), db_provider, storage_dir);
 }
 
 content::BrowserContext*
diff --git a/chrome/browser/notifications/scheduler/BUILD.gn b/chrome/browser/notifications/scheduler/BUILD.gn
index d7efc984..07cf8b7 100644
--- a/chrome/browser/notifications/scheduler/BUILD.gn
+++ b/chrome/browser/notifications/scheduler/BUILD.gn
@@ -45,10 +45,12 @@
     "schedule_service_factory_helper.h",
   ]
 
+  # This target should not depend on anything in //chrome/* except the proto library.
   deps = [
     ":lib",
     ":public",
     "//base",
+    "//chrome/browser/notifications/proto",
     "//components/keyed_service/core",
     "//components/leveldb_proto",
   ]
diff --git a/chrome/browser/notifications/scheduler/notification_background_task_scheduler.h b/chrome/browser/notifications/scheduler/notification_background_task_scheduler.h
index 0857988..d060643 100644
--- a/chrome/browser/notifications/scheduler/notification_background_task_scheduler.h
+++ b/chrome/browser/notifications/scheduler/notification_background_task_scheduler.h
@@ -27,6 +27,7 @@
     virtual void OnStopTask() = 0;
 
    protected:
+    Handler() = default;
     virtual ~Handler() = default;
 
    private:
diff --git a/chrome/browser/notifications/scheduler/notification_schedule_service_impl.cc b/chrome/browser/notifications/scheduler/notification_schedule_service_impl.cc
index fa5dd88..f9565982 100644
--- a/chrome/browser/notifications/scheduler/notification_schedule_service_impl.cc
+++ b/chrome/browser/notifications/scheduler/notification_schedule_service_impl.cc
@@ -4,16 +4,17 @@
 
 #include "chrome/browser/notifications/scheduler/notification_schedule_service_impl.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "chrome/browser/notifications/scheduler/notification_params.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler.h"
-#include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
 
 namespace notifications {
 
 NotificationScheduleServiceImpl::NotificationScheduleServiceImpl(
-    std::unique_ptr<NotificationSchedulerContext> context)
-    : scheduler_(NotificationScheduler::Create(std::move(context))) {}
+    std::unique_ptr<NotificationScheduler> scheduler)
+    : scheduler_(std::move(scheduler)) {}
 
 NotificationScheduleServiceImpl::~NotificationScheduleServiceImpl() = default;
 
diff --git a/chrome/browser/notifications/scheduler/notification_schedule_service_impl.h b/chrome/browser/notifications/scheduler/notification_schedule_service_impl.h
index 46b14e0..d739bf4 100644
--- a/chrome/browser/notifications/scheduler/notification_schedule_service_impl.h
+++ b/chrome/browser/notifications/scheduler/notification_schedule_service_impl.h
@@ -13,13 +13,12 @@
 namespace notifications {
 
 class NotificationScheduler;
-class NotificationSchedulerContext;
 struct NotificationParams;
 
 class NotificationScheduleServiceImpl : public NotificationScheduleService {
  public:
-  NotificationScheduleServiceImpl(
-      std::unique_ptr<NotificationSchedulerContext> context);
+  explicit NotificationScheduleServiceImpl(
+      std::unique_ptr<NotificationScheduler> scheduler);
   ~NotificationScheduleServiceImpl() override;
 
  private:
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler.cc b/chrome/browser/notifications/scheduler/notification_scheduler.cc
index 602507c..8985f92 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler.cc
+++ b/chrome/browser/notifications/scheduler/notification_scheduler.cc
@@ -4,33 +4,177 @@
 
 #include "chrome/browser/notifications/scheduler/notification_scheduler.h"
 
+#include <utility>
+
+#include "base/bind.h"
 #include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "chrome/browser/notifications/scheduler/display_decider.h"
+#include "chrome/browser/notifications/scheduler/distribution_policy.h"
+#include "chrome/browser/notifications/scheduler/icon_store.h"
+#include "chrome/browser/notifications/scheduler/impression_history_tracker.h"
+#include "chrome/browser/notifications/scheduler/notification_background_task_scheduler.h"
+#include "chrome/browser/notifications/scheduler/notification_entry.h"
 #include "chrome/browser/notifications/scheduler/notification_params.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
+#include "chrome/browser/notifications/scheduler/scheduled_notification_manager.h"
 
 namespace notifications {
 namespace {
 
+class NotificationSchedulerImpl;
+
+// Helper class to do async initialization in parallel for multiple subsystem
+// instances.
+class InitHelper {
+ public:
+  using InitCallback = base::OnceCallback<void(bool)>;
+  InitHelper() : weak_ptr_factory_(this) {}
+
+  ~InitHelper() = default;
+
+  // Initializes subsystems in notification scheduler, |callback| will be
+  // invoked if all initializations finished or anyone of them failed. The
+  // object should be destroyed along with the |callback|.
+  void Init(NotificationSchedulerContext* context, InitCallback callback) {
+    callback_ = std::move(callback);
+    context->icon_store()->Init(base::BindOnce(
+        &InitHelper::OnIconStoreInitialized, weak_ptr_factory_.GetWeakPtr()));
+    context->impression_tracker()->Init(
+        base::BindOnce(&InitHelper::OnImpressionTrackerInitialized,
+                       weak_ptr_factory_.GetWeakPtr()));
+    context->notification_manager()->Init(
+        base::BindOnce(&InitHelper::OnNotificationManagerInitialized,
+                       weak_ptr_factory_.GetWeakPtr()));
+  }
+
+ private:
+  void OnIconStoreInitialized(bool success) {
+    icon_store_initialzed_ = success;
+    MaybeFinishInitialization();
+  }
+
+  void OnImpressionTrackerInitialized(bool success) {
+    impression_tracker_initialzed_ = success;
+    MaybeFinishInitialization();
+  }
+
+  void OnNotificationManagerInitialized(bool success) {
+    notification_manager_initialized_ = success;
+    MaybeFinishInitialization();
+  }
+
+  void MaybeFinishInitialization() {
+    bool all_finished = icon_store_initialzed_.has_value() &&
+                        impression_tracker_initialzed_.has_value() &&
+                        notification_manager_initialized_.has_value();
+    // Notify the initialization result when all subcomponents are initialized.
+    if (!all_finished)
+      return;
+
+    bool success = icon_store_initialzed_.value() &&
+                   impression_tracker_initialzed_.value() &&
+                   notification_manager_initialized_.value();
+    std::move(callback_).Run(success);
+  }
+
+  InitCallback callback_;
+  base::Optional<bool> icon_store_initialzed_;
+  base::Optional<bool> impression_tracker_initialzed_;
+  base::Optional<bool> notification_manager_initialized_;
+
+  base::WeakPtrFactory<InitHelper> weak_ptr_factory_;
+  DISALLOW_COPY_AND_ASSIGN(InitHelper);
+};
+
 // Implementation of NotificationScheduler.
-class NotificationSchedulerImpl : public NotificationScheduler {
+class NotificationSchedulerImpl
+    : public NotificationScheduler,
+      public NotificationBackgroundTaskScheduler::Handler,
+      public ScheduledNotificationManager::Delegate {
  public:
   NotificationSchedulerImpl(
       std::unique_ptr<NotificationSchedulerContext> context)
-      : context_(std::move(context)) {}
+      : context_(std::move(context)), weak_ptr_factory_(this) {}
 
   ~NotificationSchedulerImpl() override = default;
 
  private:
   // NotificationScheduler implementation.
-  void Init(InitCallback init_callback) override { NOTIMPLEMENTED(); }
+  void Init(InitCallback init_callback) override {
+    auto helper = std::make_unique<InitHelper>();
+    auto* helper_ptr = helper.get();
+    helper_ptr->Init(
+        context_.get(),
+        base::BindOnce(&NotificationSchedulerImpl::OnInitialized,
+                       weak_ptr_factory_.GetWeakPtr(), std::move(helper),
+                       std::move(init_callback)));
+  }
 
   void Schedule(
       std::unique_ptr<NotificationParams> notification_params) override {
+    context_->notification_manager()->ScheduleNotification(
+        std::move(notification_params));
+  }
+
+  void OnInitialized(std::unique_ptr<InitHelper>,
+                     InitCallback init_callback,
+                     bool success) {
+    // TODO(xingliu): Inform the clients about initialization results and tear
+    // down internal components.
+    std::move(init_callback).Run(success);
+  }
+
+  // NotificationBackgroundTaskScheduler::Handler implementation.
+  void OnStartTask() override {
+    // Updates the impression data to compute daily notification shown budget.
+    context_->impression_tracker()->AnalyzeImpressionHistory();
+
+    // TODO(xingliu): Pass SchedulerTaskTime from background task.
+    FindNotificationToShow(SchedulerTaskTime::kMorning);
+
+    // Schedule the next background task based on scheduled notifications.
+    ScheduleBackgroundTask();
+  }
+
+  void OnStopTask() override { ScheduleBackgroundTask(); }
+
+  // ScheduledNotificationManager::Delegate implementation.
+  void DisplayNotification(
+      std::unique_ptr<NotificationEntry> notification) override {
+    // TODO(xingliu): Inform the clients and show the notification.
+    NOTIMPLEMENTED();
+  }
+
+  void FindNotificationToShow(SchedulerTaskTime task_start_time) {
+    DisplayDecider::Results results;
+    ScheduledNotificationManager::Notifications notifications;
+    context_->notification_manager()->GetAllNotifications(&notifications);
+    const auto& client_states =
+        context_->impression_tracker()->GetClientStates();
+    DisplayDecider::ClientStates client_state_ptrs;
+    for (const auto& client_state : client_states) {
+      client_state_ptrs.emplace(client_state.first, client_state.second.get());
+    }
+    context_->display_decider()->FindNotificationsToShow(
+        context_->config(), context_->clients(), DistributionPolicy::Create(),
+        task_start_time, std::move(notifications), std::move(client_state_ptrs),
+        &results);
+    for (const auto& guid : results) {
+      context_->notification_manager()->DisplayNotification(guid);
+    }
+  }
+
+  void ScheduleBackgroundTask() {
+    // TODO(xingliu): Implements a class to determine the next background task
+    // based on scheduled notification data.
     NOTIMPLEMENTED();
   }
 
   std::unique_ptr<NotificationSchedulerContext> context_;
 
+  base::WeakPtrFactory<NotificationSchedulerImpl> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(NotificationSchedulerImpl);
 };
 
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_context.cc b/chrome/browser/notifications/scheduler/notification_scheduler_context.cc
index cde8211..7920d19 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler_context.cc
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_context.cc
@@ -4,15 +4,28 @@
 
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
 
+#include <utility>
+
+#include "chrome/browser/notifications/scheduler/display_decider.h"
+#include "chrome/browser/notifications/scheduler/icon_store.h"
+#include "chrome/browser/notifications/scheduler/impression_history_tracker.h"
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler.h"
+#include "chrome/browser/notifications/scheduler/scheduled_notification_manager.h"
 #include "chrome/browser/notifications/scheduler/scheduler_config.h"
 
 namespace notifications {
 
 NotificationSchedulerContext::NotificationSchedulerContext(
     std::unique_ptr<NotificationBackgroundTaskScheduler> scheduler,
+    std::unique_ptr<IconStore> icon_store,
+    std::unique_ptr<ImpressionHistoryTracker> impression_tracker,
+    std::unique_ptr<ScheduledNotificationManager> notification_manager,
+    std::unique_ptr<DisplayDecider> display_decider,
     std::unique_ptr<SchedulerConfig> config)
     : background_task_scheduler_(std::move(scheduler)),
+      impression_tracker_(std::move(impression_tracker)),
+      notification_manager_(std::move(notification_manager)),
+      display_decider_(std::move(display_decider)),
       config_(std::move(config)) {}
 
 NotificationSchedulerContext::~NotificationSchedulerContext() = default;
diff --git a/chrome/browser/notifications/scheduler/notification_scheduler_context.h b/chrome/browser/notifications/scheduler/notification_scheduler_context.h
index a5738db3..ccf466f1 100644
--- a/chrome/browser/notifications/scheduler/notification_scheduler_context.h
+++ b/chrome/browser/notifications/scheduler/notification_scheduler_context.h
@@ -6,36 +6,75 @@
 #define CHROME_BROWSER_NOTIFICATIONS_SCHEDULER_NOTIFICATION_SCHEDULER_CONTEXT_H_
 
 #include <memory>
+#include <vector>
 
 #include "base/macros.h"
+#include "chrome/browser/notifications/scheduler/notification_scheduler_types.h"
 
 namespace notifications {
 
+class DisplayDecider;
+class IconStore;
+class ImpressionHistoryTracker;
 class NotificationBackgroundTaskScheduler;
+class ScheduledNotificationManager;
 struct SchedulerConfig;
 
 // Context that contains necessary components needed by the notification
 // scheduler to perform tasks.
-// TODO(xingliu): If we have less than 5 dependencies, remove this file to
-// directly pass in the dependencies.
 class NotificationSchedulerContext {
  public:
   NotificationSchedulerContext(
       std::unique_ptr<NotificationBackgroundTaskScheduler> scheduler,
+      std::unique_ptr<IconStore> icon_store,
+      std::unique_ptr<ImpressionHistoryTracker> impression_tracker,
+      std::unique_ptr<ScheduledNotificationManager> notification_manager,
+      std::unique_ptr<DisplayDecider> display_decider,
       std::unique_ptr<SchedulerConfig> config);
   ~NotificationSchedulerContext();
 
-  // Gets the background task scheduler.
+  const std::vector<SchedulerClientType>& clients() const { return clients_; }
+
   NotificationBackgroundTaskScheduler* background_task_scheduler() {
     return background_task_scheduler_.get();
   }
 
-  // Gets system configuration.
+  IconStore* icon_store() { return icon_store_.get(); }
+
+  ImpressionHistoryTracker* impression_tracker() {
+    return impression_tracker_.get();
+  }
+
+  ScheduledNotificationManager* notification_manager() {
+    return notification_manager_.get();
+  }
+
+  DisplayDecider* display_decider() { return display_decider_.get(); }
+
   const SchedulerConfig* config() const { return config_.get(); }
 
  private:
+  // List of clients using the notification scheduler system.
+  // TODO(xingliu): Pass in the registered the clients.
+  std::vector<SchedulerClientType> clients_;
+
+  // Used to schedule background task in OS level.
   std::unique_ptr<NotificationBackgroundTaskScheduler>
       background_task_scheduler_;
+
+  // Stores notification icons.
+  std::unique_ptr<IconStore> icon_store_;
+
+  // Tracks user impressions towards specific notification type.
+  std::unique_ptr<ImpressionHistoryTracker> impression_tracker_;
+
+  // Stores all scheduled notifications.
+  std::unique_ptr<ScheduledNotificationManager> notification_manager_;
+
+  // Helper class to decide which notification should be displayed to the user.
+  std::unique_ptr<DisplayDecider> display_decider_;
+
+  // System configuration.
   std::unique_ptr<SchedulerConfig> config_;
 
   DISALLOW_COPY_AND_ASSIGN(NotificationSchedulerContext);
diff --git a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
index 0ef36431..af11260 100644
--- a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
+++ b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.cc
@@ -4,22 +4,68 @@
 
 #include "chrome/browser/notifications/scheduler/schedule_service_factory_helper.h"
 
+#include <utility>
+
+#include "base/sequenced_task_runner.h"
+#include "base/task/post_task.h"
+#include "chrome/browser/notifications/scheduler/display_decider.h"
+#include "chrome/browser/notifications/scheduler/icon_store.h"
+#include "chrome/browser/notifications/scheduler/impression_history_tracker.h"
+#include "chrome/browser/notifications/scheduler/impression_store.h"
+#include "chrome/browser/notifications/scheduler/init_aware_scheduler.h"
 #include "chrome/browser/notifications/scheduler/notification_background_task_scheduler.h"
 #include "chrome/browser/notifications/scheduler/notification_schedule_service_impl.h"
 #include "chrome/browser/notifications/scheduler/notification_scheduler_context.h"
+#include "chrome/browser/notifications/scheduler/scheduled_notification_manager.h"
 #include "chrome/browser/notifications/scheduler/scheduler_config.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "components/leveldb_proto/public/shared_proto_database_client_list.h"
 
 namespace notifications {
+namespace {
+const base::FilePath::CharType kImpressionDBName[] =
+    FILE_PATH_LITERAL("ImpressionDB");
+const base::FilePath::CharType kIconDBName[] = FILE_PATH_LITERAL("IconDB");
+}  // namespace
 
 KeyedService* CreateNotificationScheduleService(
     std::unique_ptr<NotificationBackgroundTaskScheduler>
         background_task_scheduler,
-    leveldb_proto::ProtoDatabaseProvider* db_provider) {
+    leveldb_proto::ProtoDatabaseProvider* db_provider,
+    const base::FilePath& storage_dir) {
   auto config = SchedulerConfig::Create();
+  auto task_runner = base::CreateSequencedTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT});
+
+  // Build icon store.
+  base::FilePath icon_store_dir = storage_dir.Append(kIconDBName);
+  auto icon_db = db_provider->GetDB<proto::Icon, IconEntry>(
+      leveldb_proto::ProtoDbType::NOTIFICATION_SCHEDULER_ICON_STORE,
+      icon_store_dir, task_runner);
+  auto icon_store = std::make_unique<IconProtoDbStore>(std::move(icon_db));
+
+  // Build impression store.
+  base::FilePath impression_store_dir = storage_dir.Append(kImpressionDBName);
+  auto impression_db = db_provider->GetDB<proto::ClientState, ClientState>(
+      leveldb_proto::ProtoDbType::NOTIFICATION_SCHEDULER_IMPRESSION_STORE,
+      impression_store_dir, task_runner);
+  auto impression_store =
+      std::make_unique<ImpressionStore>(std::move(impression_db));
+  auto impression_tracker = std::make_unique<ImpressionHistoryTrackerImpl>(
+      *config.get(), std::move(impression_store));
+
+  // TODO(xingliu): Build notification store.
+  std::unique_ptr<ScheduledNotificationManager> notification_manager;
+
   auto context = std::make_unique<NotificationSchedulerContext>(
-      std::move(background_task_scheduler), std::move(config));
+      std::move(background_task_scheduler), std::move(icon_store),
+      std::move(impression_tracker), std::move(notification_manager),
+      DisplayDecider::Create(), std::move(config));
+  auto scheduler = NotificationScheduler::Create(std::move(context));
+  auto init_aware_scheduler =
+      std::make_unique<InitAwareNotificationScheduler>(std::move(scheduler));
   return static_cast<KeyedService*>(
-      new NotificationScheduleServiceImpl(std::move(context)));
+      new NotificationScheduleServiceImpl(std::move(init_aware_scheduler)));
 }
 
 }  // namespace notifications
diff --git a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h
index e64e413..dc63610 100644
--- a/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h
+++ b/chrome/browser/notifications/scheduler/schedule_service_factory_helper.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "components/keyed_service/core/keyed_service.h"
 
@@ -24,7 +25,8 @@
 KeyedService* CreateNotificationScheduleService(
     std::unique_ptr<NotificationBackgroundTaskScheduler>
         background_task_scheduler,
-    leveldb_proto::ProtoDatabaseProvider* db_provider);
+    leveldb_proto::ProtoDatabaseProvider* db_provider,
+    const base::FilePath& storage_dir);
 
 }  // namespace notifications
 
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
index 5beef82..a343d611 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -491,6 +491,13 @@
       .SetAdVideoBytes(aggregate_frame_data_->GetAdNetworkBytesForMime(
                            FrameData::ResourceMimeType::kVideo) >>
                        10);
+
+  // Record cpu metrics for the page.
+  base::TimeDelta total_ad_cpu_time;
+  for (auto const& ad_frame : ad_frames_data_storage_)
+    total_ad_cpu_time += ad_frame.GetTotalCpuUsage();
+  builder.SetAdCpuTime(total_ad_cpu_time.InMilliseconds());
+
   base::TimeTicks current_time = clock_->NowTicks();
   if (!time_commit_.is_null()) {
     int time_since_commit = (current_time - time_commit_).InMicroseconds();
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
index 954f4588..614616ca 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -749,7 +749,8 @@
 // UKM metrics for ad page load are recorded correctly.
 TEST_F(AdsPageLoadMetricsObserverTest, AdPageLoadUKM) {
   ukm::TestAutoSetUkmRecorder ukm_recorder;
-  NavigateMainFrame(kNonAdUrl);
+  RenderFrameHost* main_frame = NavigateMainFrame(kNonAdUrl);
+  RenderFrameHost* ad_frame = CreateAndNavigateSubFrame(kAdUrl, main_frame);
 
   page_load_metrics::mojom::PageLoadTiming timing;
   page_load_metrics::InitPageLoadTimingForTest(&timing);
@@ -767,6 +768,10 @@
   ResourceDataUpdate(main_rfh(), ResourceCached::NOT_CACHED,
                      10 /* resource_size_in_kbyte */,
                      "video/webm" /* mime_type */, true /* is_ad_resource */);
+
+  // Update cpu timings.
+  OnCpuTimingUpdate(ad_frame, base::TimeDelta::FromMilliseconds(500));
+  OnCpuTimingUpdate(main_rfh(), base::TimeDelta::FromMilliseconds(500));
   NavigateMainFrame(kNonAdUrl);
 
   auto entries =
@@ -795,6 +800,9 @@
           entries.front(),
           ukm::builders::AdPageLoad::kAdBytesPerSecondAfterInteractiveName),
       0);
+  EXPECT_EQ(*ukm_recorder.GetEntryMetric(
+                entries.front(), ukm::builders::AdPageLoad::kAdCpuTimeName),
+            500);
 }
 
 TEST_F(AdsPageLoadMetricsObserverTest, TestCpuTimingMetrics) {
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
index 4cefd8942..e79d71e 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.cc
@@ -150,6 +150,13 @@
   return cpu_by_activation_period_[static_cast<int>(status)];
 }
 
+base::TimeDelta FrameData::GetTotalCpuUsage() const {
+  base::TimeDelta total_cpu_time;
+  for (base::TimeDelta cpu_time : cpu_by_interactive_period_)
+    total_cpu_time += cpu_time;
+  return total_cpu_time;
+}
+
 void FrameData::SetReceivedUserActivation(base::TimeDelta foreground_duration) {
   user_activation_status_ = UserActivationStatus::kReceivedActivation;
   pre_activation_foreground_duration_ = foreground_duration;
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
index d3febd02..fb110f4 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/frame_data.h
@@ -122,6 +122,9 @@
   // Get the cpu usage for the appropriate activation period.
   base::TimeDelta GetActivationCpuUsage(UserActivationStatus status) const;
 
+  // Get total cpu usage for the frame.
+  base::TimeDelta GetTotalCpuUsage() const;
+
   // Records that the sticky user activation bit has been set on the frame.
   // Cannot be unset.  Also records the page foreground duration at that time.
   void SetReceivedUserActivation(base::TimeDelta foreground_duration);
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
index e6fcb2f..5dc6705 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -65,6 +65,11 @@
   tester_->SimulateTimingAndMetadataUpdate(timing, metadata);
 }
 
+void PageLoadMetricsObserverTestHarness::SimulateCpuTimingUpdate(
+    const mojom::CpuTiming& cpu_timing) {
+  tester_->SimulateCpuTimingUpdate(cpu_timing);
+}
+
 void PageLoadMetricsObserverTestHarness::SimulateMetadataUpdate(
     const mojom::PageLoadMetadata& metadata,
     content::RenderFrameHost* rfh) {
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
index 7643f21..da0aed4 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -83,6 +83,7 @@
   void SimulateMetadataUpdate(const mojom::PageLoadMetadata& metadata,
                               content::RenderFrameHost* rfh);
   void SimulateFeaturesUpdate(const mojom::PageLoadFeatures& new_features);
+  void SimulateCpuTimingUpdate(const mojom::CpuTiming& cpu_timing);
   void SimulateResourceDataUseUpdate(
       const std::vector<mojom::ResourceDataUpdatePtr>& resources);
   void SimulateResourceDataUseUpdate(
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
index e9e49dd..3c013a4f 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.cc
@@ -373,6 +373,8 @@
         longest_input_timestamp.InMilliseconds());
   }
 
+  builder.SetCpuTime(total_foreground_cpu_time_.InMilliseconds());
+
   // Use a bucket spacing factor of 1.3 for bytes.
   builder.SetNet_CacheBytes(ukm::GetExponentialBucketMin(cache_bytes_, 1.3));
   builder.SetNet_NetworkBytes2(
@@ -578,6 +580,13 @@
                                                  subframe_rfh);
 }
 
+void UkmPageLoadMetricsObserver::OnCpuTimingUpdate(
+    content::RenderFrameHost* subframe_rfh,
+    const page_load_metrics::mojom::CpuTiming& timing) {
+  if (GetDelegate()->GetVisibilityTracker().currently_in_foreground())
+    total_foreground_cpu_time_ += timing.task_time;
+}
+
 void UkmPageLoadMetricsObserver::RecordNoStatePrefetchMetrics(
     content::NavigationHandle* navigation_handle,
     ukm::SourceId source_id) {
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
index e0b1654..aa2905f 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer.h
@@ -84,6 +84,10 @@
       const page_load_metrics::mojom::PageLoadTiming& timing,
       const page_load_metrics::PageLoadExtraInfo& extra_info) override;
 
+  void OnCpuTimingUpdate(
+      content::RenderFrameHost* subframe_rfh,
+      const page_load_metrics::mojom::CpuTiming& timing) override;
+
   // Whether the current page load is an Offline Preview. Must be called from
   // OnCommit. Virtual for testing.
   virtual bool IsOfflinePreview(content::WebContents* web_contents) const;
@@ -136,6 +140,9 @@
   base::Optional<base::TimeDelta> transport_rtt_estimate_;
   base::Optional<int32_t> downstream_kbps_estimate_;
 
+  // Total CPU wall time used by the page while in the foreground.
+  base::TimeDelta total_foreground_cpu_time_;
+
   // Load timing metrics of the main frame resource request.
   base::Optional<net::LoadTimingInfo> main_frame_timing_;
 
diff --git a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
index c774c825..73f9ecb 100644
--- a/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/ukm_page_load_metrics_observer_unittest.cc
@@ -952,6 +952,29 @@
   }
 }
 
+TEST_F(UkmPageLoadMetricsObserverTest, CpuTimeMetrics) {
+  NavigateAndCommit(GURL(kTestUrl1));
+
+  // Simulate some CPU usage.
+  page_load_metrics::mojom::CpuTiming cpu_timing(
+      base::TimeDelta::FromMilliseconds(500));
+  SimulateCpuTimingUpdate(cpu_timing);
+
+  // Simulate closing the tab.
+  DeleteContents();
+
+  std::map<ukm::SourceId, ukm::mojom::UkmEntryPtr> merged_entries =
+      test_ukm_recorder().GetMergedEntriesByName(PageLoad::kEntryName);
+  EXPECT_EQ(1ul, merged_entries.size());
+
+  for (const auto& kv : merged_entries) {
+    test_ukm_recorder().ExpectEntrySourceHasUrl(kv.second.get(),
+                                                GURL(kTestUrl1));
+    test_ukm_recorder().ExpectEntryMetric(kv.second.get(),
+                                          PageLoad::kCpuTimeName, 500);
+  }
+}
+
 TEST_F(UkmPageLoadMetricsObserverTest, LayoutStability) {
   NavigateAndCommit(GURL(kTestUrl1));
 
diff --git a/chrome/browser/policy/schema_registry_service_profile_builder.cc b/chrome/browser/policy/schema_registry_service_builder.cc
similarity index 88%
rename from chrome/browser/policy/schema_registry_service_profile_builder.cc
rename to chrome/browser/policy/schema_registry_service_builder.cc
index f6cd70779..e769c0a9 100644
--- a/chrome/browser/policy/schema_registry_service_profile_builder.cc
+++ b/chrome/browser/policy/schema_registry_service_builder.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/policy/schema_registry_service_profile_builder.h"
+#include "chrome/browser/policy/schema_registry_service_builder.h"
 
 #include <utility>
 
@@ -103,9 +103,16 @@
   }
 #endif
 
-  std::unique_ptr<SchemaRegistryService> service(new SchemaRegistryService(
-      std::move(registry), chrome_schema, global_registry));
-  return service;
+  return BuildSchemaRegistryService(std::move(registry), chrome_schema,
+                                    global_registry);
+}
+
+std::unique_ptr<SchemaRegistryService> BuildSchemaRegistryService(
+    std::unique_ptr<SchemaRegistry> registry,
+    const Schema& chrome_schema,
+    CombinedSchemaRegistry* global_registry) {
+  return std::make_unique<SchemaRegistryService>(
+      std::move(registry), chrome_schema, global_registry);
 }
 
 }  // namespace policy
diff --git a/chrome/browser/policy/schema_registry_service_builder.h b/chrome/browser/policy/schema_registry_service_builder.h
new file mode 100644
index 0000000..e78f11a
--- /dev/null
+++ b/chrome/browser/policy/schema_registry_service_builder.h
@@ -0,0 +1,37 @@
+// 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 CHROME_BROWSER_POLICY_SCHEMA_REGISTRY_SERVICE_BUILDER_H_
+#define CHROME_BROWSER_POLICY_SCHEMA_REGISTRY_SERVICE_BUILDER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace policy {
+
+class CombinedSchemaRegistry;
+class Schema;
+class SchemaRegistryService;
+class SchemaRegistry;
+
+// Creates SchemaRegistryService for BrowserContexts.
+std::unique_ptr<SchemaRegistryService> BuildSchemaRegistryServiceForProfile(
+    content::BrowserContext* context,
+    const Schema& chrome_schema,
+    CombinedSchemaRegistry* global_registry);
+
+// Creates SchemaRegistryService without BrowserContext.
+std::unique_ptr<SchemaRegistryService> BuildSchemaRegistryService(
+    std::unique_ptr<SchemaRegistry> registry,
+    const Schema& chrome_schema,
+    CombinedSchemaRegistry* global_registry);
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_POLICY_SCHEMA_REGISTRY_SERVICE_BUILDER_H_
diff --git a/chrome/browser/policy/schema_registry_service_profile_builder.h b/chrome/browser/policy/schema_registry_service_profile_builder.h
deleted file mode 100644
index 443f5e3..0000000
--- a/chrome/browser/policy/schema_registry_service_profile_builder.h
+++ /dev/null
@@ -1,30 +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 CHROME_BROWSER_POLICY_SCHEMA_REGISTRY_SERVICE_PROFILE_BUILDER_H_
-#define CHROME_BROWSER_POLICY_SCHEMA_REGISTRY_SERVICE_PROFILE_BUILDER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace policy {
-
-class CombinedSchemaRegistry;
-class Schema;
-class SchemaRegistryService;
-
-// Creates SchemaRegistryServices for BrowserContexts.
-std::unique_ptr<SchemaRegistryService> BuildSchemaRegistryServiceForProfile(
-    content::BrowserContext* context,
-    const Schema& chrome_schema,
-    CombinedSchemaRegistry* global_registry);
-
-}  // namespace policy
-
-#endif  // CHROME_BROWSER_POLICY_SCHEMA_REGISTRY_SERVICE_PROFILE_BUILDER_H_
diff --git a/chrome/browser/previews/previews_content_util.cc b/chrome/browser/previews/previews_content_util.cc
index cafbb0e..9643b45 100644
--- a/chrome/browser/previews/previews_content_util.cc
+++ b/chrome/browser/previews/previews_content_util.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
+#include "base/rand_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/content_settings/cookie_settings_factory.h"
 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_chrome_settings.h"
@@ -22,6 +23,7 @@
 #include "chrome/browser/previews/previews_offline_helper.h"
 #include "chrome/browser/previews/previews_service.h"
 #include "chrome/browser/previews/previews_service_factory.h"
+#include "chrome/browser/previews/previews_ui_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_host/chrome_navigation_ui_data.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
@@ -432,6 +434,92 @@
   return content::PREVIEWS_OFF;
 }
 
+namespace {
+// This bit mask is all the preview types we should potentially holdback on
+// before commit.
+content::PreviewsState kPreCommitPreviews =
+    content::SERVER_LOFI_ON | content::SERVER_LITE_PAGE_ON |
+    content::OFFLINE_PAGE_ON | content::LITE_PAGE_REDIRECT_ON;
+}  // namespace
+
+content::PreviewsState MaybeCoinFlipHoldbackBeforeCommit(
+    content::PreviewsState initial_state,
+    content::NavigationHandle* navigation_handle) {
+  if (!base::FeatureList::IsEnabled(features::kCoinFlipHoldback))
+    return initial_state;
+
+  // Get PreviewsUserData to store the result of the coin flip. If it can't be
+  // gotten, return early.
+  PreviewsUITabHelper* ui_tab_helper =
+      PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
+  PreviewsUserData* previews_data =
+      ui_tab_helper ? ui_tab_helper->GetPreviewsUserData(navigation_handle)
+                    : nullptr;
+  if (!previews_data)
+    return initial_state;
+
+  // It is possible that any number of at-commit-decided previews are enabled,
+  // but do not hold them back until the commit time logic runs.
+  if (!HasEnabledPreviews(initial_state & kPreCommitPreviews))
+    return initial_state;
+
+  if (previews_data->random_coin_flip_for_navigation() ||
+      params::ShouldOverrideCoinFlipHoldbackResult()) {
+    // Holdback all previews. It is possible that some number of client previews
+    // will also be held back here. However, since a before-commit preview was
+    // likely, we turn off all of them to make analysis simpler and this code
+    // more robust.
+    previews_data->set_coin_flip_holdback_result(
+        CoinFlipHoldbackResult::kHoldback);
+    return content::PREVIEWS_OFF;
+  }
+
+  previews_data->set_coin_flip_holdback_result(
+      CoinFlipHoldbackResult::kAllowed);
+  return initial_state;
+}
+
+content::PreviewsState MaybeCoinFlipHoldbackAfterCommit(
+    content::PreviewsState initial_state,
+    content::NavigationHandle* navigation_handle) {
+  if (!base::FeatureList::IsEnabled(features::kCoinFlipHoldback))
+    return initial_state;
+
+  // Get PreviewsUserData to store the result of the coin flip. If it can't be
+  // gotten, return early.
+  PreviewsUITabHelper* ui_tab_helper =
+      PreviewsUITabHelper::FromWebContents(navigation_handle->GetWebContents());
+  PreviewsUserData* previews_data =
+      ui_tab_helper ? ui_tab_helper->GetPreviewsUserData(navigation_handle)
+                    : nullptr;
+  if (!previews_data)
+    return initial_state;
+
+  if (!HasEnabledPreviews(initial_state)) {
+    return initial_state;
+  }
+
+  if (previews_data->random_coin_flip_for_navigation() ||
+      params::ShouldOverrideCoinFlipHoldbackResult()) {
+    // No pre-commit previews should be set, since such a preview would have
+    // already committed and we don't want to incorrectly clear that state. If
+    // it did, at least make everything functionally correct.
+    if (HasEnabledPreviews(initial_state & kPreCommitPreviews)) {
+      NOTREACHED();
+      previews_data->set_coin_flip_holdback_result(
+          CoinFlipHoldbackResult::kNotSet);
+      return initial_state;
+    }
+    previews_data->set_coin_flip_holdback_result(
+        CoinFlipHoldbackResult::kHoldback);
+    return content::PREVIEWS_OFF;
+  }
+
+  previews_data->set_coin_flip_holdback_result(
+      CoinFlipHoldbackResult::kAllowed);
+  return initial_state;
+}
+
 previews::PreviewsType GetMainFramePreviewsType(
     content::PreviewsState previews_state) {
   // The order is important here.
diff --git a/chrome/browser/previews/previews_content_util.h b/chrome/browser/previews/previews_content_util.h
index c47f434..aac90612 100644
--- a/chrome/browser/previews/previews_content_util.h
+++ b/chrome/browser/previews/previews_content_util.h
@@ -31,6 +31,14 @@
     previews::PreviewsDecider* previews_decider,
     content::NavigationHandle* navigation_handle);
 
+// If this Chrome session is in a coin flip holdback, possibly modify the
+// previews state of the navigation according to a random coin flip. This method
+// should only be called before commit (at navigation start or redirect) and
+// will only impact previews that are decided before commit.
+content::PreviewsState MaybeCoinFlipHoldbackBeforeCommit(
+    content::PreviewsState initial_state,
+    content::NavigationHandle* navigation_handle);
+
 // Returns an updated PreviewsState given |previews_state| that has already
 // been updated wrt server previews. This should be called at Navigation Commit
 // time. It will defer to any server preview set, otherwise it chooses which
@@ -42,6 +50,15 @@
     const previews::PreviewsDecider* previews_decider,
     content::NavigationHandle* navigation_handle);
 
+// If this Chrome session is in a coin flip holdback, possibly modify the
+// previews state of the navigation according to a random coin flip. This method
+// should only be called after commit and may impact all preview types. This
+// method assume |MaybeCoinFlipHoldbackBeforeCommit| has already been called
+// with the same |navigation_handle|.
+content::PreviewsState MaybeCoinFlipHoldbackAfterCommit(
+    content::PreviewsState initial_state,
+    content::NavigationHandle* navigation_handle);
+
 // Returns the effective PreviewsType known on a main frame basis given the
 // |previews_state| bitmask for the committed main frame. This uses the same
 // previews precendence consideration as |DetermineCommittedClientPreviewsState|
diff --git a/chrome/browser/previews/previews_content_util_unittest.cc b/chrome/browser/previews/previews_content_util_unittest.cc
index 9fbf7f5..894bde2 100644
--- a/chrome/browser/previews/previews_content_util_unittest.cc
+++ b/chrome/browser/previews/previews_content_util_unittest.cc
@@ -7,14 +7,20 @@
 #include <memory>
 #include <vector>
 
+#include "base/test/gtest_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
+#include "chrome/browser/previews/previews_ui_tab_helper.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/previews/content/previews_user_data.h"
 #include "components/previews/core/previews_experiments.h"
 #include "components/previews/core/previews_features.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/previews_state.h"
 #include "content/public/test/mock_navigation_handle.h"
+#include "content/public/test/navigation_simulator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -530,6 +536,315 @@
           content::RESOURCE_LOADING_HINTS_ON | content::LITE_PAGE_REDIRECT_ON));
 }
 
+class PreviewsContentSimulatedNavigationTest
+    : public ChromeRenderViewHostTestHarness {
+ public:
+  void SetUp() override {
+    ChromeRenderViewHostTestHarness::SetUp();
+    PreviewsUITabHelper::CreateForWebContents(web_contents());
+  }
+
+  previews::PreviewsUserData* GetPreviewsUserData(
+      content::NavigationHandle* handle) {
+    PreviewsUITabHelper* tab_helper =
+        PreviewsUITabHelper::FromWebContents(web_contents());
+    return tab_helper->GetPreviewsUserData(handle);
+  }
+
+  content::NavigationHandle* StartNavigation() {
+    navigation_simulator_ =
+        content::NavigationSimulator::CreateBrowserInitiated(
+            GURL("https://test.com"), web_contents());
+    navigation_simulator_->Start();
+
+    PreviewsUITabHelper* tab_helper =
+        PreviewsUITabHelper::FromWebContents(web_contents());
+    tab_helper->CreatePreviewsUserDataForNavigationHandle(
+        navigation_simulator_->GetNavigationHandle(), 1);
+
+    return navigation_simulator_->GetNavigationHandle();
+  }
+
+  content::NavigationHandle* StartNavigationAndReadyCommit() {
+    navigation_simulator_ =
+        content::NavigationSimulator::CreateBrowserInitiated(
+            GURL("https://test.com"), web_contents());
+    navigation_simulator_->Start();
+
+    PreviewsUITabHelper* tab_helper =
+        PreviewsUITabHelper::FromWebContents(web_contents());
+    tab_helper->CreatePreviewsUserDataForNavigationHandle(
+        navigation_simulator_->GetNavigationHandle(), 1);
+
+    navigation_simulator_->ReadyToCommit();
+    return navigation_simulator_->GetNavigationHandle();
+  }
+
+ private:
+  std::unique_ptr<content::NavigationSimulator> navigation_simulator_;
+};
+
+TEST_F(PreviewsContentSimulatedNavigationTest, TestCoinFlipBeforeCommit) {
+  struct TestCase {
+    std::string msg;
+    bool enable_feature;
+    // True maps to previews::CoinFlipHoldbackResult::kHoldback.
+    bool set_random_coin_flip_for_navigation;
+    bool set_coin_flip_override;
+    previews::CoinFlipHoldbackResult want_coin_flip_result;
+    content::PreviewsState initial_state;
+    content::PreviewsState want_returned;
+  };
+  const TestCase kTestCases[]{
+      {
+          .msg = "Feature disabled, no affect, heads",
+          .enable_feature = false,
+          .set_random_coin_flip_for_navigation = true,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "Feature disabled, no affect, tails",
+          .enable_feature = false,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "Feature disabled, no affect, forced override",
+          .enable_feature = false,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = true,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "After-commit decided previews are not affected before commit "
+                 "on true coin flip",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = true,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "After-commit decided previews are not affected before commit "
+                 "on forced override",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = true,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "After-commit decided previews are not affected before commit "
+                 "on false coin flip",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg =
+              "Before-commit decided previews are affected on true coin flip",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = true,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
+          .initial_state = content::OFFLINE_PAGE_ON,
+          .want_returned = content::PREVIEWS_OFF,
+      },
+      {
+          .msg =
+              "Before-commit decided previews are affected on forced override",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = true,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
+          .initial_state = content::OFFLINE_PAGE_ON,
+          .want_returned = content::PREVIEWS_OFF,
+      },
+      {
+          .msg = "Before-commit decided previews are logged on false coin flip",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kAllowed,
+          .initial_state = content::OFFLINE_PAGE_ON,
+          .want_returned = content::OFFLINE_PAGE_ON,
+      },
+      {
+          .msg =
+              "True coin flip impacts both pre and post commit previews when "
+              "both exist",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = true,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
+          .initial_state = content::OFFLINE_PAGE_ON | content::CLIENT_LOFI_ON,
+          .want_returned = content::PREVIEWS_OFF,
+      },
+      {
+          .msg =
+              "Forced override impacts both pre and post commit previews when "
+              "both exist",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = true,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
+          .initial_state = content::OFFLINE_PAGE_ON | content::CLIENT_LOFI_ON,
+          .want_returned = content::PREVIEWS_OFF,
+      },
+      {
+          .msg = "False coin flip logs both pre and post commit previews when "
+                 "both exist",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kAllowed,
+          .initial_state = content::OFFLINE_PAGE_ON | content::CLIENT_LOFI_ON,
+          .want_returned = content::OFFLINE_PAGE_ON | content::CLIENT_LOFI_ON,
+      },
+  };
+
+  for (const TestCase& test_case : kTestCases) {
+    SCOPED_TRACE(test_case.msg);
+
+    // Starting the navigation will cause content to call into
+    // |MaybeCoinFlipHoldbackBeforeCommit| as part of the navigation simulation.
+    // So don't enable the feature until afterwards.
+    content::NavigationHandle* handle = StartNavigation();
+
+    GetPreviewsUserData(handle)->SetRandomCoinFlipForNavigationForTesting(
+        test_case.set_random_coin_flip_for_navigation);
+
+    base::test::ScopedFeatureList scoped_feature_list;
+    if (test_case.enable_feature) {
+      scoped_feature_list.InitAndEnableFeatureWithParameters(
+          previews::features::kCoinFlipHoldback,
+          {{"force_coin_flip_always_holdback",
+            test_case.set_coin_flip_override ? "true" : "false"}});
+    } else {
+      scoped_feature_list.InitAndDisableFeature(
+          previews::features::kCoinFlipHoldback);
+    }
+
+    content::PreviewsState returned =
+        MaybeCoinFlipHoldbackBeforeCommit(test_case.initial_state, handle);
+
+    EXPECT_EQ(test_case.want_returned, returned);
+    EXPECT_EQ(test_case.want_coin_flip_result,
+              GetPreviewsUserData(handle)->coin_flip_holdback_result());
+  }
+}
+
+TEST_F(PreviewsContentSimulatedNavigationTest, TestCoinFlipAfterCommit) {
+  struct TestCase {
+    std::string msg;
+    bool enable_feature;
+    bool set_random_coin_flip_for_navigation;
+    bool set_coin_flip_override;
+    previews::CoinFlipHoldbackResult want_coin_flip_result;
+    content::PreviewsState initial_state;
+    content::PreviewsState want_returned;
+  };
+  const TestCase kTestCases[]{
+      {
+          .msg = "Feature disabled, no affect, heads",
+          .enable_feature = false,
+          .set_random_coin_flip_for_navigation = true,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "Feature disabled, no affect, tails",
+          .enable_feature = false,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "Feature disabled, no affect, forced override",
+          .enable_feature = false,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = true,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kNotSet,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+      {
+          .msg = "Holdback enabled previews",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = true,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::PREVIEWS_OFF,
+      },
+      {
+          .msg = "Holdback enabled previews via override",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = true,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kHoldback,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::PREVIEWS_OFF,
+      },
+      {
+          .msg = "Log enabled previews",
+          .enable_feature = true,
+          .set_random_coin_flip_for_navigation = false,
+          .set_coin_flip_override = false,
+          .want_coin_flip_result = previews::CoinFlipHoldbackResult::kAllowed,
+          .initial_state = content::CLIENT_LOFI_ON,
+          .want_returned = content::CLIENT_LOFI_ON,
+      },
+  };
+
+  for (const TestCase& test_case : kTestCases) {
+    SCOPED_TRACE(test_case.msg);
+
+    // Starting the navigation will cause content to call into
+    // |MaybeCoinFlipHoldbackBeforeCommit| as part of the navigation simulation.
+    // So don't enable the feature until afterwards.
+    content::NavigationHandle* handle = StartNavigationAndReadyCommit();
+
+    GetPreviewsUserData(handle)->SetRandomCoinFlipForNavigationForTesting(
+        test_case.set_random_coin_flip_for_navigation);
+
+    base::test::ScopedFeatureList scoped_feature_list;
+    if (test_case.enable_feature) {
+      scoped_feature_list.InitAndEnableFeatureWithParameters(
+          previews::features::kCoinFlipHoldback,
+          {{"force_coin_flip_always_holdback",
+            test_case.set_coin_flip_override ? "true" : "false"}});
+    } else {
+      scoped_feature_list.InitAndDisableFeature(
+          previews::features::kCoinFlipHoldback);
+    }
+
+    content::PreviewsState returned =
+        MaybeCoinFlipHoldbackAfterCommit(test_case.initial_state, handle);
+
+    EXPECT_EQ(test_case.want_returned, returned);
+    EXPECT_EQ(test_case.want_coin_flip_result,
+              GetPreviewsUserData(handle)->coin_flip_holdback_result());
+  }
+}
+
 }  // namespace
 
 }  // namespace previews
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index ea38c1592..7b8ae58 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -400,10 +400,17 @@
   return nullptr;
 }
 
+policy::SchemaRegistryService*
+OffTheRecordProfileImpl::GetPolicySchemaRegistryService() {
+  return nullptr;
+}
+
+#if !defined(OS_CHROMEOS)
 policy::UserCloudPolicyManager*
 OffTheRecordProfileImpl::GetUserCloudPolicyManager() {
   return GetOriginalProfile()->GetUserCloudPolicyManager();
 }
+#endif
 
 net::URLRequestContextGetter* OffTheRecordProfileImpl::GetRequestContext() {
   return GetDefaultStoragePartition(this)->GetURLRequestContext();
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 183c07c..e13314c3 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -57,7 +57,10 @@
   PrefService* GetPrefs() override;
   const PrefService* GetPrefs() const override;
   PrefService* GetOffTheRecordPrefs() override;
+  policy::SchemaRegistryService* GetPolicySchemaRegistryService() override;
+#if !defined(OS_CHROMEOS)
   policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override;
+#endif
   net::URLRequestContextGetter* GetRequestContext() override;
   base::OnceCallback<net::CookieStore*()> GetExtensionsCookieStoreGetter()
       override;
diff --git a/chrome/browser/profiles/pref_service_builder_utils.cc b/chrome/browser/profiles/pref_service_builder_utils.cc
new file mode 100644
index 0000000..87f373a
--- /dev/null
+++ b/chrome/browser/profiles/pref_service_builder_utils.cc
@@ -0,0 +1,115 @@
+// 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 "chrome/browser/profiles/pref_service_builder_utils.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/scoped_blocking_call.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/policy/chrome_browser_policy_connector.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/chrome_pref_service_factory.h"
+#include "chrome/browser/prefs/in_process_service_factory_factory.h"
+#include "chrome/browser/prefs/profile_pref_store_manager.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/grit/chromium_strings.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_keyed_service_factory.h"
+#include "components/policy/core/common/cloud/cloud_policy_manager.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_value_store.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "content/public/browser/network_service_instance.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
+#include "ui/base/l10n/l10n_util.h"
+
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+#include "chrome/browser/content_settings/content_settings_supervised_provider.h"
+#include "chrome/browser/supervised_user/supervised_user_constants.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
+#endif
+
+namespace {
+
+// Text content of README file created in each profile directory. Both %s
+// placeholders must contain the product name. This is not localizable and hence
+// not in resources.
+const char kReadmeText[] =
+    "%s settings and storage represent user-selected preferences and "
+    "information and MUST not be extracted, overwritten or modified except "
+    "through %s defined APIs.";
+
+}  // namespace
+
+void CreateProfileReadme(const base::FilePath& profile_path) {
+  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
+                                                base::BlockingType::MAY_BLOCK);
+  base::FilePath readme_path = profile_path.Append(chrome::kReadmeFilename);
+  std::string product_name = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
+  std::string readme_text = base::StringPrintf(
+      kReadmeText, product_name.c_str(), product_name.c_str());
+  if (base::WriteFile(readme_path, readme_text.data(), readme_text.size()) ==
+      -1) {
+    LOG(ERROR) << "Could not create README file.";
+  }
+}
+
+void RegisterProfilePrefs(bool is_signin_profile,
+                          const std::string& locale,
+                          user_prefs::PrefRegistrySyncable* pref_registry) {
+#if defined(OS_CHROMEOS)
+  if (is_signin_profile)
+    RegisterLoginProfilePrefs(pref_registry);
+  else
+#endif
+    RegisterUserProfilePrefs(pref_registry, locale);
+
+  SimpleDependencyManager::GetInstance()->RegisterProfilePrefsForServices(
+      pref_registry);
+  BrowserContextDependencyManager::GetInstance()
+      ->RegisterProfilePrefsForServices(pref_registry);
+}
+
+std::unique_ptr<sync_preferences::PrefServiceSyncable> CreatePrefService(
+    scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
+    PrefStore* extension_pref_store,
+    policy::PolicyService* policy_service,
+    policy::ChromeBrowserPolicyConnector* browser_policy_connector,
+    prefs::mojom::TrackedPreferenceValidationDelegatePtr
+        pref_validation_delegate,
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    SimpleFactoryKey* key,
+    const base::FilePath& path,
+    bool async_prefs) {
+  SupervisedUserSettingsService* supervised_user_settings = nullptr;
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+  supervised_user_settings =
+      SupervisedUserSettingsServiceFactory::GetForKey(key);
+  supervised_user_settings->Init(path, io_task_runner.get(), !async_prefs);
+#endif
+  {
+    std::unique_ptr<PrefValueStore::Delegate> delegate =
+        InProcessPrefServiceFactoryFactory::GetInstanceForKey(key)
+            ->CreateDelegate();
+    delegate->InitPrefRegistry(pref_registry.get());
+    return chrome_prefs::CreateProfilePrefs(
+        path, std::move(pref_validation_delegate), policy_service,
+        supervised_user_settings, extension_pref_store, pref_registry,
+        browser_policy_connector, async_prefs, io_task_runner,
+        std::move(delegate));
+  }
+}
diff --git a/chrome/browser/profiles/pref_service_builder_utils.h b/chrome/browser/profiles/pref_service_builder_utils.h
new file mode 100644
index 0000000..e07374b
--- /dev/null
+++ b/chrome/browser/profiles/pref_service_builder_utils.h
@@ -0,0 +1,62 @@
+// 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 CHROME_BROWSER_PROFILES_PREF_SERVICE_BUILDER_UTILS_H_
+#define CHROME_BROWSER_PROFILES_PREF_SERVICE_BUILDER_UTILS_H_
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "build/build_config.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
+
+class PrefStore;
+class SimpleFactoryKey;
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace policy {
+class PolicyService;
+class ChromeBrowserPolicyConnector;
+}  // namespace policy
+
+namespace sync_preferences {
+class PrefServiceSyncable;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+// This file includes multiple helper functions to create the Profile's
+// PrefService. Note: please update all of the callers if updating any helper
+// function. Currently, these code are called in both ProfileImpl and
+// StartupData.
+
+void CreateProfileReadme(const base::FilePath& profile_path);
+
+// Called to register all of the prefs before creating the PrefService.
+void RegisterProfilePrefs(bool is_signin_profile,
+                          const std::string& locale,
+                          user_prefs::PrefRegistrySyncable* pref_registry);
+
+// Creates the PrefService.
+std::unique_ptr<sync_preferences::PrefServiceSyncable> CreatePrefService(
+    scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
+    PrefStore* extension_pref_store,
+    policy::PolicyService* policy_service,
+    policy::ChromeBrowserPolicyConnector* browser_policy_connector,
+    prefs::mojom::TrackedPreferenceValidationDelegatePtr
+        pref_validation_delegate,
+    scoped_refptr<base::SequencedTaskRunner> io_task_runner,
+    SimpleFactoryKey* key,
+    const base::FilePath& path,
+    bool async_prefs);
+
+#endif  // CHROME_BROWSER_PROFILES_PREF_SERVICE_BUILDER_UTILS_H_
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index b44d79d..757722fb 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -129,14 +129,6 @@
   return GetOffTheRecordPrefs();
 }
 
-policy::SchemaRegistryService* Profile::GetPolicySchemaRegistryService() {
-  return nullptr;
-}
-
-policy::UserCloudPolicyManager* Profile::GetUserCloudPolicyManager() {
-  return nullptr;
-}
-
 Profile::Delegate::~Delegate() {
 }
 
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 450560d..19f29aa4 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -233,10 +233,14 @@
   virtual ProfileKey* GetProfileKey() const = 0;
 
   // Returns the SchemaRegistryService.
-  virtual policy::SchemaRegistryService* GetPolicySchemaRegistryService();
+  virtual policy::SchemaRegistryService* GetPolicySchemaRegistryService() = 0;
 
+// In Chrome OS, use UserPolicyManagerFactoryChromeOS::GetCloudPolicyManager()
+// instead.
+#if !defined(OS_CHROMEOS)
   // Returns the UserCloudPolicyManager.
-  virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager();
+  virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() = 0;
+#endif
 
   virtual policy::ProfilePolicyConnector* GetProfilePolicyConnector() = 0;
   virtual const policy::ProfilePolicyConnector* GetProfilePolicyConnector()
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 732378e..c8d5dca 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -64,15 +64,17 @@
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_builder.h"
 #include "chrome/browser/policy/schema_registry_service.h"
-#include "chrome/browser/policy/schema_registry_service_profile_builder.h"
+#include "chrome/browser/policy/schema_registry_service_builder.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/chrome_pref_service_factory.h"
 #include "chrome/browser/prefs/in_process_service_factory_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
+#include "chrome/browser/prefs/profile_pref_store_manager.h"
 #include "chrome/browser/prerender/prerender_manager_factory.h"
 #include "chrome/browser/profiles/bookmark_model_loaded_observer.h"
 #include "chrome/browser/profiles/chrome_version_service.h"
 #include "chrome/browser/profiles/gaia_info_update_service_factory.h"
+#include "chrome/browser/profiles/pref_service_builder_utils.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_destroyer.h"
@@ -88,6 +90,7 @@
 #include "chrome/browser/site_isolation/site_isolation_policy.h"
 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h"
+#include "chrome/browser/startup_data.h"
 #include "chrome/browser/transition_manager/full_browser_transition_manager.h"
 #include "chrome/browser/ui/startup/startup_browser_creator.h"
 #include "chrome/browser/ui/webui/prefs_internals_source.h"
@@ -117,6 +120,7 @@
 #include "components/metrics/metrics_service.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/policy/core/common/cloud/cloud_policy_manager.h"
+#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/signin/core/browser/signin_pref_names.h"
@@ -195,7 +199,9 @@
 
 #endif
 
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+#include "chrome/browser/android/profile_key_startup_accessor.h"
+#else
 #include "chrome/services/app_service/app_service.h"
 #include "chrome/services/app_service/public/mojom/constants.mojom.h"
 #include "components/zoom/zoom_event_manager.h"
@@ -242,14 +248,6 @@
 const int kCreateSessionServiceDelayMS = 500;
 #endif
 
-// Text content of README file created in each profile directory. Both %s
-// placeholders must contain the product name. This is not localizable and hence
-// not in resources.
-const char kReadmeText[] =
-    "%s settings and storage represent user-selected preferences and "
-    "information and MUST not be extracted, overwritten or modified except "
-    "through %s defined APIs.";
-
 // Value written to prefs for EXIT_CRASHED and EXIT_SESSION_ENDED.
 const char kPrefExitTypeCrashed[] = "Crashed";
 const char kPrefExitTypeSessionEnded[] = "SessionEnded";
@@ -261,19 +259,6 @@
   return google_apis::GetNonStableAPIKey();
 }
 
-void CreateProfileReadme(const base::FilePath& profile_path) {
-  base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
-                                                base::BlockingType::MAY_BLOCK);
-  base::FilePath readme_path = profile_path.Append(chrome::kReadmeFilename);
-  std::string product_name = l10n_util::GetStringUTF8(IDS_PRODUCT_NAME);
-  std::string readme_text = base::StringPrintf(
-      kReadmeText, product_name.c_str(), product_name.c_str());
-  if (base::WriteFile(readme_path, readme_text.data(), readme_text.size()) ==
-      -1) {
-    LOG(ERROR) << "Could not create README file.";
-  }
-}
-
 // Creates the profile directory synchronously if it doesn't exist. If
 // |create_readme| is true, the profile README will be created asynchronously in
 // the profile directory.
@@ -466,11 +451,9 @@
     scoped_refptr<base::SequencedTaskRunner> io_task_runner)
     : path_(path),
       io_task_runner_(std::move(io_task_runner)),
-      pref_registry_(new user_prefs::PrefRegistrySyncable),
       io_data_(this),
       last_session_exit_type_(EXIT_NORMAL),
       start_time_(base::Time::Now()),
-      key_(std::make_unique<ProfileKey>(GetPath())),
       delegate_(delegate),
       reporting_permissions_checker_factory_(this),
       shared_cors_origin_access_list_(
@@ -479,9 +462,6 @@
   DCHECK(!path.empty()) << "Using an empty path will attempt to write "
                         << "profile files to the root directory!";
 
-  // TODO(hanxi): get |key_| from the startup data if it has already been
-  // created when this profile is created.
-
 #if defined(OS_CHROMEOS)
   const bool is_regular_profile =
       !chromeos::ProfileHelper::IsSigninProfile(this) &&
@@ -510,14 +490,88 @@
   set_is_guest_profile(path == ProfileManager::GetGuestProfilePath());
   set_is_system_profile(path == ProfileManager::GetSystemProfilePath());
 
-  policy::BrowserPolicyConnector* connector =
+  // The ProfileImpl can be created both synchronously and asynchronously.
+  bool async_prefs = create_mode == CREATE_MODE_ASYNCHRONOUS;
+
+#if defined(OS_ANDROID)
+  auto* startup_data = g_browser_process->startup_data();
+  DCHECK(startup_data && startup_data->GetProfileKey());
+  TakePrefsFromStartupData();
+  async_prefs = false;
+#else
+  LoadPrefsForNormalStartup(async_prefs);
+#endif
+
+  content::BrowserContext::Initialize(this, path_);
+
+  // Register on BrowserContext.
+  user_prefs::UserPrefs::Set(this, prefs_.get());
+
+  SimpleKeyMap::GetInstance()->Associate(this, key_.get());
+
+#if defined(OS_CHROMEOS)
+  if (is_regular_profile) {
+    chromeos::AccountManagerFactory* factory =
+        g_browser_process->platform_part()->GetAccountManagerFactory();
+    chromeos::AccountManager* account_manager =
+        factory->GetAccountManager(path_.value());
+    account_manager->Initialize(
+        path_,
+        g_browser_process->system_network_context_manager()
+            ->GetSharedURLLoaderFactory(),
+        base::BindRepeating(&chromeos::DelayNetworkCall,
+                            base::TimeDelta::FromMilliseconds(
+                                chromeos::kDefaultNetworkRetryDelayMS)),
+        GetPrefs());
+  }
+#endif
+
+  if (async_prefs) {
+    // Wait for the notification that prefs has been loaded
+    // (successfully or not).  Note that we can use base::Unretained
+    // because the PrefService is owned by this class and lives on
+    // the same thread.
+    prefs_->AddPrefInitObserver(base::BindOnce(
+        &ProfileImpl::OnPrefsLoaded, base::Unretained(this), create_mode));
+  } else {
+    // Prefs were loaded synchronously so we can continue directly.
+    OnPrefsLoaded(create_mode, true);
+  }
+}
+
+#if defined(OS_ANDROID)
+void ProfileImpl::TakePrefsFromStartupData() {
+  auto* startup_data = g_browser_process->startup_data();
+
+  // On Android, it is possible that the ProfileKey has been build before the
+  // ProfileImpl is created. The ownership of all these pre-created objects
+  // will be taken by ProfileImpl.
+  key_ = startup_data->TakeProfileKey();
+  prefs_ = startup_data->TakeProfilePrefService();
+  schema_registry_service_ = startup_data->TakeSchemaRegistryService();
+  configuration_policy_provider_ =
+      startup_data->TakeConfigurationPolicyProvider();
+  user_cloud_policy_manager_ = static_cast<policy::UserCloudPolicyManager*>(
+      configuration_policy_provider_.get());
+  profile_policy_connector_ = startup_data->TakeProfilePolicyConnector();
+  pref_registry_ = startup_data->TakePrefRegistrySyncable();
+
+  ProfileKeyStartupAccessor::GetInstance()->Reset();
+}
+#endif
+
+void ProfileImpl::LoadPrefsForNormalStartup(bool async_prefs) {
+  key_ = std::make_unique<ProfileKey>(GetPath());
+  pref_registry_ = base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
+
+  policy::ChromeBrowserPolicyConnector* connector =
       g_browser_process->browser_policy_connector();
   schema_registry_service_ = BuildSchemaRegistryServiceForProfile(
       this, connector->GetChromeSchema(), connector->GetSchemaRegistry());
 
   // If we are creating the profile synchronously, then we should load the
   // policy data immediately.
-  bool force_immediate_policy_load = (create_mode == CREATE_MODE_SYNCHRONOUS);
+  bool force_immediate_policy_load = !async_prefs;
 
 #if defined(OS_CHROMEOS)
   if (force_immediate_policy_load)
@@ -541,33 +595,17 @@
           g_browser_process->browser_policy_connector(),
           force_immediate_policy_load, this);
 
-  DCHECK(create_mode == CREATE_MODE_ASYNCHRONOUS ||
-         create_mode == CREATE_MODE_SYNCHRONOUS);
-  bool async_prefs = create_mode == CREATE_MODE_ASYNCHRONOUS;
-
+  bool is_signin_profile = false;
 #if defined(OS_CHROMEOS)
-  if (chromeos::ProfileHelper::IsSigninProfile(this))
-    RegisterLoginProfilePrefs(pref_registry_.get());
-  else
+  is_signin_profile = chromeos::ProfileHelper::IsSigninProfile(this);
 #endif
-    RegisterUserProfilePrefs(pref_registry_.get());
+  ::RegisterProfilePrefs(is_signin_profile,
+                         g_browser_process->GetApplicationLocale(),
+                         pref_registry_.get());
 
-  SimpleDependencyManager::GetInstance()->RegisterProfilePrefsForServices(
-      pref_registry_.get());
-  BrowserContextDependencyManager::GetInstance()
-      ->RegisterProfilePrefsForServices(pref_registry_.get());
-
-  SupervisedUserSettingsService* supervised_user_settings = nullptr;
-#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-  supervised_user_settings =
-      SupervisedUserSettingsServiceFactory::GetForKey(key_.get());
-  supervised_user_settings->Init(path_, io_task_runner_.get(),
-                                 create_mode == CREATE_MODE_SYNCHRONOUS);
-#endif
-
+  prefs::mojom::TrackedPreferenceValidationDelegatePtr pref_validation_delegate;
   scoped_refptr<safe_browsing::SafeBrowsingService> safe_browsing_service(
       g_browser_process->safe_browsing_service());
-  prefs::mojom::TrackedPreferenceValidationDelegatePtr pref_validation_delegate;
   if (safe_browsing_service.get()) {
     auto pref_validation_delegate_impl =
         safe_browsing_service->CreatePreferenceValidationDelegate(this);
@@ -577,53 +615,13 @@
     }
   }
 
-  content::BrowserContext::Initialize(this, path_);
-
-  {
-    auto delegate =
-        InProcessPrefServiceFactoryFactory::GetInstanceForKey(key_.get())
-            ->CreateDelegate();
-    delegate->InitPrefRegistry(pref_registry_.get());
-    prefs_ = chrome_prefs::CreateProfilePrefs(
-        path_, std::move(pref_validation_delegate),
-        profile_policy_connector_->policy_service(), supervised_user_settings,
-        CreateExtensionPrefStore(this, false), pref_registry_, connector,
-        async_prefs, GetIOTaskRunner(), std::move(delegate));
-    // Register on BrowserContext.
-    user_prefs::UserPrefs::Set(this, prefs_.get());
-  }
-
+  prefs_ =
+      CreatePrefService(pref_registry_, CreateExtensionPrefStore(this, false),
+                        profile_policy_connector_->policy_service(),
+                        g_browser_process->browser_policy_connector(),
+                        std::move(pref_validation_delegate), GetIOTaskRunner(),
+                        key_.get(), path_, async_prefs);
   key_->SetPrefs(prefs_.get());
-  SimpleKeyMap::GetInstance()->Associate(this, key_.get());
-
-#if defined(OS_CHROMEOS)
-  if (is_regular_profile) {
-    chromeos::AccountManagerFactory* factory =
-        g_browser_process->platform_part()->GetAccountManagerFactory();
-    chromeos::AccountManager* account_manager =
-        factory->GetAccountManager(path.value());
-    account_manager->Initialize(
-        path,
-        g_browser_process->system_network_context_manager()
-            ->GetSharedURLLoaderFactory(),
-        base::BindRepeating(&chromeos::DelayNetworkCall,
-                            base::TimeDelta::FromMilliseconds(
-                                chromeos::kDefaultNetworkRetryDelayMS)),
-        GetPrefs());
-  }
-#endif
-
-  if (async_prefs) {
-    // Wait for the notification that prefs has been loaded
-    // (successfully or not).  Note that we can use base::Unretained
-    // because the PrefService is owned by this class and lives on
-    // the same thread.
-    prefs_->AddPrefInitObserver(base::BindOnce(
-        &ProfileImpl::OnPrefsLoaded, base::Unretained(this), create_mode));
-  } else {
-    // Prefs were loaded synchronously so we can continue directly.
-    OnPrefsLoaded(create_mode, true);
-  }
 }
 
 void ProfileImpl::DoFinalInit() {
@@ -1120,9 +1118,11 @@
   return schema_registry_service_.get();
 }
 
+#if !defined(OS_CHROMEOS)
 policy::UserCloudPolicyManager* ProfileImpl::GetUserCloudPolicyManager() {
   return user_cloud_policy_manager_;
 }
+#endif
 
 policy::ProfilePolicyConnector* ProfileImpl::GetProfilePolicyConnector() {
   return profile_policy_connector_.get();
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 1d24e86..95102e38 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -142,7 +142,9 @@
   PrefService* GetOffTheRecordPrefs() override;
   PrefService* GetReadOnlyOffTheRecordPrefs() override;
   policy::SchemaRegistryService* GetPolicySchemaRegistryService() override;
+#if !defined(OS_CHROMEOS)
   policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override;
+#endif
   policy::ProfilePolicyConnector* GetProfilePolicyConnector() override;
   const policy::ProfilePolicyConnector* GetProfilePolicyConnector()
       const override;
@@ -186,6 +188,15 @@
               CreateMode create_mode,
               scoped_refptr<base::SequencedTaskRunner> io_task_runner);
 
+#if defined(OS_ANDROID)
+  // Takes the ownership of the pre-created PrefService and other objects if
+  // they have been created.
+  void TakePrefsFromStartupData();
+#endif
+
+  // Creates |prefs| from scratch in normal startup.
+  void LoadPrefsForNormalStartup(bool async_prefs);
+
   // Does final initialization. Should be called after prefs were loaded.
   void DoFinalInit();
 
diff --git a/chrome/browser/resources/app_management/dom_switch.js b/chrome/browser/resources/app_management/dom_switch.js
index 98f8354..f6fc7c8 100644
--- a/chrome/browser/resources/app_management/dom_switch.js
+++ b/chrome/browser/resources/app_management/dom_switch.js
@@ -114,28 +114,6 @@
   },
 
   /**
-   * TODO(dpapad): Delete this method once migration to Polymer 2 has finished.
-   * @param {string} prop
-   * @param {Object} value
-   */
-  _forwardParentProp: function(prop, value) {
-    if (this.instance_) {
-      this.instance_[prop] = value;
-    }
-  },
-
-  /**
-   * TODO(dpapad): Delete this method once migration to Polymer 2 has finished.
-   * @param {string} path
-   * @param {Object} value
-   */
-  _forwardParentPath: function(path, value) {
-    if (this.instance_) {
-      this.instance_.notifyPath(path, value, true);
-    }
-  },
-
-  /**
    * @param {string} prop
    * @param {Object} value
    */
diff --git a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
index f413afd..4cf592f4 100644
--- a/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
+++ b/chrome/browser/resources/chromeos/arc_graphics_tracing/arc_graphics_tracing_ui.js
@@ -330,6 +330,7 @@
     this.bands = [];
     this.charts = [];
     this.globalEvents = [];
+    this.vsyncEvents = null;
     this.resolution = resolution;
     this.minTimestamp = minTimestamp;
     this.maxTimestamp = maxTimestamp;
@@ -562,6 +563,16 @@
     this.globalEvents.push(events);
   }
 
+  /**
+   * Sets VSYNC events and adds them as a global events.
+   *
+   * @param {Events} VSYNC events to set.
+   */
+  setVSync(events) {
+    this.addGlobal(events);
+    this.vsyncEvents = events;
+  }
+
   /** Initializes tooltip support by observing mouse events */
   setTooltip_() {
     this.tooltip = $('arc-event-band-tooltip');
@@ -644,6 +655,23 @@
   }
 
   /**
+   * Returns timestamp of the last VSYNC event happened before or on given
+   * |eventTimestamp|.
+   *
+   * @param {number} eventTimestamp.
+   */
+  getVSyncTimestamp_(eventTimestamp) {
+    if (!this.vsyncEvents) {
+      return null;
+    }
+    var vsyncEventIndex = this.vsyncEvents.getLastBefore(eventTimestamp);
+    if (vsyncEventIndex < 0) {
+      return null;
+    }
+    return this.vsyncEvents.events[vsyncEventIndex][1];
+  }
+
+  /**
    * Creates and shows tooltip for event band for the position under |event|.
    *
    * @param {Object} mouse event.
@@ -651,9 +679,9 @@
    */
   updateToolTipForBand_(event, eventBand) {
     var horizontalGap = 10;
-    var eventIconOffset = 70;
+    var eventIconOffset = 24;
     var eventIconRadius = 4;
-    var eventNameOffset = 78;
+    var eventNameOffset = 32;
     var verticalGap = 5;
     var intentOffset = 12;
     var lineHeight = 16;
@@ -668,10 +696,6 @@
     this.tooltip.appendChild(svg);
     var yOffset = verticalGap + lineHeight;
     var eventTimestamp = this.offsetToTime(offsetX);
-    SVG.addText(
-        svg, horizontalGap, yOffset, fontSize,
-        timestempToMsText(eventTimestamp) + ' ms');
-    yOffset += lineHeight;
 
     // Find the event under the cursor. |index| points to the current event
     // and |nextIndex| points to the next event.
@@ -689,10 +713,15 @@
     var globalEvent = this.findGlobalEvent_(eventTimestamp, 200 /* distance */);
     if (globalEvent) {
       // Show the global event info.
-      var attributes = eventAttributes[globalEvent[0]];
-      SVG.addText(
-          svg, horizontalGap, yOffset, fontSize,
-          attributes.name + ' ' + timestempToMsText(globalEvent[1]) + ' ms.');
+      var globalEventType = globalEvent[0];
+      var globalEventTimestamp = globalEvent[1];
+      // -1 to prevent VSYNC detects itself. In last case, previous VSYNC would
+      // be chosen.
+      var vsyncTimestamp = this.getVSyncTimestamp_(globalEventTimestamp - 1);
+
+
+      var attributes = eventAttributes[globalEventType];
+      SVG.addText(svg, horizontalGap, yOffset, fontSize, attributes.name);
       yOffset += lineHeight;
       // Render content if exists.
       if (globalEvent.length > 2) {
@@ -701,6 +730,18 @@
             globalEvent[2]);
         yOffset += lineHeight;
       }
+
+      SVG.addText(
+          svg, horizontalGap, yOffset, fontSize,
+          timestempToMsText(globalEventTimestamp) + ' chart time ms');
+      yOffset += lineHeight;
+      if (vsyncTimestamp) {
+        SVG.addText(
+            svg, horizontalGap, yOffset, fontSize,
+            '+' + timestempToMsText(globalEventTimestamp - vsyncTimestamp) +
+                ' since last vsync ms');
+        yOffset += lineHeight;
+      }
     } else if (index < 0 || eventBand.isEndOfSequence(index)) {
       // In case cursor points to idle event, show its interval.
       var startIdle = index < 0 ? 0 : eventBand.events[index][1];
@@ -709,7 +750,7 @@
       SVG.addText(
           svg, horizontalGap, yOffset, fontSize,
           'Idle ' + timestempToMsText(startIdle) + '...' +
-              timestempToMsText(endIdle) + ' ms.');
+              timestempToMsText(endIdle) + ' chart time ms.');
       yOffset += lineHeight;
     } else {
       // Show the sequence of non-idle events.
@@ -723,23 +764,27 @@
       }
 
       var sequenceTimestamp = eventBand.events[index][1];
+      var vsyncTimestamp = this.getVSyncTimestamp_(sequenceTimestamp);
+
+      SVG.addText(
+          svg, horizontalGap, yOffset, fontSize,
+          timestempToMsText(sequenceTimestamp) + ' chart time ms');
+      yOffset += lineHeight;
+      if (vsyncTimestamp) {
+        SVG.addText(
+            svg, horizontalGap, yOffset, fontSize,
+            '+' + timestempToMsText(sequenceTimestamp - vsyncTimestamp) +
+                ' since last vsync ms');
+        yOffset += lineHeight;
+      }
+
       var lastTimestamp = sequenceTimestamp;
-      var firstEvent = true;
       // Scan for the entries to show.
       var entriesToShow = [];
       while (index >= 0) {
         var attributes = eventBand.getEventAttributes(index);
         var eventTimestamp = eventBand.events[index][1];
         var entryToShow = {};
-        if (firstEvent) {
-          // Show the global timestamp.
-          entryToShow.prefix = timestempToMsText(sequenceTimestamp) + ' ms';
-          firstEvent = false;
-        } else {
-          // Show the offset relative to the start of sequence of events.
-          entryToShow.prefix = '+' +
-              timestempToMsText(eventTimestamp - sequenceTimestamp) + ' ms';
-        }
         entryToShow.color = attributes.color;
         entryToShow.text = attributes.name;
         if (entriesToShow.length > 0) {
@@ -760,7 +805,6 @@
       }
       for (var i = 0; i < entriesToShow.length; ++i) {
         var entryToShow = entriesToShow[i];
-        SVG.addText(svg, horizontalGap, yOffset, fontSize, entryToShow.prefix);
         SVG.addCircle(
             svg, eventIconOffset, yOffset - eventIconRadius, eventIconRadius, 1,
             entryToShow.color, 'black');
@@ -1243,6 +1287,22 @@
     }
     return this.getNextEvent(closest, 1 /* direction */);
   }
+
+  /**
+   * Returns the index of the last event before or on requested |timestamp|.
+   *
+   * @param {number} timestamp to search.
+   */
+  getLastBefore(timestamp) {
+    var closest = this.getClosest(timestamp);
+    if (closest < 0) {
+      return -1;
+    }
+    if (this.events[closest][1] <= timestamp) {
+      return closest;
+    }
+    return this.getNextEvent(closest, -1 /* direction */);
+  }
 }
 
 /**
@@ -1313,7 +1373,7 @@
       new Events(model.android.buffers[0], 400, 499), topBandHeight,
       topBandPadding);
   // Add vsync events
-  androidBands.addGlobal(vsyncEvents);
+  androidBands.setVSync(vsyncEvents);
   androidBands.addGlobal(new Events(
       model.android.global_events, 405 /* kSurfaceFlingerCompositionJank */,
       405 /* kSurfaceFlingerCompositionJank */));
@@ -1348,7 +1408,7 @@
       // Chrome buffer events are not displayed at this time.
     }
     // Add vsync events
-    activityBands.addGlobal(vsyncEvents);
+    activityBands.setVSync(vsyncEvents);
     activityBands.addGlobal(new Events(
         view.global_events, 106 /* kBufferFillJank */,
         106 /* kBufferFillJank */));
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
index 789dfb53..218721fe 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.html
@@ -20,7 +20,7 @@
     <link rel="stylesheet" href="assistant_value_prop.css">
     <assistant-loading id="loading" hidden>
     </assistant-loading>
-    <assistant-value-prop id="value-prop">
+    <assistant-value-prop id="value-prop" hidden>
     </assistant-value-prop>
     <assistant-third-party id="third-party" hidden>
     </assistant-third-party>
diff --git a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js
index 5059ac0e..f15f940 100644
--- a/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js
+++ b/chrome/browser/resources/chromeos/assistant_optin/assistant_optin_flow.js
@@ -172,6 +172,7 @@
       return;
     }
 
+    this.$['loading'].hidden = true;
     screen.hidden = false;
     screen.addEventListener('loading', this.boundShowLoadingScreen);
     screen.addEventListener('error', this.boundOnScreenLoadingError);
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.html b/chrome/browser/resources/settings/chromeos/os_settings.html
index f84a5ce5..95cf9194 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings.html
@@ -17,7 +17,8 @@
     }
 
     html.loading::before {
-      background-color: var(--md-toolbar-color);
+      /* TODO(hsuregan): update for dark mode when needed. */
+      background-color: white;
       border-bottom: var(--md-toolbar-border);
       box-sizing: border-box;
       content: '';
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
index df961af1..7ccb695 100644
--- a/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
+++ b/chrome/browser/resources/settings/chromeos/os_settings_ui/os_settings_ui.html
@@ -35,14 +35,13 @@
 
       cr-toolbar {
         @apply --layout-center;
+        /* TODO(hsuregan): update for dark mode when needed. */
+        background-color: white;
+        color: var(--cr-secondary-text-color);
         min-height: 56px;
         z-index: 2;
       }
 
-      :host-context(html:not([dark])) cr-toolbar {
-        --iron-icon-fill-color: white;
-      }
-
       #container {
         flex: 1;
         overflow: overlay;
diff --git a/chrome/browser/resources/settings/page_visibility.js b/chrome/browser/resources/settings/page_visibility.js
index 19eb861..d41820da 100644
--- a/chrome/browser/resources/settings/page_visibility.js
+++ b/chrome/browser/resources/settings/page_visibility.js
@@ -46,8 +46,10 @@
 
 /**
  * @typedef {{
+ *   contentProtectionAttestation: boolean,
  *   networkPrediction: boolean,
  *   searchPrediction: boolean,
+ *   wakeOnWifi: boolean,
  * }}
  */
 let PrivacyPageVisibility;
@@ -96,8 +98,10 @@
       advancedSettings: true,
       dateTime: showOSSettings,
       privacy: {
+        contentProtectionAttestation: showOSSettings,
         searchPrediction: false,
         networkPrediction: false,
+        wakeOnWifi: showOSSettings,
       },
       downloads: {
         googleDrive: false,
@@ -128,8 +132,10 @@
       advancedSettings: true,
       dateTime: showOSSettings,
       privacy: {
+        contentProtectionAttestation: showOSSettings,
         searchPrediction: true,
         networkPrediction: true,
+        wakeOnWifi: showOSSettings,
       },
       downloads: {
         googleDrive: true,
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index f1da2b7..e5bbd124 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -128,10 +128,12 @@
         </settings-toggle-button>
 <if expr="chromeos">
         <settings-toggle-button
+            hidden="[[!pageVisibility.contentProtectionAttestation]]"
             pref="{{prefs.cros.device.attestation_for_content_protection_enabled}}"
             label="$i18n{enableContentProtectionAttestation}">
         </settings-toggle-button>
         <settings-toggle-button
+            hidden="[[!pageVisibility.wakeOnWifi]]"
             pref="{{prefs.settings.internet.wake_on_wifi_darkconnect}}"
             label="$i18n{wakeOnWifi}">
         </settings-toggle-button>
diff --git a/chrome/browser/startup_data.cc b/chrome/browser/startup_data.cc
index 6584975..a1560dc 100644
--- a/chrome/browser/startup_data.cc
+++ b/chrome/browser/startup_data.cc
@@ -5,9 +5,162 @@
 #include "chrome/browser/startup_data.h"
 
 #include "chrome/browser/metrics/chrome_feature_list_creator.h"
+#include "chrome/browser/prefs/profile_pref_store_manager.h"
+
+#if defined(OS_ANDROID)
+#include "base/files/file_util.h"
+#include "base/no_destructor.h"
+#include "base/path_service.h"
+#include "base/task/post_task.h"
+#include "chrome/browser/android/profile_key_startup_accessor.h"
+#include "chrome/browser/policy/cloud/user_cloud_policy_manager_builder.h"
+#include "chrome/browser/policy/profile_policy_connector.h"
+#include "chrome/browser/policy/profile_policy_connector_builder.h"
+#include "chrome/browser/policy/schema_registry_service.h"
+#include "chrome/browser/policy/schema_registry_service_builder.h"
+#include "chrome/browser/prefs/browser_prefs.h"
+#include "chrome/browser/prefs/chrome_pref_service_factory.h"
+#include "chrome/browser/prefs/in_process_service_factory_factory.h"
+#include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
+#include "chrome/browser/profiles/pref_service_builder_utils.h"
+#include "chrome/browser/supervised_user/supervised_user_pref_store.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service.h"
+#include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_factory_key.h"
+#include "components/policy/core/common/cloud/cloud_external_data_manager.h"
+#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
+#include "components/policy/core/common/cloud/user_cloud_policy_store.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/sync_preferences/pref_service_syncable.h"
+#include "content/public/browser/network_service_instance.h"
+#include "services/preferences/public/cpp/in_process_service_factory.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
+
+namespace {
+
+base::FilePath GetProfilePath() {
+  base::FilePath user_data_dir;
+  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  return user_data_dir.AppendASCII(chrome::kInitialProfile);
+}
+
+}  // namespace
+
+#endif
 
 StartupData::StartupData()
     : chrome_feature_list_creator_(
           std::make_unique<ChromeFeatureListCreator>()) {}
 
 StartupData::~StartupData() = default;
+
+#if defined(OS_ANDROID)
+void StartupData::CreateProfilePrefService() {
+  key_ = std::make_unique<ProfileKey>(GetProfilePath());
+  PreProfilePrefServiceInit();
+  CreateProfilePrefServiceInternal();
+  key_->SetPrefs(prefs_.get());
+
+  ProfileKeyStartupAccessor::GetInstance()->SetProfileKey(key_.get());
+}
+
+bool StartupData::HasBuiltProfilePrefService() {
+  return !!prefs_.get();
+}
+
+ProfileKey* StartupData::GetProfileKey() {
+  return key_.get();
+}
+
+std::unique_ptr<ProfileKey> StartupData::TakeProfileKey() {
+  return std::move(key_);
+}
+
+std::unique_ptr<policy::SchemaRegistryService>
+StartupData::TakeSchemaRegistryService() {
+  return std::move(schema_registry_service_);
+}
+
+std::unique_ptr<policy::ConfigurationPolicyProvider>
+StartupData::TakeConfigurationPolicyProvider() {
+  return std::move(configuration_policy_provider_);
+}
+
+std::unique_ptr<policy::ProfilePolicyConnector>
+StartupData::TakeProfilePolicyConnector() {
+  return std::move(profile_policy_connector_);
+}
+
+scoped_refptr<user_prefs::PrefRegistrySyncable>
+StartupData::TakePrefRegistrySyncable() {
+  return std::move(pref_registry_);
+}
+
+std::unique_ptr<sync_preferences::PrefServiceSyncable>
+StartupData::TakeProfilePrefService() {
+  return std::move(prefs_);
+}
+
+void StartupData::PreProfilePrefServiceInit() {
+  pref_registry_ = base::MakeRefCounted<user_prefs::PrefRegistrySyncable>();
+  ChromeBrowserMainExtraPartsProfiles::
+      EnsureBrowserContextKeyedServiceFactoriesBuilt();
+}
+
+void StartupData::CreateProfilePrefServiceInternal() {
+  const base::FilePath& path = key_->GetPath();
+  if (!base::PathExists(path)) {
+    // TODO(rogerta): http://crbug/160553 - Bad things happen if we can't
+    // write to the profile directory.  We should eventually be able to run in
+    // this situation.
+    if (!base::CreateDirectory(path))
+      return;
+
+    CreateProfileReadme(path);
+  }
+
+  scoped_refptr<base::SequencedTaskRunner> io_task_runner =
+      base::CreateSequencedTaskRunnerWithTraits(
+          {base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()});
+
+  policy::ChromeBrowserPolicyConnector* browser_policy_connector =
+      chrome_feature_list_creator_->browser_policy_connector();
+  std::unique_ptr<policy::SchemaRegistry> schema_registry =
+      std::make_unique<policy::SchemaRegistry>();
+  schema_registry_service_ = BuildSchemaRegistryService(
+      std::move(schema_registry), browser_policy_connector->GetChromeSchema(),
+      browser_policy_connector->GetSchemaRegistry());
+
+  configuration_policy_provider_ = CreateUserCloudPolicyManager(
+      path, schema_registry_service_->registry(),
+      true /* force_immediate_policy_load */, io_task_runner);
+
+  auto* user_cloud_policy_manager = static_cast<policy::CloudPolicyManager*>(
+      configuration_policy_provider_.get());
+  profile_policy_connector_ = policy::CreateAndInitProfilePolicyConnector(
+      schema_registry_service_->registry(),
+      static_cast<policy::ChromeBrowserPolicyConnector*>(
+          browser_policy_connector),
+      user_cloud_policy_manager, user_cloud_policy_manager->core()->store(),
+      true /* force_immediate_policy_load*/, nullptr /* user */);
+
+  RegisterProfilePrefs(false /* is_signin_profile */,
+                       chrome_feature_list_creator_->actual_locale(),
+                       pref_registry_.get());
+
+  prefs::mojom::TrackedPreferenceValidationDelegatePtr pref_validation_delegate;
+  // The preference tracking and protection is not required on Android.
+  DCHECK(!ProfilePrefStoreManager::kPlatformSupportsPreferenceTracking);
+
+  prefs_ = CreatePrefService(
+      pref_registry_, nullptr /* extension_pref_store */,
+      profile_policy_connector_->policy_service(), browser_policy_connector,
+      std::move(pref_validation_delegate), io_task_runner, key_.get(), path,
+      false /* async_prefs*/);
+}
+#endif
diff --git a/chrome/browser/startup_data.h b/chrome/browser/startup_data.h
index ebe30fb..fd50ab1 100644
--- a/chrome/browser/startup_data.h
+++ b/chrome/browser/startup_data.h
@@ -8,23 +8,87 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "build/build_config.h"
 
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
+
+namespace policy {
+class ConfigurationPolicyProvider;
+class ProfilePolicyConnector;
+class SchemaRegistryService;
+}  // namespace policy
+
+namespace sync_preferences {
+class PrefServiceSyncable;
+}
+
+class PrefService;
+class ProfileKey;
 class ChromeFeatureListCreator;
 
 // The StartupData owns any pre-created objects in //chrome before the full
 // browser starts, including the ChromeFeatureListCreator and the Profile's
-// PrefService (TODO).
+// PrefService. See doc:
+// https://docs.google.com/document/d/1ybmGWRWXu0aYNxA99IcHFesDAslIaO1KFP6eGdHTJaE/edit#heading=h.7bk05syrcom
 class StartupData {
  public:
   StartupData();
   ~StartupData();
 
+#if defined(OS_ANDROID)
+  // Initializes all necessary parameters to create the Profile's PrefService.
+  void CreateProfilePrefService();
+
+  // Returns whether a PrefService has been created.
+  bool HasBuiltProfilePrefService();
+
+  ProfileKey* GetProfileKey();
+
+  // Passes ownership of the |key_| to the caller.
+  std::unique_ptr<ProfileKey> TakeProfileKey();
+
+  // Passes ownership of the |schema_registry_service_| to the caller.
+  std::unique_ptr<policy::SchemaRegistryService> TakeSchemaRegistryService();
+
+  // Passes ownership of the |configuration_policy_provider_| to the caller.
+  std::unique_ptr<policy::ConfigurationPolicyProvider>
+  TakeConfigurationPolicyProvider();
+
+  // Passes ownership of the |profile_policy_connector_| to the caller.
+  std::unique_ptr<policy::ProfilePolicyConnector> TakeProfilePolicyConnector();
+
+  // Passes ownership of the |pref_registry_| to the caller.
+  scoped_refptr<user_prefs::PrefRegistrySyncable> TakePrefRegistrySyncable();
+
+  // Passes ownership of the |prefs_| to the caller.
+  std::unique_ptr<sync_preferences::PrefServiceSyncable>
+  TakeProfilePrefService();
+#endif
+
   ChromeFeatureListCreator* chrome_feature_list_creator() {
     return chrome_feature_list_creator_.get();
   }
 
  private:
+#if defined(OS_ANDROID)
+  void PreProfilePrefServiceInit();
+  void CreateProfilePrefServiceInternal();
+
+  std::unique_ptr<ProfileKey> key_;
+
+  std::unique_ptr<policy::SchemaRegistryService> schema_registry_service_;
+  std::unique_ptr<policy::ConfigurationPolicyProvider>
+      configuration_policy_provider_;
+  std::unique_ptr<policy::ProfilePolicyConnector> profile_policy_connector_;
+
+  scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_;
+
+  std::unique_ptr<sync_preferences::PrefServiceSyncable> prefs_;
+#endif
+
   std::unique_ptr<ChromeFeatureListCreator> chrome_feature_list_creator_;
 
   DISALLOW_COPY_AND_ASSIGN(StartupData);
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
index a570182..eca5944 100644
--- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc
+++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -220,7 +220,7 @@
   }
 
   // Trigger a sync reconfig to enable/disable the right SU data types.
-  // The logic to do this lives in the SupervisedUserSyncDataTypeController.
+  // The logic to do this lives in the SupervisedUserSyncModelTypeController.
   // TODO(crbug.com/946473): Get rid of this hack and instead call
   // ReadyForStartChanged from the controller.
   syncer::SyncService* sync_service =
diff --git a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc b/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc
deleted file mode 100644
index c07f026..0000000
--- a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h"
-
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/profiles/profile.h"
-
-SupervisedUserSyncDataTypeController::SupervisedUserSyncDataTypeController(
-    syncer::ModelType type,
-    const base::Closure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    Profile* profile)
-    : syncer::AsyncDirectoryTypeController(type,
-                                           dump_stack,
-                                           sync_service,
-                                           sync_client,
-                                           syncer::GROUP_UI,
-                                           base::ThreadTaskRunnerHandle::Get()),
-      profile_(profile) {
-  DCHECK(type == syncer::SUPERVISED_USER_SETTINGS ||
-         type == syncer::SUPERVISED_USER_WHITELISTS);
-}
-
-SupervisedUserSyncDataTypeController::~SupervisedUserSyncDataTypeController() {}
-
-bool SupervisedUserSyncDataTypeController::ReadyForStart() const {
-  DCHECK(CalledOnValidThread());
-  return profile_->IsSupervised();
-}
diff --git a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h b/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h
deleted file mode 100644
index cd71676..0000000
--- a/chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_SYNC_DATA_TYPE_CONTROLLER_H_
-#define CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_SYNC_DATA_TYPE_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-#include "components/sync/driver/data_type_controller.h"
-
-class Profile;
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-// A DataTypeController for supervised user sync datatypes, which enables or
-// disables these types based on the profile's IsSupervised state.
-class SupervisedUserSyncDataTypeController
-    : public syncer::AsyncDirectoryTypeController {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  SupervisedUserSyncDataTypeController(syncer::ModelType type,
-                                       const base::Closure& dump_stack,
-                                       syncer::SyncService* sync_service,
-                                       syncer::SyncClient* sync_client,
-                                       Profile* profile);
-  ~SupervisedUserSyncDataTypeController() override;
-
-  // AsyncDirectoryTypeController implementation.
-  bool ReadyForStart() const override;
-
- private:
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(SupervisedUserSyncDataTypeController);
-};
-
-#endif  // CHROME_BROWSER_SUPERVISED_USER_SUPERVISED_USER_SYNC_DATA_TYPE_CONTROLLER_H_
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index ffb7c9f..84dd4ff4 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -29,7 +29,6 @@
 #include "chrome/browser/security_events/security_event_recorder_factory.h"
 #include "chrome/browser/sync/bookmark_sync_service_factory.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
-#include "chrome/browser/sync/glue/theme_data_type_controller.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/send_tab_to_self_sync_service_factory.h"
@@ -64,12 +63,11 @@
 #include "components/invalidation/impl/profile_invalidation_provider.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/sync/password_model_worker.h"
-#include "components/search_engines/search_engine_data_type_controller.h"
+#include "components/search_engines/template_url_service.h"
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/driver/async_directory_type_controller.h"
 #include "components/sync/driver/model_type_controller.h"
 #include "components/sync/driver/sync_api_component_factory.h"
 #include "components/sync/driver/sync_driver_switches.h"
@@ -99,9 +97,7 @@
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/api/storage/settings_sync_util.h"
 #include "chrome/browser/extensions/extension_sync_service.h"
-#include "chrome/browser/sync/glue/extension_data_type_controller.h"
 #include "chrome/browser/sync/glue/extension_model_type_controller.h"
-#include "chrome/browser/sync/glue/extension_setting_data_type_controller.h"
 #include "chrome/browser/sync/glue/extension_setting_model_type_controller.h"
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
@@ -110,7 +106,6 @@
 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
-#include "chrome/browser/supervised_user/supervised_user_sync_data_type_controller.h"
 #include "chrome/browser/supervised_user/supervised_user_sync_model_type_controller.h"
 #include "chrome/browser/supervised_user/supervised_user_whitelist_service.h"
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
@@ -125,7 +120,6 @@
 #include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
-#include "chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_sync_model_type_controller.h"
 #include "chrome/browser/ui/app_list/arc/arc_package_syncable_service.h"
 #include "components/arc/arc_util.h"
@@ -133,12 +127,8 @@
 
 using content::BrowserThread;
 #if BUILDFLAG(ENABLE_EXTENSIONS)
-using browser_sync::ExtensionDataTypeController;
 using browser_sync::ExtensionModelTypeController;
-using browser_sync::ExtensionSettingDataTypeController;
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
-using browser_sync::SearchEngineDataTypeController;
-using syncer::AsyncDirectoryTypeController;
 
 namespace browser_sync {
 
@@ -302,176 +292,107 @@
   }
 
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
-  if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSSupervisedUsers)) {
-    controllers.push_back(
-        std::make_unique<SupervisedUserSyncModelTypeController>(
-            syncer::SUPERVISED_USER_SETTINGS, profile_, dump_stack, this));
-    controllers.push_back(
-        std::make_unique<SupervisedUserSyncModelTypeController>(
-            syncer::SUPERVISED_USER_WHITELISTS, profile_, dump_stack, this));
-  } else {
-    controllers.push_back(
-        std::make_unique<SupervisedUserSyncDataTypeController>(
-            syncer::SUPERVISED_USER_SETTINGS, dump_stack, sync_service, this,
-            profile_));
-    controllers.push_back(
-        std::make_unique<SupervisedUserSyncDataTypeController>(
-            syncer::SUPERVISED_USER_WHITELISTS, dump_stack, sync_service, this,
-            profile_));
-  }
+  controllers.push_back(std::make_unique<SupervisedUserSyncModelTypeController>(
+      syncer::SUPERVISED_USER_SETTINGS, profile_, dump_stack, this));
+  controllers.push_back(std::make_unique<SupervisedUserSyncModelTypeController>(
+      syncer::SUPERVISED_USER_WHITELISTS, profile_, dump_stack, this));
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // App sync is enabled by default.  Register unless explicitly
   // disabled.
   if (!disabled_types.Has(syncer::APPS)) {
-    if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSApps)) {
-      controllers.push_back(std::make_unique<ExtensionModelTypeController>(
-          syncer::APPS, GetModelTypeStoreService()->GetStoreFactory(),
-          base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                         base::Unretained(this), syncer::APPS),
-          dump_stack, profile_));
-    } else {
-      controllers.push_back(std::make_unique<ExtensionDataTypeController>(
-          syncer::APPS, dump_stack, sync_service, this, profile_));
-    }
+    controllers.push_back(std::make_unique<ExtensionModelTypeController>(
+        syncer::APPS, GetModelTypeStoreService()->GetStoreFactory(),
+        base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                       base::Unretained(this), syncer::APPS),
+        dump_stack, profile_));
   }
 
   // Extension sync is enabled by default.  Register unless explicitly
   // disabled.
   if (!disabled_types.Has(syncer::EXTENSIONS)) {
-    if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSExtensions)) {
-      controllers.push_back(std::make_unique<ExtensionModelTypeController>(
-          syncer::EXTENSIONS, GetModelTypeStoreService()->GetStoreFactory(),
-          base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                         base::Unretained(this), syncer::EXTENSIONS),
-          dump_stack, profile_));
-    } else {
-      controllers.push_back(std::make_unique<ExtensionDataTypeController>(
-          syncer::EXTENSIONS, dump_stack, sync_service, this, profile_));
-    }
+    controllers.push_back(std::make_unique<ExtensionModelTypeController>(
+        syncer::EXTENSIONS, GetModelTypeStoreService()->GetStoreFactory(),
+        base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                       base::Unretained(this), syncer::EXTENSIONS),
+        dump_stack, profile_));
   }
 
   // Extension setting sync is enabled by default.  Register unless explicitly
   // disabled.
   if (!disabled_types.Has(syncer::EXTENSION_SETTINGS)) {
-    if (base::FeatureList::IsEnabled(
-            switches::kSyncPseudoUSSExtensionSettings)) {
-      controllers.push_back(
-          std::make_unique<ExtensionSettingModelTypeController>(
-              syncer::EXTENSION_SETTINGS,
-              GetModelTypeStoreService()->GetStoreFactory(),
-              extensions::settings_sync_util::GetSyncableServiceProvider(
-                  profile_, syncer::EXTENSION_SETTINGS),
-              dump_stack, profile_));
-    } else {
-      controllers.push_back(
-          std::make_unique<ExtensionSettingDataTypeController>(
-              syncer::EXTENSION_SETTINGS, dump_stack, sync_service, this,
-              profile_));
-    }
+    controllers.push_back(std::make_unique<ExtensionSettingModelTypeController>(
+        syncer::EXTENSION_SETTINGS,
+        GetModelTypeStoreService()->GetStoreFactory(),
+        extensions::settings_sync_util::GetSyncableServiceProvider(
+            profile_, syncer::EXTENSION_SETTINGS),
+        dump_stack, profile_));
   }
 
   // App setting sync is enabled by default.  Register unless explicitly
   // disabled.
   if (!disabled_types.Has(syncer::APP_SETTINGS)) {
-    if (base::FeatureList::IsEnabled(
-            switches::kSyncPseudoUSSExtensionSettings)) {
-      controllers.push_back(
-          std::make_unique<ExtensionSettingModelTypeController>(
-              syncer::APP_SETTINGS,
-              GetModelTypeStoreService()->GetStoreFactory(),
-              extensions::settings_sync_util::GetSyncableServiceProvider(
-                  profile_, syncer::APP_SETTINGS),
-              dump_stack, profile_));
-    } else {
-      controllers.push_back(
-          std::make_unique<ExtensionSettingDataTypeController>(
-              syncer::APP_SETTINGS, dump_stack, sync_service, this, profile_));
-    }
+    controllers.push_back(std::make_unique<ExtensionSettingModelTypeController>(
+        syncer::APP_SETTINGS, GetModelTypeStoreService()->GetStoreFactory(),
+        extensions::settings_sync_util::GetSyncableServiceProvider(
+            profile_, syncer::APP_SETTINGS),
+        dump_stack, profile_));
   }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
 #if !defined(OS_ANDROID)
   // Theme sync is enabled by default.  Register unless explicitly disabled.
   if (!disabled_types.Has(syncer::THEMES)) {
-    if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSThemes)) {
-      controllers.push_back(std::make_unique<ExtensionModelTypeController>(
-          syncer::THEMES, GetModelTypeStoreService()->GetStoreFactory(),
-          base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                         base::Unretained(this), syncer::THEMES),
-          dump_stack, profile_));
-    } else {
-      controllers.push_back(std::make_unique<ThemeDataTypeController>(
-          dump_stack, sync_service, this, profile_));
-    }
+    controllers.push_back(std::make_unique<ExtensionModelTypeController>(
+        syncer::THEMES, GetModelTypeStoreService()->GetStoreFactory(),
+        base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                       base::Unretained(this), syncer::THEMES),
+        dump_stack, profile_));
   }
 
   // Search Engine sync is enabled by default.  Register unless explicitly
   // disabled. The service can be null in tests.
   if (!disabled_types.Has(syncer::SEARCH_ENGINES)) {
-    if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSSearchEngines)) {
-      controllers.push_back(
-          std::make_unique<syncer::SyncableServiceBasedModelTypeController>(
-              syncer::SEARCH_ENGINES,
-              GetModelTypeStoreService()->GetStoreFactory(),
-              base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                             base::Unretained(this), syncer::SEARCH_ENGINES),
-              dump_stack));
-    } else {
-      controllers.push_back(std::make_unique<SearchEngineDataTypeController>(
-          dump_stack, sync_service, this,
-          TemplateURLServiceFactory::GetForProfile(profile_)));
-    }
+    controllers.push_back(
+        std::make_unique<syncer::SyncableServiceBasedModelTypeController>(
+            syncer::SEARCH_ENGINES,
+            GetModelTypeStoreService()->GetStoreFactory(),
+            base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                           base::Unretained(this), syncer::SEARCH_ENGINES),
+            dump_stack));
   }
 #endif  // !defined(OS_ANDROID)
 
 #if BUILDFLAG(ENABLE_APP_LIST)
-  if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSAppList)) {
-    controllers.push_back(
-        std::make_unique<syncer::SyncableServiceBasedModelTypeController>(
-            syncer::APP_LIST, GetModelTypeStoreService()->GetStoreFactory(),
-            base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                           base::Unretained(this), syncer::APP_LIST),
-            dump_stack));
-  } else {
-    controllers.push_back(std::make_unique<AsyncDirectoryTypeController>(
-        syncer::APP_LIST, dump_stack, sync_service, this, syncer::GROUP_UI,
-        base::CreateSequencedTaskRunnerWithTraits({BrowserThread::UI})));
-  }
+  controllers.push_back(
+      std::make_unique<syncer::SyncableServiceBasedModelTypeController>(
+          syncer::APP_LIST, GetModelTypeStoreService()->GetStoreFactory(),
+          base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                         base::Unretained(this), syncer::APP_LIST),
+          dump_stack));
 #endif  // BUILDFLAG(ENABLE_APP_LIST)
 
 #if defined(OS_LINUX) || defined(OS_WIN)
   // Dictionary sync is enabled by default.
   if (!disabled_types.Has(syncer::DICTIONARY)) {
-    if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSDictionary)) {
-      controllers.push_back(
-          std::make_unique<syncer::SyncableServiceBasedModelTypeController>(
-              syncer::DICTIONARY, GetModelTypeStoreService()->GetStoreFactory(),
-              base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                             base::Unretained(this), syncer::DICTIONARY),
-              dump_stack));
-    } else {
-      controllers.push_back(std::make_unique<AsyncDirectoryTypeController>(
-          syncer::DICTIONARY, dump_stack, sync_service, this, syncer::GROUP_UI,
-          base::CreateSequencedTaskRunnerWithTraits({BrowserThread::UI})));
-    }
+    controllers.push_back(
+        std::make_unique<syncer::SyncableServiceBasedModelTypeController>(
+            syncer::DICTIONARY, GetModelTypeStoreService()->GetStoreFactory(),
+            base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                           base::Unretained(this), syncer::DICTIONARY),
+            dump_stack));
   }
 #endif  // defined(OS_LINUX) || defined(OS_WIN)
 
 #if defined(OS_CHROMEOS)
   if (arc::IsArcAllowedForProfile(profile_) &&
       !arc::IsArcAppSyncFlowDisabled()) {
-    if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSArcPackage)) {
-      controllers.push_back(std::make_unique<ArcPackageSyncModelTypeController>(
-          GetModelTypeStoreService()->GetStoreFactory(),
-          base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
-                         base::Unretained(this), syncer::ARC_PACKAGE),
-          dump_stack, sync_service, profile_));
-    } else {
-      controllers.push_back(std::make_unique<ArcPackageSyncDataTypeController>(
-          syncer::ARC_PACKAGE, dump_stack, sync_service, this, profile_));
-    }
+    controllers.push_back(std::make_unique<ArcPackageSyncModelTypeController>(
+        GetModelTypeStoreService()->GetStoreFactory(),
+        base::BindOnce(&ChromeSyncClient::GetSyncableServiceForType,
+                       base::Unretained(this), syncer::ARC_PACKAGE),
+        dump_stack, sync_service, profile_));
   }
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.cc b/chrome/browser/sync/glue/extension_data_type_controller.cc
deleted file mode 100644
index e5da78e..0000000
--- a/chrome/browser/sync/glue/extension_data_type_controller.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync/glue/extension_data_type_controller.h"
-
-#include "base/metrics/histogram_macros.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/profiles/profile.h"
-#include "extensions/browser/extension_system.h"
-
-namespace browser_sync {
-
-ExtensionDataTypeController::ExtensionDataTypeController(
-    syncer::ModelType type,
-    const base::Closure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    Profile* profile)
-    : AsyncDirectoryTypeController(type,
-                                   dump_stack,
-                                   sync_service,
-                                   sync_client,
-                                   syncer::GROUP_UI,
-                                   base::ThreadTaskRunnerHandle::Get()),
-      profile_(profile) {
-  DCHECK(type == syncer::EXTENSIONS || type == syncer::APPS);
-}
-
-ExtensionDataTypeController::~ExtensionDataTypeController() {}
-
-bool ExtensionDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  extensions::ExtensionSystem::Get(profile_)->InitForRegularProfile(
-      true /* extensions_enabled */);
-  return true;
-}
-
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/extension_data_type_controller.h b/chrome/browser/sync/glue/extension_data_type_controller.h
deleted file mode 100644
index 267b993..0000000
--- a/chrome/browser/sync/glue/extension_data_type_controller.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_TYPE_CONTROLLER_H_
-#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_TYPE_CONTROLLER_H_
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-#include "components/sync/driver/generic_change_processor.h"
-
-class Profile;
-
-namespace browser_sync {
-
-// TODO(zea): Rename this and ExtensionSettingsDTC to ExtensionOrApp*, since
-// both actually handle the APP datatypes as well.
-class ExtensionDataTypeController
-    : public syncer::AsyncDirectoryTypeController {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  ExtensionDataTypeController(
-      syncer::ModelType type,  // Either EXTENSIONS or APPS.
-      const base::Closure& dump_stack,
-      syncer::SyncService* sync_service,
-      syncer::SyncClient* sync_client,
-      Profile* profile);
-  ~ExtensionDataTypeController() override;
-
- private:
-  // AsyncDirectoryTypeController implementation.
-  bool StartModels() override;
-
-  Profile* const profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionDataTypeController);
-};
-
-}  // namespace browser_sync
-
-#endif  // CHROME_BROWSER_SYNC_GLUE_EXTENSION_DATA_TYPE_CONTROLLER_H_
diff --git a/chrome/browser/sync/glue/extension_model_type_controller.h b/chrome/browser/sync/glue/extension_model_type_controller.h
index 67092e9b..83c4755 100644
--- a/chrome/browser/sync/glue/extension_model_type_controller.h
+++ b/chrome/browser/sync/glue/extension_model_type_controller.h
@@ -14,8 +14,7 @@
 namespace browser_sync {
 
 // Controller with custom logic to start the extensions machinery when sync is
-// starting. Analogous to ExtensionDataTypeController and
-// ThemeDataTypeController.
+// starting.
 class ExtensionModelTypeController
     : public syncer::SyncableServiceBasedModelTypeController {
  public:
diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc b/chrome/browser/sync/glue/extension_setting_data_type_controller.cc
deleted file mode 100644
index 7ec20bf..0000000
--- a/chrome/browser/sync/glue/extension_setting_data_type_controller.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync/glue/extension_setting_data_type_controller.h"
-
-#include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
-#include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/profiles/profile.h"
-#include "components/sync/driver/generic_change_processor.h"
-#include "components/sync/model/syncable_service.h"
-#include "extensions/browser/api/storage/backend_task_runner.h"
-#include "extensions/browser/extension_system.h"
-
-namespace browser_sync {
-
-ExtensionSettingDataTypeController::ExtensionSettingDataTypeController(
-    syncer::ModelType type,
-    const base::Closure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    Profile* profile)
-    : AsyncDirectoryTypeController(type,
-                                   dump_stack,
-                                   sync_service,
-                                   sync_client,
-                                   syncer::GROUP_FILE,
-                                   extensions::GetBackendTaskRunner()),
-      profile_(profile) {
-  DCHECK(type == syncer::EXTENSION_SETTINGS || type == syncer::APP_SETTINGS);
-}
-
-ExtensionSettingDataTypeController::~ExtensionSettingDataTypeController() {}
-
-bool ExtensionSettingDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  extensions::ExtensionSystem::Get(profile_)->InitForRegularProfile(
-      true /* extensions_enabled */);
-  return true;
-}
-
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/extension_setting_data_type_controller.h b/chrome/browser/sync/glue/extension_setting_data_type_controller.h
deleted file mode 100644
index 1c6c85d..0000000
--- a/chrome/browser/sync/glue/extension_setting_data_type_controller.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_GLUE_EXTENSION_SETTING_DATA_TYPE_CONTROLLER_H__
-#define CHROME_BROWSER_SYNC_GLUE_EXTENSION_SETTING_DATA_TYPE_CONTROLLER_H__
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-
-class Profile;
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-namespace browser_sync {
-
-class ExtensionSettingDataTypeController
-    : public syncer::AsyncDirectoryTypeController {
- public:
-  // |type| is either EXTENSION_SETTINGS or APP_SETTINGS.
-  // |dump_stack| is called when an unrecoverable error occurs.
-  ExtensionSettingDataTypeController(syncer::ModelType type,
-                                     const base::Closure& dump_stack,
-                                     syncer::SyncService* sync_service,
-                                     syncer::SyncClient* sync_client,
-                                     Profile* profile);
-  ~ExtensionSettingDataTypeController() override;
-
- private:
-  // AsyncDirectoryTypeController implementation.
-  bool StartModels() override;
-
-  // Only used on the UI thread.
-  Profile* profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ExtensionSettingDataTypeController);
-};
-
-}  // namespace browser_sync
-
-#endif  // CHROME_BROWSER_SYNC_GLUE_EXTENSION_SETTING_DATA_TYPE_CONTROLLER_H__
diff --git a/chrome/browser/sync/glue/theme_data_type_controller.cc b/chrome/browser/sync/glue/theme_data_type_controller.cc
deleted file mode 100644
index 63613b6..0000000
--- a/chrome/browser/sync/glue/theme_data_type_controller.cc
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync/glue/theme_data_type_controller.h"
-
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/profiles/profile.h"
-#include "extensions/browser/extension_system.h"
-
-namespace browser_sync {
-
-ThemeDataTypeController::ThemeDataTypeController(
-    const base::Closure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    Profile* profile)
-    : AsyncDirectoryTypeController(syncer::THEMES,
-                                   dump_stack,
-                                   sync_service,
-                                   sync_client,
-                                   syncer::GROUP_UI,
-                                   base::ThreadTaskRunnerHandle::Get()),
-      profile_(profile) {}
-
-ThemeDataTypeController::~ThemeDataTypeController() {}
-
-bool ThemeDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  extensions::ExtensionSystem::Get(profile_)->InitForRegularProfile(
-      true /* extensions_enabled */);
-  return true;
-}
-
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/glue/theme_data_type_controller.h b/chrome/browser/sync/glue/theme_data_type_controller.h
deleted file mode 100644
index bc026ffc..0000000
--- a/chrome/browser/sync/glue/theme_data_type_controller.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_SYNC_GLUE_THEME_DATA_TYPE_CONTROLLER_H_
-#define CHROME_BROWSER_SYNC_GLUE_THEME_DATA_TYPE_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-
-class Profile;
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-namespace browser_sync {
-
-class ThemeDataTypeController : public syncer::AsyncDirectoryTypeController {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  ThemeDataTypeController(const base::Closure& dump_stack,
-                          syncer::SyncService* sync_service,
-                          syncer::SyncClient* sync_client,
-                          Profile* profile);
-  ~ThemeDataTypeController() override;
-
- private:
-  // AsyncDirectoryTypeController implementation.
-  bool StartModels() override;
-
-  Profile* const profile_;
-  DISALLOW_COPY_AND_ASSIGN(ThemeDataTypeController);
-};
-
-}  // namespace browser_sync
-
-#endif  // CHROME_BROWSER_SYNC_GLUE_THEME_DATA_TYPE_CONTROLLER_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 1a40fd40..9482832 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -3349,8 +3349,6 @@
         "app_list/arc/arc_default_app_list.h",
         "app_list/arc/arc_fast_app_reinstall_starter.cc",
         "app_list/arc/arc_fast_app_reinstall_starter.h",
-        "app_list/arc/arc_package_sync_data_type_controller.cc",
-        "app_list/arc/arc_package_sync_data_type_controller.h",
         "app_list/arc/arc_package_sync_model_type_controller.cc",
         "app_list/arc/arc_package_sync_model_type_controller.h",
         "app_list/arc/arc_package_syncable_service.cc",
diff --git a/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc b/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc
deleted file mode 100644
index c4bc45ad..0000000
--- a/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h"
-
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
-#include "components/sync/base/pref_names.h"
-#include "components/sync/base/sync_prefs.h"
-#include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_service.h"
-
-ArcPackageSyncDataTypeController::ArcPackageSyncDataTypeController(
-    syncer::ModelType type,
-    const base::Closure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    Profile* profile)
-    : syncer::AsyncDirectoryTypeController(type,
-                                           dump_stack,
-                                           sync_service,
-                                           sync_client,
-                                           syncer::GROUP_UI,
-                                           base::ThreadTaskRunnerHandle::Get()),
-      profile_(profile) {
-  arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get();
-  if (arc_session_manager)
-    arc_session_manager->AddObserver(this);
-}
-
-ArcPackageSyncDataTypeController::~ArcPackageSyncDataTypeController() {
-  arc::ArcSessionManager* arc_session_manager = arc::ArcSessionManager::Get();
-  if (arc_session_manager)
-    arc_session_manager->RemoveObserver(this);
-}
-
-bool ArcPackageSyncDataTypeController::ReadyForStart() const {
-  DCHECK(CalledOnValidThread());
-  // In sync integration test, always consider the DTC as ready for start.
-  return ArcAppListPrefsFactory::IsFactorySetForSyncTest() ||
-         (arc::IsArcPlayStoreEnabledForProfile(profile_) && ShouldSyncArc());
-}
-
-bool ArcPackageSyncDataTypeController::StartModels() {
-  DCHECK_EQ(state(), MODEL_STARTING);
-  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
-  DCHECK(arc_prefs);
-  model_normal_start_ = arc_prefs->package_list_initial_refreshed();
-  arc_prefs->AddObserver(this);
-  return model_normal_start_;
-}
-
-void ArcPackageSyncDataTypeController::StopModels() {
-  ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile_);
-  if (arc_prefs)
-    arc_prefs->RemoveObserver(this);
-}
-
-void ArcPackageSyncDataTypeController::OnPackageListInitialRefreshed() {
-  // model_normal_start_ is true by default. Normally,
-  // ArcPackageSyncDataTypeController::StartModels() gets called before ARC
-  // package list is refreshed. But in integration test, the order can be either
-  // way. If OnPackageListInitialRefreshed comes before
-  // ArcPackageSyncDataTypeController ::StartModels(), this function is no-op
-  // and waits for StartModels() to be called.
-  if (model_normal_start_)
-    return;
-
-  model_normal_start_ = true;
-  OnModelLoaded();
-}
-
-void ArcPackageSyncDataTypeController::OnArcPlayStoreEnabledChanged(
-    bool enabled) {
-  DCHECK(CalledOnValidThread());
-
-  sync_service()->ReadyForStartChanged(type());
-}
-
-void ArcPackageSyncDataTypeController::OnArcInitialStart() {
-  sync_service()->ReadyForStartChanged(type());
-}
-
-bool ArcPackageSyncDataTypeController::ShouldSyncArc() const {
-  return sync_service()->GetPreferredDataTypes().Has(type());
-}
diff --git a/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h b/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h
deleted file mode 100644
index c6b8738..0000000
--- a/chrome/browser/ui/app_list/arc/arc_package_sync_data_type_controller.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PACKAGE_SYNC_DATA_TYPE_CONTROLLER_H_
-#define CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PACKAGE_SYNC_DATA_TYPE_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "chrome/browser/chromeos/arc/arc_session_manager.h"
-#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-#include "components/sync/driver/data_type_controller.h"
-
-class Profile;
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-// A DataTypeController for arc package sync datatypes, which enables or
-// disables these types based on whether ArcAppInstance is ready.
-class ArcPackageSyncDataTypeController
-    : public syncer::AsyncDirectoryTypeController,
-      public ArcAppListPrefs::Observer,
-      public arc::ArcSessionManager::Observer {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  ArcPackageSyncDataTypeController(syncer::ModelType type,
-                                   const base::Closure& dump_stack,
-                                   syncer::SyncService* sync_service,
-                                   syncer::SyncClient* sync_client,
-                                   Profile* profile);
-  ~ArcPackageSyncDataTypeController() override;
-
-  // AsyncDirectoryTypeController implementation.
-  bool ReadyForStart() const override;
-  bool StartModels() override;
-  void StopModels() override;
-
- private:
-  // ArcAppListPrefs::Observer:
-  void OnPackageListInitialRefreshed() override;
-
-  // ArcSessionManager::Observer:
-  void OnArcPlayStoreEnabledChanged(bool enabled) override;
-  void OnArcInitialStart() override;
-
-  // Returns true if user enables app sync.
-  bool ShouldSyncArc() const;
-
-  bool model_normal_start_ = true;
-
-  Profile* const profile_;
-
-  DISALLOW_COPY_AND_ASSIGN(ArcPackageSyncDataTypeController);
-};
-#endif  // CHROME_BROWSER_UI_APP_LIST_ARC_ARC_PACKAGE_SYNC_DATA_TYPE_CONTROLLER_H_
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc
index 45138ca..a0d3978d 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/ash/chrome_new_window_client.h"
 
+#include <string>
 #include <utility>
 
 #include "ash/public/cpp/ash_features.h"
@@ -87,6 +88,19 @@
   return url;
 }
 
+// Returns URL path and query without the "/" prefix. For example, for the URL
+// "chrome://settings/networks/?type=WiFi" returns "networks/?type=WiFi".
+std::string GetPathAndQuery(const GURL& url) {
+  std::string result = url.path();
+  if (!result.empty() && result[0] == '/')
+    result.erase(0, 1);
+  if (url.has_query()) {
+    result += '?';
+    result += url.query();
+  }
+  return result;
+}
+
 // Implementation of CustomTabSession interface.
 class CustomTabSessionImpl : public arc::mojom::CustomTabSession {
  public:
@@ -474,13 +488,15 @@
     // Show browser settings (e.g. chrome://settings). This may open in a window
     // or a tab depending on feature SplitSettings.
     if (url.host() == chrome::kChromeUISettingsHost) {
-      chrome::ShowSettingsSubPageForProfile(profile,
-                                            /*sub_page=*/std::string());
+      std::string sub_page = GetPathAndQuery(url);
+      chrome::ShowSettingsSubPageForProfile(profile, sub_page);
       return nullptr;
     }
     // OS settings are shown in a window.
     if (url.host() == chrome::kChromeUIOSSettingsHost) {
-      chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(profile);
+      std::string sub_page = GetPathAndQuery(url);
+      chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(profile,
+                                                                   sub_page);
       return nullptr;
     }
   }
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
index 48fd0166..00628b2d 100644
--- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
+++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -12,6 +12,8 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/settings_window_manager_chromeos.h"
+#include "chrome/browser/ui/settings_window_manager_observer_chromeos.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/account_id/account_id.h"
@@ -161,3 +163,28 @@
     EXPECT_NE(nullptr, contents->GetUserData(key));
   }
 }
+
+IN_PROC_BROWSER_TEST_F(ChromeNewWindowClientBrowserTest, OpenSettingsFromArc) {
+  class Observer : public chrome::SettingsWindowManagerObserver {
+   public:
+    void OnNewSettingsWindow(Browser* settings_browser) override {
+      ++new_settings_count_;
+    }
+    int new_settings_count_ = 0;
+  } observer;
+
+  auto* settings = chrome::SettingsWindowManager::GetInstance();
+  settings->AddObserver(&observer);
+
+  // Navigating to Wi-Fi settings opens a new settings window.
+  GURL wifi_url("chrome://settings/networks/?type=WiFi");
+  ChromeNewWindowClient::Get()->OpenUrlFromArc(wifi_url);
+  EXPECT_EQ(1, observer.new_settings_count_);
+
+  // The window loads Wi-Fi settings (not just the settings main page).
+  content::WebContents* contents =
+      GetLastActiveBrowser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_EQ(wifi_url, contents->GetVisibleURL());
+
+  settings->RemoveObserver(&observer);
+}
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
index a0a9988..871d94eb 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.cc
@@ -283,8 +283,8 @@
              syncer::SyncService::DISABLE_REASON_USER_CHOICE);
 }
 
-bool SaveCardBubbleControllerImpl::CanAnimate() const {
-  return can_animate_;
+bool SaveCardBubbleControllerImpl::ShouldShowCardSavedAnimation() const {
+  return should_show_card_saved_animation_;
 }
 
 void SaveCardBubbleControllerImpl::OnSyncPromoAccepted(
@@ -327,7 +327,7 @@
       DCHECK(!local_save_card_prompt_callback_.is_null());
       // Show an animated card saved confirmation message next time
       // UpdateSaveCardIcon() is called.
-      can_animate_ = true;
+      should_show_card_saved_animation_ = true;
 
       std::move(local_save_card_prompt_callback_).Run(AutofillClient::ACCEPTED);
       break;
@@ -427,7 +427,7 @@
 void SaveCardBubbleControllerImpl::OnAnimationEnded() {
   // Do not repeat the animation next time UpdateSaveCardIcon() is called,
   // unless explicitly set somewhere else.
-  can_animate_ = false;
+  should_show_card_saved_animation_ = false;
 
   // We do not want to show the promo if the user clicked on the icon and the
   // manage cards bubble started to show.
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
index 126ebf9..3fccd9c7 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl.h
@@ -112,7 +112,7 @@
   //    to the server -- this should change.
   // TODO(crbug.com/864702): Don't show promo if user is a butter user.
   bool ShouldShowSignInPromo() const override;
-  bool CanAnimate() const override;
+  bool ShouldShowCardSavedAnimation() const override;
   void OnSyncPromoAccepted(const AccountInfo& account,
                            signin_metrics::AccessPoint access_point,
                            bool is_default_promo_account) override;
@@ -170,8 +170,8 @@
   // Should outlive this object.
   PersonalDataManager* personal_data_manager_;
 
-  // Is true only if the card saved animation can be shown.
-  bool can_animate_ = false;
+  // Is true only if the card saved animation should be shown.
+  bool should_show_card_saved_animation_ = false;
 
   // Weak reference. Will be nullptr if no bubble is currently shown.
   SaveCardBubbleView* save_card_bubble_view_ = nullptr;
diff --git a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
index c087130..0893dbbf 100644
--- a/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
+++ b/chrome/browser/ui/autofill/payments/save_card_bubble_controller_impl_unittest.cc
@@ -142,7 +142,7 @@
 
   void ClickSaveButton() {
     controller()->OnSaveButton({});
-    if (controller()->CanAnimate())
+    if (controller()->ShouldShowCardSavedAnimation())
       controller()->OnAnimationEnded();
   }
 
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_icon_view.cc b/chrome/browser/ui/views/autofill/payments/save_card_icon_view.cc
index 89852de4..8a104c3 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_icon_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_icon_view.cc
@@ -57,9 +57,8 @@
   enabled &= SetCommandEnabled(enabled);
   SetVisible(enabled);
 
-  if (enabled && controller->CanAnimate()) {
+  if (enabled && controller->ShouldShowCardSavedAnimation())
     AnimateIn(IDS_AUTOFILL_CARD_SAVED);
-  }
 
   return was_visible != visible();
 }
diff --git a/chrome/browser/ui/views/location_bar/location_bar_view.cc b/chrome/browser/ui/views/location_bar/location_bar_view.cc
index f07d8f7..153fb78 100644
--- a/chrome/browser/ui/views/location_bar/location_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_bar_view.cc
@@ -623,8 +623,11 @@
 
 void LocationBarView::OnThemeChanged() {
   tint_ = GetTint();
+  SkColor icon_color = GetColor(OmniboxPart::RESULTS_ICON);
   for (PageActionIconView* icon_view : page_action_icons_)
-    icon_view->SetIconColor(GetColor(OmniboxPart::RESULTS_ICON));
+    icon_view->SetIconColor(icon_color);
+  for (ContentSettingImageView* image_view : content_setting_views_)
+    image_view->SetIconColor(icon_color);
 }
 
 void LocationBarView::OnNativeThemeChanged(const ui::NativeTheme* theme) {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
index 2136ea0..73cbd4e3 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_match_cell_view.cc
@@ -9,6 +9,7 @@
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "base/metrics/field_trial_params.h"
+#include "base/optional.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
@@ -69,14 +70,16 @@
   int vertical_margin =
       is_two_line ? kTwoLineRowMarginHeight : kOneLineRowMarginHeight;
 
-  if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalMargin)) {
+  base::Optional<int> vertical_margin_override =
+      OmniboxFieldTrial::GetSuggestionVerticalMarginFieldTrialOverride();
+  if (vertical_margin_override) {
     // If the vertical margin experiment is on, we purposely set both the
     // one-line and two-line suggestions to have the same vertical margin.
     //
     // There is no vertical margin value we could set to make the new answer
     // style look anything similar to the pre-Refresh style, but setting them to
     // be the same looks reasonable, and is a sane place to start experimenting.
-    vertical_margin = OmniboxFieldTrial::GetSuggestionVerticalMargin();
+    vertical_margin = vertical_margin_override.value();
   }
 
   return gfx::Insets(vertical_margin, kMarginLeft, vertical_margin,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
index 3d9e323..eeae1f2f 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -8,6 +8,7 @@
 #include <numeric>
 
 #include "base/bind.h"
+#include "base/optional.h"
 #include "build/build_config.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
@@ -398,11 +399,13 @@
   // interior between each row of text.
   popup_height += RoundedOmniboxResultsFrame::GetNonResultSectionHeight();
 
-  if (base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalMargin)) {
+  base::Optional<int> vertical_margin_override =
+      OmniboxFieldTrial::GetSuggestionVerticalMarginFieldTrialOverride();
+  if (vertical_margin_override) {
     // If the vertical margin experiment uses a very small value (like a value
     // similar to pre-Refresh), we need to pad up the popup height at the
     // bottom (just like pre-Refresh) to prevent it from looking very bad.
-    if (OmniboxFieldTrial::GetSuggestionVerticalMargin() < 4)
+    if (vertical_margin_override.value() < 4)
       popup_height += 4;
   }
 
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 7dc7917..2fc09c1 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -169,7 +169,7 @@
       omnibox::kUIExperimentBlueSearchLoopAndSearchQuery);
   if (match_.answer) {
     const bool reverse = OmniboxFieldTrial::IsReverseAnswersEnabled() &&
-                         !match_.IsExceptedFromLineReversal();
+                         !match_.answer->IsExceptedFromLineReversal();
     if (reverse) {
       suggestion_view_->content()->SetText(match_.answer->second_line());
       suggestion_view_->description()->SetText(match_.contents,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
index 1c83ad2..2693525 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
@@ -55,7 +55,7 @@
     SetText(hint_);
   }
   SetTooltipText(hint_);
-  set_corner_radius(CalculatePreferredSize().height() / 2.f);
+  set_corner_radius(kButtonHeight / 2.f);
   animation_->SetSlideDuration(500);
   SetElideBehavior(gfx::FADE_TAIL);
 
@@ -134,7 +134,7 @@
   size_t preferred_width = CalculateGoalWidth(parent_width, &goal_text_);
   if (!initialized_) {
     initialized_ = true;
-    goal_width_ = preferred_width;
+    goal_width_ = start_width_ = preferred_width;
     animation_->Reset(1);
     SetText(goal_text_);
     return;
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
index 6fed4fe..355d8ee 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/ssl/security_state_tab_helper.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/hover_button.h"
@@ -21,10 +22,15 @@
 #include "components/content_settings/core/common/pref_names.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/ssl_status.h"
+#include "content/public/test/browser_side_navigation_test_utils.h"
+#include "content/public/test/navigation_simulator.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_web_contents_factory.h"
 #include "device/usb/public/cpp/fake_usb_device_manager.h"
 #include "device/usb/public/mojom/device.mojom.h"
+#include "net/ssl/ssl_connection_status_flags.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -41,6 +47,7 @@
 #endif
 
 const char* kUrl = "http://www.example.com/index.html";
+const char* kSecureUrl = "https://www.example.com/index.html";
 
 namespace test {
 
@@ -70,6 +77,8 @@
   PageInfoBubbleView* view() { return view_; }
   views::View* permissions_view() { return view_->permissions_view_; }
 
+  base::string16 GetWindowTitle() { return view_->GetWindowTitle(); }
+
   PermissionSelectorRow* GetPermissionSelectorAt(int index) {
     return view_->selector_rows_[index].get();
   }
@@ -586,3 +595,37 @@
   EXPECT_EQ(base::ASCIIToUTF16("Flash"), label->text());
 }
 #endif
+
+// Tests opening the bubble between navigation start and finish. The bubble
+// should be updated to reflect the secure state after the navigation commits.
+TEST_F(PageInfoBubbleViewTest, OpenPageInfoBubbleAfterNavigationStart) {
+  content::BrowserSideNavigationSetUp();
+  SecurityStateTabHelper::CreateForWebContents(
+      web_contents_helper_.web_contents());
+  std::unique_ptr<content::NavigationSimulator> navigation =
+      content::NavigationSimulator::CreateRendererInitiated(
+          GURL(kSecureUrl),
+          web_contents_helper_.web_contents()->GetMainFrame());
+  navigation->Start();
+  api_->CreateView();
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_NOT_SECURE_SUMMARY),
+            api_->GetWindowTitle());
+
+  // Set up a test SSLInfo so that Page Info sees the connection as secure.
+  uint16_t cipher_suite = 0xc02f;  // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+  int connection_status = 0;
+  net::SSLConnectionStatusSetCipherSuite(cipher_suite, &connection_status);
+  net::SSLConnectionStatusSetVersion(net::SSL_CONNECTION_VERSION_TLS1_2,
+                                     &connection_status);
+  net::SSLInfo ssl_info;
+  ssl_info.connection_status = connection_status;
+  ssl_info.cert =
+      net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+  ASSERT_TRUE(ssl_info.cert);
+
+  navigation->SetSSLInfo(ssl_info);
+
+  navigation->Commit();
+  EXPECT_EQ(l10n_util::GetStringUTF16(IDS_PAGE_INFO_SECURE_SUMMARY),
+            api_->GetWindowTitle());
+}
diff --git a/chrome/browser/ui/views/passwords/password_pending_view.cc b/chrome/browser/ui/views/passwords/password_pending_view.cc
index 4330df6..a2a0b92 100644
--- a/chrome/browser/ui/views/passwords/password_pending_view.cc
+++ b/chrome/browser/ui/views/passwords/password_pending_view.cc
@@ -176,7 +176,7 @@
 std::unique_ptr<views::EditableCombobox> CreatePasswordEditableCombobox(
     const autofill::PasswordForm& form,
     bool are_passwords_revealed) {
-  DCHECK(form.federation_origin.opaque());
+  DCHECK(!form.IsFederatedCredential());
   const std::vector<base::string16> passwords =
       form.all_possible_passwords.empty()
           ? std::vector<base::string16>(/*n=*/1, form.password_value)
@@ -212,7 +212,7 @@
          model()->state() ==
              password_manager::ui::PENDING_PASSWORD_UPDATE_STATE);
   const autofill::PasswordForm& password_form = model()->pending_password();
-  if (!password_form.federation_origin.opaque()) {
+  if (password_form.IsFederatedCredential()) {
     // The credential to be saved doesn't contain password but just the identity
     // provider (e.g. "Sign in with Google"). Thus, the layout is different.
     SetLayoutManager(std::make_unique<views::FillLayout>());
@@ -357,6 +357,7 @@
 
 bool PasswordPendingView::IsDialogButtonEnabled(ui::DialogButton button) const {
   return button != ui::DIALOG_BUTTON_OK ||
+         model()->pending_password().IsFederatedCredential() ||
          !model()->pending_password().password_value.empty();
 }
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc
index f4cd0e9..2b4b208 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.cc
@@ -6,16 +6,30 @@
 
 #include <memory>
 
+#include "chrome/browser/ui/layout_constants.h"
 #include "ui/views/layout/flex_layout.h"
+#include "ui/views/view_class_properties.h"
 
 ToolbarIconContainerView::ToolbarIconContainerView() {
-  SetLayoutManager(std::make_unique<views::FlexLayout>());
+  auto layout_manager = std::make_unique<views::FlexLayout>();
+  layout_manager->SetCollapseMargins(true).SetDefaultChildMargins(
+      gfx::Insets(0, 0, 0, GetLayoutConstant(TOOLBAR_ELEMENT_PADDING)));
+  SetLayoutManager(std::move(layout_manager));
 }
 
 ToolbarIconContainerView::~ToolbarIconContainerView() = default;
 
 void ToolbarIconContainerView::UpdateAllIcons() {}
 
+void ToolbarIconContainerView::AddMainView(views::View* main_view) {
+  DCHECK(!main_view_);
+  // Set empty margins from this view to negate the default ones set in the
+  // constructor.
+  main_view->SetProperty(views::kMarginsKey, new gfx::Insets());
+  main_view_ = main_view;
+  AddChildView(main_view_);
+}
+
 void ToolbarIconContainerView::ChildPreferredSizeChanged(views::View* child) {
   PreferredSizeChanged();
 }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
index 0d89b3d..2d01db25 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_icon_container_view.h
@@ -17,11 +17,18 @@
   // Update all the icons it contains. Override by subclass.
   virtual void UpdateAllIcons();
 
+  // Adds the RHS child as well as setting its margins.
+  void AddMainView(views::View* main_view);
+
  private:
-  // views::View
+  // views::View:
   void ChildPreferredSizeChanged(views::View* child) override;
   void ChildVisibilityChanged(views::View* child) override;
 
+  // The main view is nominally always present and is last child in the view
+  // hierarchy.
+  views::View* main_view_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(ToolbarIconContainerView);
 };
 
diff --git a/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc b/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc
index e4a8340..fcee5a454 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_page_action_icon_container_view.cc
@@ -41,7 +41,7 @@
   }
 
   avatar_ = new AvatarToolbarButton(browser);
-  AddChildView(avatar_);
+  AddMainView(avatar_);
 }
 
 ToolbarPageActionIconContainerView::~ToolbarPageActionIconContainerView() =
diff --git a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h
index 4a38e03..a4a24de 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/app_downloading_screen_handler.h
@@ -32,6 +32,8 @@
 class AppDownloadingScreenHandler : public BaseScreenHandler,
                                     public AppDownloadingScreenView {
  public:
+  using TView = AppDownloadingScreenView;
+
   explicit AppDownloadingScreenHandler(JSCallsContainer* js_calls_container);
   ~AppDownloadingScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
index 250e858dfc..52d9c9a 100644
--- a/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/app_launch_splash_screen_handler.h
@@ -60,6 +60,8 @@
       public AppLaunchSplashScreenView,
       public NetworkStateInformer::NetworkStateInformerObserver {
  public:
+  using TView = AppLaunchSplashScreenView;
+
   AppLaunchSplashScreenHandler(
       JSCallsContainer* js_calls_container,
       const scoped_refptr<NetworkStateInformer>& network_state_informer,
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
index b5166a33..0b0a86bc 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/arc_kiosk_splash_screen_handler.h
@@ -50,6 +50,8 @@
 class ArcKioskSplashScreenHandler : public BaseScreenHandler,
                                     public ArcKioskSplashScreenView {
  public:
+  using TView = ArcKioskSplashScreenView;
+
   explicit ArcKioskSplashScreenHandler(JSCallsContainer* js_calls_container);
   ~ArcKioskSplashScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
index 7326af2..cff8cb2 100644
--- a/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/arc_terms_of_service_screen_handler.h
@@ -23,6 +23,7 @@
 namespace chromeos {
 
 class ArcTermsOfServiceScreen;
+class ArcTermsOfServiceScreenView;
 
 class ArcTermsOfServiceScreenViewObserver {
  public:
@@ -81,6 +82,8 @@
       public system::TimezoneSettings::Observer,
       public chromeos::NetworkStateHandlerObserver {
  public:
+  using TView = ArcTermsOfServiceScreenView;
+
   explicit ArcTermsOfServiceScreenHandler(JSCallsContainer* js_calls_container);
   ~ArcTermsOfServiceScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
index 7e855fd3..71319f1 100644
--- a/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/assistant_optin_flow_screen_handler.h
@@ -47,6 +47,8 @@
       public arc::VoiceInteractionControllerClient::Observer,
       assistant::mojom::SpeakerIdEnrollmentClient {
  public:
+  using TView = AssistantOptInFlowScreenView;
+
   explicit AssistantOptInFlowScreenHandler(
       JSCallsContainer* js_calls_container);
   ~AssistantOptInFlowScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
index 5ca9668..7ac15fc 100644
--- a/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/auto_enrollment_check_screen_handler.h
@@ -17,6 +17,8 @@
 class AutoEnrollmentCheckScreenHandler : public AutoEnrollmentCheckScreenView,
                                          public BaseScreenHandler {
  public:
+  using TView = AutoEnrollmentCheckScreenView;
+
   explicit AutoEnrollmentCheckScreenHandler(
       JSCallsContainer* js_calls_container);
   ~AutoEnrollmentCheckScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h
index 98c7564..55459002 100644
--- a/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/demo_preferences_screen_handler.h
@@ -38,6 +38,8 @@
 class DemoPreferencesScreenHandler : public BaseScreenHandler,
                                      public DemoPreferencesScreenView {
  public:
+  using TView = DemoPreferencesScreenView;
+
   explicit DemoPreferencesScreenHandler(JSCallsContainer* js_calls_container);
   ~DemoPreferencesScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h
index a160308..74e2d4bb 100644
--- a/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/demo_setup_screen_handler.h
@@ -41,6 +41,8 @@
 class DemoSetupScreenHandler : public BaseScreenHandler,
                                public DemoSetupScreenView {
  public:
+  using TView = DemoSetupScreenView;
+
   explicit DemoSetupScreenHandler(JSCallsContainer* js_calls_container);
   ~DemoSetupScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
index 7ba286e..f90ad43 100644
--- a/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/device_disabled_screen_handler.h
@@ -29,6 +29,8 @@
 class DeviceDisabledScreenHandler : public DeviceDisabledScreenView,
                                     public BaseScreenHandler {
  public:
+  using TView = DeviceDisabledScreenView;
+
   explicit DeviceDisabledScreenHandler(JSCallsContainer* js_calls_container);
   ~DeviceDisabledScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h
index d5a4cf7..495d3f6 100644
--- a/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/discover_screen_handler.h
@@ -35,6 +35,8 @@
 class DiscoverScreenHandler : public BaseScreenHandler,
                               public DiscoverScreenView {
  public:
+  using TView = DiscoverScreenView;
+
   explicit DiscoverScreenHandler(JSCallsContainer* js_calls_container);
   ~DiscoverScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
index 2dae08b3..f145b4b1e 100644
--- a/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enable_debugging_screen_handler.h
@@ -36,6 +36,8 @@
 class EnableDebuggingScreenHandler : public EnableDebuggingScreenView,
                                      public BaseScreenHandler {
  public:
+  using TView = EnableDebuggingScreenView;
+
   explicit EnableDebuggingScreenHandler(JSCallsContainer* js_calls_container);
   ~EnableDebuggingScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
index 70ac8c16d..68916602 100644
--- a/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/encryption_migration_screen_handler.h
@@ -58,6 +58,8 @@
                                          public CryptohomeClient::Observer,
                                          public PowerManagerClient::Observer {
  public:
+  using TView = EncryptionMigrationScreenView;
+
   explicit EncryptionMigrationScreenHandler(
       JSCallsContainer* js_calls_container);
   ~EncryptionMigrationScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
index 1c3e6cf8..0d4ff94 100644
--- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h
@@ -58,6 +58,8 @@
       public EnrollmentScreenView,
       public NetworkStateInformer::NetworkStateInformerObserver {
  public:
+  using TView = EnrollmentScreenView;
+
   EnrollmentScreenHandler(
       JSCallsContainer* js_calls_container,
       const scoped_refptr<NetworkStateInformer>& network_state_informer,
diff --git a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h
index 241095f4..b31cd28d 100644
--- a/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/error_screen_handler.h
@@ -58,6 +58,8 @@
 // A class that handles the WebUI hooks in error screen.
 class ErrorScreenHandler : public BaseScreenHandler, public ErrorScreenView {
  public:
+  using TView = ErrorScreenView;
+
   explicit ErrorScreenHandler(JSCallsContainer* js_calls_container);
   ~ErrorScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
index 949db98b..4d77296b 100644
--- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
@@ -42,6 +42,8 @@
 // with the eula part of the JS page.
 class EulaScreenHandler : public EulaView, public BaseScreenHandler {
  public:
+  using TView = EulaView;
+
   EulaScreenHandler(JSCallsContainer* js_calls_container,
                     CoreOobeView* core_oobe_view);
   ~EulaScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h
index ae999ba..8eb35772 100644
--- a/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/fingerprint_setup_screen_handler.h
@@ -38,6 +38,8 @@
       public FingerprintSetupScreenView,
       public device::mojom::FingerprintObserver {
  public:
+  using TView = FingerprintSetupScreenView;
+
   explicit FingerprintSetupScreenHandler(JSCallsContainer* js_calls_container);
   ~FingerprintSetupScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
index 3b442c1..8dbda25 100644
--- a/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/hid_detection_screen_handler.h
@@ -53,6 +53,8 @@
     : public HIDDetectionView,
       public BaseScreenHandler {
  public:
+  using TView = HIDDetectionView;
+
   HIDDetectionScreenHandler(JSCallsContainer* js_calls_container,
                             CoreOobeView* core_oobe_view);
   ~HIDDetectionScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
index dcf3379..b841c25 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_autolaunch_screen_handler.h
@@ -32,6 +32,8 @@
                                      public KioskAppManagerObserver,
                                      public BaseScreenHandler {
  public:
+  using TView = KioskAutolaunchScreenView;
+
   explicit KioskAutolaunchScreenHandler(JSCallsContainer* js_calls_container);
   ~KioskAutolaunchScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
index 7af84fcd..c82e3f1 100644
--- a/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/kiosk_enable_screen_handler.h
@@ -31,6 +31,8 @@
 class KioskEnableScreenHandler : public KioskEnableScreenView,
                                  public BaseScreenHandler {
  public:
+  using TView = KioskEnableScreenView;
+
   explicit KioskEnableScreenHandler(JSCallsContainer* js_calls_container);
   ~KioskEnableScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
index ae77194e..3f934b9e 100644
--- a/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/marketing_opt_in_screen_handler.h
@@ -34,6 +34,8 @@
 class MarketingOptInScreenHandler : public BaseScreenHandler,
                                     public MarketingOptInScreenView {
  public:
+  using TView = MarketingOptInScreenView;
+
   explicit MarketingOptInScreenHandler(JSCallsContainer* js_calls_container);
   ~MarketingOptInScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h
index 4c44af37..3b0579e 100644
--- a/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/multidevice_setup_screen_handler.h
@@ -29,6 +29,8 @@
 class MultiDeviceSetupScreenHandler : public BaseScreenHandler,
                                       public MultiDeviceSetupScreenView {
  public:
+  using TView = MultiDeviceSetupScreenView;
+
   explicit MultiDeviceSetupScreenHandler(JSCallsContainer* js_calls_container);
   ~MultiDeviceSetupScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h
index cf25f418..94e179f 100644
--- a/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/network_screen_handler.h
@@ -52,6 +52,8 @@
 class NetworkScreenHandler : public NetworkScreenView,
                              public BaseScreenHandler {
  public:
+  using TView = NetworkScreenView;
+
   NetworkScreenHandler(JSCallsContainer* js_calls_container,
                        CoreOobeView* core_oobe_view);
   ~NetworkScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
index 344d4597..059aa11 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.cc
@@ -344,8 +344,7 @@
   AddScreenHandler(
       std::make_unique<ErrorScreenHandler>(js_calls_container_.get()));
 
-  error_screen_ =
-      std::make_unique<ErrorScreen>(GetHandler<ErrorScreenHandler>());
+  error_screen_ = std::make_unique<ErrorScreen>(GetView<ErrorScreenHandler>());
   ErrorScreen* error_screen = error_screen_.get();
 
   AddScreenHandler(std::make_unique<EnrollmentScreenHandler>(
@@ -527,130 +526,10 @@
   return core_handler_;
 }
 
-WelcomeView* OobeUI::GetWelcomeView() {
-  return GetHandler<WelcomeScreenHandler>();
-}
-
-EulaView* OobeUI::GetEulaView() {
-  return GetHandler<EulaScreenHandler>();
-}
-
-UpdateView* OobeUI::GetUpdateView() {
-  return GetHandler<UpdateScreenHandler>();
-}
-
-EnableDebuggingScreenView* OobeUI::GetEnableDebuggingScreenView() {
-  return GetHandler<EnableDebuggingScreenHandler>();
-}
-
-EnrollmentScreenView* OobeUI::GetEnrollmentScreenView() {
-  return GetHandler<EnrollmentScreenHandler>();
-}
-
-ResetView* OobeUI::GetResetView() {
-  return GetHandler<ResetScreenHandler>();
-}
-
-DemoSetupScreenView* OobeUI::GetDemoSetupScreenView() {
-  return GetHandler<DemoSetupScreenHandler>();
-}
-
-DemoPreferencesScreenView* OobeUI::GetDemoPreferencesScreenView() {
-  return GetHandler<DemoPreferencesScreenHandler>();
-}
-
-FingerprintSetupScreenView* OobeUI::GetFingerprintSetupScreenView() {
-  return GetHandler<FingerprintSetupScreenHandler>();
-}
-
-KioskAutolaunchScreenView* OobeUI::GetKioskAutolaunchScreenView() {
-  return GetHandler<KioskAutolaunchScreenHandler>();
-}
-
-KioskEnableScreenView* OobeUI::GetKioskEnableScreenView() {
-  return GetHandler<KioskEnableScreenHandler>();
-}
-
-TermsOfServiceScreenView* OobeUI::GetTermsOfServiceScreenView() {
-  return GetHandler<TermsOfServiceScreenHandler>();
-}
-
-SyncConsentScreenView* OobeUI::GetSyncConsentScreenView() {
-  return GetHandler<SyncConsentScreenHandler>();
-}
-
-MarketingOptInScreenView* OobeUI::GetMarketingOptInScreenView() {
-  return GetHandler<MarketingOptInScreenHandler>();
-}
-
-ArcTermsOfServiceScreenView* OobeUI::GetArcTermsOfServiceScreenView() {
-  return GetHandler<ArcTermsOfServiceScreenHandler>();
-}
-
-RecommendAppsScreenView* OobeUI::GetRecommendAppsScreenView() {
-  return GetHandler<RecommendAppsScreenHandler>();
-}
-
-AppDownloadingScreenView* OobeUI::GetAppDownloadingScreenView() {
-  return GetHandler<AppDownloadingScreenHandler>();
-}
-
-WrongHWIDScreenView* OobeUI::GetWrongHWIDScreenView() {
-  return GetHandler<WrongHWIDScreenHandler>();
-}
-
-AutoEnrollmentCheckScreenView* OobeUI::GetAutoEnrollmentCheckScreenView() {
-  return GetHandler<AutoEnrollmentCheckScreenHandler>();
-}
-
-HIDDetectionView* OobeUI::GetHIDDetectionView() {
-  return GetHandler<HIDDetectionScreenHandler>();
-}
-
-DeviceDisabledScreenView* OobeUI::GetDeviceDisabledScreenView() {
-  return GetHandler<DeviceDisabledScreenHandler>();
-}
-
-EncryptionMigrationScreenView* OobeUI::GetEncryptionMigrationScreenView() {
-  return GetHandler<EncryptionMigrationScreenHandler>();
-}
-
-SupervisionTransitionScreenView* OobeUI::GetSupervisionTransitionScreenView() {
-  return GetHandler<SupervisionTransitionScreenHandler>();
-}
-
-UpdateRequiredView* OobeUI::GetUpdateRequiredScreenView() {
-  return GetHandler<UpdateRequiredScreenHandler>();
-}
-
-AssistantOptInFlowScreenView* OobeUI::GetAssistantOptInFlowScreenView() {
-  return GetHandler<AssistantOptInFlowScreenHandler>();
-}
-
-MultiDeviceSetupScreenView* OobeUI::GetMultiDeviceSetupScreenView() {
-  return GetHandler<MultiDeviceSetupScreenHandler>();
-}
-
 ErrorScreen* OobeUI::GetErrorScreen() {
   return error_screen_.get();
 }
 
-NetworkScreenView* OobeUI::GetNetworkScreenView() {
-  return GetHandler<NetworkScreenHandler>();
-}
-
-AppLaunchSplashScreenView* OobeUI::GetAppLaunchSplashScreenView() {
-  return GetHandler<AppLaunchSplashScreenHandler>();
-}
-
-ArcKioskSplashScreenView* OobeUI::GetArcKioskSplashScreenView() {
-  return GetHandler<ArcKioskSplashScreenHandler>();
-}
-
-DiscoverScreenView* OobeUI::GetDiscoverScreenView() {
-  return GetHandler<DiscoverScreenHandler>();
-}
-
 void OobeUI::GetLocalizedStrings(base::DictionaryValue* localized_strings) {
   for (BaseWebUIHandler* handler : webui_handlers_)
     handler->GetLocalizedStrings(localized_strings);
diff --git a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
index 0aa7cff..88d13769 100644
--- a/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
+++ b/chrome/browser/ui/webui/chromeos/login/oobe_ui.h
@@ -29,45 +29,14 @@
 }  // namespace service_manager
 
 namespace chromeos {
-class AppDownloadingScreenView;
-class AppLaunchSplashScreenView;
-class ArcKioskSplashScreenView;
-class ArcTermsOfServiceScreenView;
-class AssistantOptInFlowScreenView;
-class AutoEnrollmentCheckScreenView;
-class BaseScreenHandler;
-class CoreOobeView;
-class DemoPreferencesScreenView;
-class DemoSetupScreenView;
-class DeviceDisabledScreenView;
-class EnableDebuggingScreenView;
-class EncryptionMigrationScreenView;
-class EnrollmentScreenView;
-class EulaView;
+
 class ErrorScreen;
-class DiscoverScreenView;
-class FingerprintSetupScreenView;
-class HIDDetectionView;
-class KioskAutolaunchScreenView;
-class KioskEnableScreenView;
 class LoginScreenContext;
-class MarketingOptInScreenView;
-class MultiDeviceSetupScreenView;
 class NativeWindowDelegate;
-class NetworkScreenView;
 class NetworkStateInformer;
 class OobeDisplayChooser;
-class RecommendAppsScreenView;
-class ResetView;
 class SigninScreenHandler;
 class SigninScreenHandlerDelegate;
-class SyncConsentScreenView;
-class TermsOfServiceScreenView;
-class UpdateView;
-class UpdateRequiredView;
-class SupervisionTransitionScreenView;
-class WelcomeView;
-class WrongHWIDScreenView;
 
 // A custom WebUI that defines datasource for out-of-box-experience (OOBE) UI:
 // - welcome screen (setup language/keyboard/network).
@@ -103,37 +72,7 @@
   ~OobeUI() override;
 
   CoreOobeView* GetCoreOobeView();
-  WelcomeView* GetWelcomeView();
-  EulaView* GetEulaView();
-  UpdateView* GetUpdateView();
-  EnableDebuggingScreenView* GetEnableDebuggingScreenView();
-  EnrollmentScreenView* GetEnrollmentScreenView();
-  ResetView* GetResetView();
-  DemoSetupScreenView* GetDemoSetupScreenView();
-  DemoPreferencesScreenView* GetDemoPreferencesScreenView();
-  FingerprintSetupScreenView* GetFingerprintSetupScreenView();
-  KioskAutolaunchScreenView* GetKioskAutolaunchScreenView();
-  KioskEnableScreenView* GetKioskEnableScreenView();
-  TermsOfServiceScreenView* GetTermsOfServiceScreenView();
-  SyncConsentScreenView* GetSyncConsentScreenView();
-  ArcTermsOfServiceScreenView* GetArcTermsOfServiceScreenView();
-  RecommendAppsScreenView* GetRecommendAppsScreenView();
-  AppDownloadingScreenView* GetAppDownloadingScreenView();
   ErrorScreen* GetErrorScreen();
-  WrongHWIDScreenView* GetWrongHWIDScreenView();
-  AutoEnrollmentCheckScreenView* GetAutoEnrollmentCheckScreenView();
-  AppLaunchSplashScreenView* GetAppLaunchSplashScreenView();
-  ArcKioskSplashScreenView* GetArcKioskSplashScreenView();
-  HIDDetectionView* GetHIDDetectionView();
-  DeviceDisabledScreenView* GetDeviceDisabledScreenView();
-  EncryptionMigrationScreenView* GetEncryptionMigrationScreenView();
-  SupervisionTransitionScreenView* GetSupervisionTransitionScreenView();
-  UpdateRequiredView* GetUpdateRequiredScreenView();
-  AssistantOptInFlowScreenView* GetAssistantOptInFlowScreenView();
-  MultiDeviceSetupScreenView* GetMultiDeviceSetupScreenView();
-  DiscoverScreenView* GetDiscoverScreenView();
-  NetworkScreenView* GetNetworkScreenView();
-  MarketingOptInScreenView* GetMarketingOptInScreenView();
 
   // Collects localized strings from the owned handlers.
   void GetLocalizedStrings(base::DictionaryValue* localized_strings);
@@ -195,7 +134,6 @@
     return GetHandler<THandler>();
   }
 
- private:
   // Find a handler instance.
   template <typename THandler>
   THandler* GetHandler() {
@@ -210,6 +148,7 @@
     return nullptr;
   }
 
+ private:
   void AddWebUIHandler(std::unique_ptr<BaseWebUIHandler> handler);
   void AddScreenHandler(std::unique_ptr<BaseScreenHandler> handler);
 
diff --git a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
index bcb6aa5..23b672f 100644
--- a/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/recommend_apps_screen_handler.h
@@ -48,6 +48,8 @@
 class RecommendAppsScreenHandler : public BaseScreenHandler,
                                    public RecommendAppsScreenView {
  public:
+  using TView = RecommendAppsScreenView;
+
   explicit RecommendAppsScreenHandler(JSCallsContainer* js_calls_container);
   ~RecommendAppsScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
index 82f3843..c9ea00c 100644
--- a/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/reset_screen_handler.h
@@ -56,6 +56,8 @@
 class ResetScreenHandler : public ResetView,
                            public BaseScreenHandler {
  public:
+  using TView = ResetView;
+
   explicit ResetScreenHandler(JSCallsContainer* js_calls_container);
   ~ResetScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
index 5d30da68..502e70fd 100644
--- a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
@@ -44,6 +44,8 @@
     : public BaseScreenHandler,
       public SupervisionTransitionScreenView {
  public:
+  using TView = SupervisionTransitionScreenView;
+
   explicit SupervisionTransitionScreenHandler(
       JSCallsContainer* js_calls_container);
   ~SupervisionTransitionScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
index 8912c3b..fa73bb4 100644
--- a/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/sync_consent_screen_handler.h
@@ -40,6 +40,8 @@
 class SyncConsentScreenHandler : public BaseScreenHandler,
                                  public SyncConsentScreenView {
  public:
+  using TView = SyncConsentScreenView;
+
   explicit SyncConsentScreenHandler(JSCallsContainer* js_calls_container);
   ~SyncConsentScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
index 1a01bd4..a26fdf6 100644
--- a/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/terms_of_service_screen_handler.h
@@ -50,6 +50,8 @@
 class TermsOfServiceScreenHandler : public BaseScreenHandler,
                                     public TermsOfServiceScreenView {
  public:
+  using TView = TermsOfServiceScreenView;
+
   TermsOfServiceScreenHandler(JSCallsContainer* js_calls_container,
                               CoreOobeView* core_oobe_view);
   ~TermsOfServiceScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
index 037c4cd..7b05a5a 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_required_screen_handler.h
@@ -41,6 +41,8 @@
 class UpdateRequiredScreenHandler : public UpdateRequiredView,
                                     public BaseScreenHandler {
  public:
+  using TView = UpdateRequiredView;
+
   explicit UpdateRequiredScreenHandler(JSCallsContainer* js_calls_container);
   ~UpdateRequiredScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
index 7d19e0bea5..b8bec37 100644
--- a/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/update_screen_handler.h
@@ -48,6 +48,8 @@
 
 class UpdateScreenHandler : public UpdateView, public BaseScreenHandler {
  public:
+  using TView = UpdateView;
+
   explicit UpdateScreenHandler(JSCallsContainer* js_calls_container);
   ~UpdateScreenHandler() override;
 
diff --git a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
index 38b5be34..b3313a6 100644
--- a/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h
@@ -53,6 +53,8 @@
 // the welcome screen (part of the page) of the OOBE.
 class WelcomeScreenHandler : public WelcomeView, public BaseScreenHandler {
  public:
+  using TView = WelcomeView;
+
   WelcomeScreenHandler(JSCallsContainer* js_calls_container,
                        CoreOobeView* core_oobe_view);
   ~WelcomeScreenHandler() override;
diff --git a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
index 0113dc7..12e68a51 100644
--- a/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
+++ b/chrome/browser/ui/webui/chromeos/login/wrong_hwid_screen_handler.h
@@ -31,6 +31,8 @@
 class WrongHWIDScreenHandler : public WrongHWIDScreenView,
                                public BaseScreenHandler {
  public:
+  using TView = WrongHWIDScreenView;
+
   explicit WrongHWIDScreenHandler(JSCallsContainer* js_calls_container);
   ~WrongHWIDScreenHandler() override;
 
diff --git a/chrome/chrome_cleaner/README.md b/chrome/chrome_cleaner/README.md
index e9a6063..fe976c1d2 100644
--- a/chrome/chrome_cleaner/README.md
+++ b/chrome/chrome_cleaner/README.md
@@ -4,6 +4,8 @@
 standalone application distributed to Chrome users to find and remove Unwanted
 Software (UwS).
 
+The tool and its tests are Windows-only.
+
 ## Integration with Chrome
 
 The application is distributed in two versions:
@@ -29,18 +31,42 @@
 *   [Settings page user interaction handlers](/chrome/browser/ui/webui/settings)
     (files `chrome_cleanup_handler.*`)
 *   [UI for modal dialogs](/chrome/browser/ui/views) (files `chrome_cleaner_*`)
-*   [Shared constants and Mojo interfaces](/components/chrome_cleaner/public) -
+*   [Shared constants and IPC interfaces](/components/chrome_cleaner/public) -
     These are used for communication between Chrome and the Software Reporter /
     Chrome Cleanup Tool, so both this directory and the other Chromium
     directories above have dependencies on them.
 
+## Internal Resources
+
+If |is_official_chrome_cleaner_build| is set in GN, the build looks for
+internal resources in the chrome_cleaner_internal/ directory. These resources
+are not open source so are only available internally to Google. They include
+the licensed scanning engine used to find real-world UwS.
+
+Otherwise the build will link to the test scanning engine in
+`chrome/chrome_cleaner/engines/target/test_engine_delegate.cc` which only
+detects test files. This is the default when building on the Chromium
+buildbots.
+
+To ship a non-test version of the tool, implement EngineDelegate to wrap an
+engine that can detect and remove UwS. The engine will be run inside a sandbox
+with low privileges. To perform operations like opening file handles, scanning
+process memory, and deleting files, the engine will need to call the callbacks
+passed to EngineDelegate as |privileged_file_calls|, |privileged_scan_calls|
+and |privileged_removal_calls|.
+
 ## Status
 
-Incomplete: the source code for the Software Reporter and Chrome Cleanup Tool
-are currently being moved from a Google internal repository into this
-directory.
+Code complete. Some tests are still in the Google internal repository.
+
+The unit tests (`chrome_cleaner_unittests.exe`) are built and executed on the
+Chromium buildbots. The final binaries (`chrome_cleanup_tool.exe` and
+`software_reporter_tool.exe`) are also built because chrome_cleaner_unittests
+has an artificial dependency on them, but nothing currently executes them.
+
+[TODO(crbug.com/949669)](https://crbug.com/949669): add an integration test
+that builds and runs the binaries, and remove the artificial dependency.
 
 ## Contact
 
-csharp@chromium.org
 joenotcharles@google.com
diff --git a/chrome/chrome_cleaner/components/system_report_component.cc b/chrome/chrome_cleaner/components/system_report_component.cc
index 14912f6..54a733e2 100644
--- a/chrome/chrome_cleaner/components/system_report_component.cc
+++ b/chrome/chrome_cleaner/components/system_report_component.cc
@@ -41,6 +41,7 @@
 #include "base/win/scoped_bstr.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/scoped_variant.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "chrome/chrome_cleaner/chrome_utils/chrome_util.h"
 #include "chrome/chrome_cleaner/chrome_utils/extension_file_logger.h"
@@ -593,9 +594,7 @@
       const std::set<GUID, GUIDLess>& guids = provider->second;
       for (std::set<GUID, GUIDLess>::const_iterator guid = guids.begin();
            guid != guids.end(); ++guid) {
-        base::string16 guid_str;
-        GUIDToString(*guid, &guid_str);
-        logged_guids.push_back(guid_str);
+        logged_guids.push_back(base::win::String16FromGUID(*guid));
       }
       LoggingServiceAPI::GetInstance()->AddLayeredServiceProvider(
           logged_guids, file_information);
diff --git a/chrome/chrome_cleaner/os/disk_util.cc b/chrome/chrome_cleaner/os/disk_util.cc
index 3d042c80..37a54b4e 100644
--- a/chrome/chrome_cleaner/os/disk_util.cc
+++ b/chrome/chrome_cleaner/os/disk_util.cc
@@ -29,6 +29,7 @@
 #include "base/win/current_module.h"
 #include "base/win/registry.h"
 #include "base/win/shortcut.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "chrome/chrome_cleaner/constants/version.h"
 #include "chrome/chrome_cleaner/os/file_path_sanitization.h"
@@ -658,9 +659,9 @@
           providers->emplace(base::FilePath(path), std::set<GUID, GUIDLess>());
       inserted.first->second.insert(service_providers[i].ProviderId);
     } else {
-      base::string16 guid;
-      GUIDToString(service_providers[i].ProviderId, &guid);
-      LOG(ERROR) << "Couldn't get path for provider: " << guid;
+      LOG(ERROR) << "Couldn't get path for provider: "
+                 << base::win::String16FromGUID(
+                        service_providers[i].ProviderId);
     }
   }
 }
diff --git a/chrome/chrome_cleaner/os/system_util.cc b/chrome/chrome_cleaner/os/system_util.cc
index d3b919d0..55b8e57 100644
--- a/chrome/chrome_cleaner/os/system_util.cc
+++ b/chrome/chrome_cleaner/os/system_util.cc
@@ -72,14 +72,6 @@
   return true;
 }
 
-void GUIDToString(const GUID& guid, base::string16* output) {
-  DCHECK(output);
-  static const size_t kGUIDStringSize = 39;
-  int result = ::StringFromGUID2(guid, base::WriteInto(output, kGUIDStringSize),
-                                 kGUIDStringSize);
-  DCHECK(result == kGUIDStringSize);
-}
-
 void SetBackgroundMode() {
   // Get the process working set size and flags, so that we can reset them
   // after setting the process to background mode. For some reason Windows sets
diff --git a/chrome/chrome_cleaner/os/system_util.h b/chrome/chrome_cleaner/os/system_util.h
index f275c001..88d2e82 100644
--- a/chrome/chrome_cleaner/os/system_util.h
+++ b/chrome/chrome_cleaner/os/system_util.h
@@ -53,10 +53,6 @@
 // running on a Windows version before Vista.
 bool GetMediumIntegrityToken(base::win::ScopedHandle* medium_integrity_token);
 
-// Convert a GUID to its textual representation. |output| receives the textual
-// representation.
-void GUIDToString(const GUID&, base::string16* output);
-
 // Set the current process to background mode.
 void SetBackgroundMode();
 
diff --git a/chrome/chrome_cleaner/os/system_util_unittest.cc b/chrome/chrome_cleaner/os/system_util_unittest.cc
index 82d4e77..fcf80df0 100644
--- a/chrome/chrome_cleaner/os/system_util_unittest.cc
+++ b/chrome/chrome_cleaner/os/system_util_unittest.cc
@@ -34,16 +34,4 @@
   EXPECT_LT(integrity_level, SECURITY_MANDATORY_HIGH_RID);
 }
 
-TEST(SystemUtilTests, GUIDToString) {
-  base::string16 provider1;
-  base::string16 provider2;
-  base::string16 provider3;
-  GUIDToString(kGUID1, &provider1);
-  GUIDToString(kGUID2, &provider2);
-  GUIDToString(kGUID3, &provider3);
-  EXPECT_STREQ(provider1.c_str(), kGUID1Str);
-  EXPECT_STREQ(provider2.c_str(), kGUID2Str);
-  EXPECT_STREQ(provider3.c_str(), kGUID3Str);
-}
-
 }  // namespace chrome_cleaner
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 38f30f6..a5059c95 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -153,6 +153,8 @@
 const base::FilePath::CharType kMediaCacheDirname[] = FPL("Media Cache");
 const base::FilePath::CharType kNetworkPersistentStateFilename[] =
     FPL("Network Persistent State");
+const base::FilePath::CharType kNotificationSchedulerStorageDirname[] =
+    FPL("Notification Scheduler");
 const base::FilePath::CharType kOfflinePageArchivesDirname[] =
     FPL("Offline Pages/archives");
 const base::FilePath::CharType kOfflinePageMetadataDirname[] =
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 6cc29fb..43b1ce5 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -56,6 +56,7 @@
 extern const base::FilePath::CharType kLocalStateFilename[];
 extern const base::FilePath::CharType kMediaCacheDirname[];
 extern const base::FilePath::CharType kNetworkPersistentStateFilename[];
+extern const base::FilePath::CharType kNotificationSchedulerStorageDirname[];
 extern const base::FilePath::CharType kOfflinePageArchivesDirname[];
 extern const base::FilePath::CharType kOfflinePageMetadataDirname[];
 extern const base::FilePath::CharType kOfflinePagePrefetchStoreDirname[];
diff --git a/chrome/common/extensions/api/PRESUBMIT.py b/chrome/common/extensions/api/PRESUBMIT.py
index 851496e..0b33c830 100644
--- a/chrome/common/extensions/api/PRESUBMIT.py
+++ b/chrome/common/extensions/api/PRESUBMIT.py
@@ -28,7 +28,6 @@
   api_pair_names = {
     'activity_log_private.json': 'activity_log_private.js',
     'autofill_private.idl': 'autofill_private.js',
-    'automation.idl': 'automation.js',
     'developer_private.idl': 'developer_private.js',
     'bookmark_manager_private.json': 'bookmark_manager_private.js',
     'command_line_private.json': 'command_line_private.js',
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index fd0157a6..cb351822 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -110,15 +110,6 @@
       "chrome://settings/*"
     ]
   }],
-  "automationInternal": {
-    "internal": true,
-    "dependencies": ["manifest:automation"],
-    "contexts": ["blessed_extension"]
-  },
-  "automation": {
-    "dependencies": ["manifest:automation"],
-    "contexts": ["blessed_extension"]
-  },
   "autotestPrivate": {
     "dependencies": ["permission:autotestPrivate"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index c4228d01..4e5e62e 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -16,8 +16,6 @@
   "cast_streaming_session.idl",
   "cast_streaming_udp_transport.idl",
   "autofill_private.idl",
-  "automation.idl",
-  "automation_internal.idl",
   "autotest_private.idl",
   "bookmark_manager_private.json",
   "bookmarks.json",
diff --git a/chrome/common/extensions/chrome_extension_messages.h b/chrome/common/extensions/chrome_extension_messages.h
index f8f1ded6..23b0d41 100644
--- a/chrome/common/extensions/chrome_extension_messages.h
+++ b/chrome/common/extensions/chrome_extension_messages.h
@@ -15,7 +15,7 @@
 
 #include "base/strings/string16.h"
 #include "base/values.h"
-#include "chrome/common/extensions/api/automation_internal.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/common/stack_frame.h"
 #include "ipc/ipc_message_macros.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chrome/common/extensions/docs/templates/intros/declarativeNetRequest.html b/chrome/common/extensions/docs/templates/intros/declarativeNetRequest.html
index 129db14..c9748d6 100644
--- a/chrome/common/extensions/docs/templates/intros/declarativeNetRequest.html
+++ b/chrome/common/extensions/docs/templates/intros/declarativeNetRequest.html
@@ -309,6 +309,12 @@
     "priority" : 1,
     "action" : { "type" : "redirect", "redirectUrl" : "https://example.com" },
     "condition" : { "urlFilter" : "google.com", "resourceTypes" : ["main_frame"] }
+  },
+  {
+    "id" : 4,
+    "priority" : 1,
+    "action" : { "type" : "redirect", "redirectUrl" : "/a.jpg" },
+    "condition" : { "urlFilter" : "abcd.com", "resourceTypes" : ["main_frame"] }
   }
 ]
 </pre>
@@ -325,4 +331,9 @@
     <code>allow</code> rule, the request is not blocked and instead redirected
     to <code>"https://example.com"</code>.
   </li>
+  <li>
+    Consider a navigation to <code>"http://abcd.com"</code>. The rule with id
+    (4) matches. Since rule (4) specifies a relative URL, the request is
+    redirected to <code>"chrome-extension://&lt;extension-id&gt;/a.jpg"</code>.
+  </li>
 </ul>
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index 3011c1b..66c6b2f 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -1413,6 +1413,8 @@
       HRESULT hrWrite = HRESULT_FROM_WIN32(::GetLastError());
       LOGFN(ERROR) << "WriteFile hr=" << putHR(hrWrite);
     }
+
+    ::RtlSecureZeroMemory(const_cast<char*>(json.data()), json.size());
   } else {
     LOGFN(ERROR) << "base::JSONWriter::Write failed";
   }
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
index fc4215a0..c284b32 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_module.cc
@@ -8,6 +8,8 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/strings/string_util.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "chrome/common/chrome_version.h"
 #include "chrome/credential_provider/eventlog/gcp_eventlog_messages.h"
@@ -55,17 +57,15 @@
   eventlog_path =
       eventlog_path.Append(FILE_PATH_LITERAL("gcp_eventlog_provider.dll"));
 
-  wchar_t provider_guid_in_wchar[64];
-  StringFromGUID2(CLSID_GaiaCredentialProvider, provider_guid_in_wchar,
-                  base::size(provider_guid_in_wchar));
+  auto provider_guid_string =
+      base::win::String16FromGUID(CLSID_GaiaCredentialProvider);
 
-  wchar_t filter_guid_in_wchar[64];
-  StringFromGUID2(__uuidof(CGaiaCredentialProviderFilter), filter_guid_in_wchar,
-                  base::size(filter_guid_in_wchar));
+  auto filter_guid_string =
+      base::win::String16FromGUID(__uuidof(CGaiaCredentialProviderFilter));
 
   ATL::_ATL_REGMAP_ENTRY regmap[] = {
-      {L"CP_CLASS_GUID", provider_guid_in_wchar},
-      {L"CP_FILTER_CLASS_GUID", filter_guid_in_wchar},
+      {L"CP_CLASS_GUID", base::as_wcstr(provider_guid_string.c_str())},
+      {L"CP_FILTER_CLASS_GUID", base::as_wcstr(filter_guid_string.c_str())},
       {L"VERSION", TEXT(CHROME_VERSION_STRING)},
       {L"EVENTLOG_PATH", eventlog_path.value().c_str()},
       {nullptr, nullptr},
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc b/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc
index 63e9bce..f69e873 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_provider_unittests.cc
@@ -11,6 +11,7 @@
 
 #include "base/synchronization/waitable_event.h"
 #include "base/win/registry.h"
+#include "base/win/win_util.h"
 #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"
@@ -931,15 +932,14 @@
 
     // In the case that a real CReauthCredential is created, we expect that this
     // credential will set the default credential provider for the user tile.
-    wchar_t guid_in_wchar[64];
-    ::StringFromGUID2(CLSID_GaiaCredentialProvider, guid_in_wchar,
-                      base::size(guid_in_wchar));
+    auto guid_string =
+        base::win::String16FromGUID(CLSID_GaiaCredentialProvider);
 
     wchar_t guid_in_registry[64];
     ULONG length = base::size(guid_in_registry);
     EXPECT_EQ(S_OK, GetMachineRegString(kLogonUiUserTileRegKey, sid,
                                         guid_in_registry, &length));
-    EXPECT_EQ(base::string16(guid_in_wchar), base::string16(guid_in_registry));
+    EXPECT_EQ(guid_string, base::string16(guid_in_registry));
     ::CoTaskMemFree(sid);
   }
 
diff --git a/chrome/credential_provider/gaiacp/gcp_utils_unittests.cc b/chrome/credential_provider/gaiacp/gcp_utils_unittests.cc
index 3063548..32469b8 100644
--- a/chrome/credential_provider/gaiacp/gcp_utils_unittests.cc
+++ b/chrome/credential_provider/gaiacp/gcp_utils_unittests.cc
@@ -433,12 +433,6 @@
 
   // EnrollToGoogleMdmIfNeeded() should be a noop.
   base::Value properties(base::Value::Type::DICTIONARY);
-  properties.SetStringKey(kKeyEmail, "foo@gmail.com");
-  properties.SetStringKey(kKeyMdmIdToken, "token");
-  properties.SetStringKey(kKeyAccessToken, "access_token");
-  properties.SetStringKey(kKeySID, "sid");
-  properties.SetStringKey(kKeyUsername, "username");
-  properties.SetStringKey(kKeyDomain, "domain");
   ASSERT_EQ(S_OK, EnrollToGoogleMdmIfNeeded(properties));
 }
 
@@ -460,9 +454,13 @@
                                                  const char*>> {};
 
 TEST_P(GcpEnrollmentArgsTest, EnrollToGoogleMdmIfNeeded_MissingArgs) {
-  // Does not matter whether MDM is enforced or not.
+  // Enforce successful MDM enrollment. We just want to verify that correct
+  // verification of the dictionary is being performed in the function.
   registry_util::RegistryOverrideManager registry_override;
   InitializeRegistryOverrideForTesting(&registry_override);
+  ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmUrl, L"https://mdm.com"));
+  GoogleMdmEnrollmentStatusForTesting forced_enrollment_status(true);
+  GoogleMdmEnrolledStatusForTesting forced_enrolled_status(false);
 
   const char* email = std::get<0>(GetParam());
   const char* id_token = std::get<1>(GetParam());
diff --git a/chrome/credential_provider/gaiacp/mdm_utils.cc b/chrome/credential_provider/gaiacp/mdm_utils.cc
index 0832172..6250bf7f 100644
--- a/chrome/credential_provider/gaiacp/mdm_utils.cc
+++ b/chrome/credential_provider/gaiacp/mdm_utils.cc
@@ -119,90 +119,83 @@
 }
 
 HRESULT ExtractRegistrationData(const base::Value& registration_data,
+                                base::string16* out_email,
                                 base::string16* out_id_token,
                                 base::string16* out_access_token,
                                 base::string16* out_sid,
                                 base::string16* out_username,
                                 base::string16* out_domain) {
+  DCHECK(out_email);
+  DCHECK(out_id_token);
+  DCHECK(out_access_token);
+  DCHECK(out_sid);
+  DCHECK(out_username);
+  DCHECK(out_domain);
   if (!registration_data.is_dict()) {
     LOGFN(ERROR) << "Registration data is not a dictionary";
     return E_INVALIDARG;
   }
 
-  base::string16 id_token = GetDictString(registration_data, kKeyMdmIdToken);
-  base::string16 access_token =
-      GetDictString(registration_data, kKeyAccessToken);
-  base::string16 sid = GetDictString(registration_data, kKeySID);
-  base::string16 username = GetDictString(registration_data, kKeyUsername);
-  base::string16 domain = GetDictString(registration_data, kKeyDomain);
+  *out_email = GetDictString(registration_data, kKeyEmail);
+  *out_id_token = GetDictString(registration_data, kKeyMdmIdToken);
+  *out_access_token = GetDictString(registration_data, kKeyAccessToken);
+  *out_sid = GetDictString(registration_data, kKeySID);
+  *out_username = GetDictString(registration_data, kKeyUsername);
+  *out_domain = GetDictString(registration_data, kKeyDomain);
 
-  if (id_token.empty()) {
+  if (out_email->empty()) {
+    LOGFN(ERROR) << "Email is empty";
+    return E_INVALIDARG;
+  }
+
+  if (out_id_token->empty()) {
     LOGFN(ERROR) << "MDM id token is empty";
     return E_INVALIDARG;
   }
 
-  if (access_token.empty()) {
+  if (out_access_token->empty()) {
     LOGFN(ERROR) << "Access token is empty";
     return E_INVALIDARG;
   }
 
-  if (sid.empty()) {
+  if (out_sid->empty()) {
     LOGFN(ERROR) << "SID is empty";
     return E_INVALIDARG;
   }
 
-  if (username.empty()) {
+  if (out_username->empty()) {
     LOGFN(ERROR) << "username is empty";
     return E_INVALIDARG;
   }
 
-  if (domain.empty()) {
+  if (out_domain->empty()) {
     LOGFN(ERROR) << "domain is empty";
     return E_INVALIDARG;
   }
 
-  if (out_id_token)
-    *out_id_token = id_token;
-
-  if (out_access_token)
-    *out_access_token = access_token;
-
-  if (out_sid)
-    *out_sid = sid;
-
-  if (out_username)
-    *out_username = username;
-
-  if (out_domain)
-    *out_domain = domain;
-
   return S_OK;
 }
 
-HRESULT VerifyRegistrationData(
-    const base::Optional<base::Value>& registration_data) {
-  if (!registration_data) {
-    LOGFN(ERROR) << "No registration data present.";
+HRESULT RegisterWithGoogleDeviceManagement(const base::string16& mdm_url,
+                                           const base::Value& properties) {
+  // Make sure all the needed data is present in the dictionary.
+  base::string16 email;
+  base::string16 id_token;
+  base::string16 access_token;
+  base::string16 sid;
+  base::string16 username;
+  base::string16 domain;
+
+  HRESULT hr = ExtractRegistrationData(properties, &email, &id_token,
+                                       &access_token, &sid, &username, &domain);
+
+  if (FAILED(hr)) {
+    LOGFN(ERROR) << "ExtractRegistrationData hr=" << putHR(hr);
     return E_INVALIDARG;
   }
 
-  return ExtractRegistrationData(registration_data.value(), nullptr, nullptr,
-                                 nullptr, nullptr, nullptr);
-}
-
-HRESULT RegisterWithGoogleDeviceManagement(const base::string16& mdm_url,
-                                           const base::string16& email,
-                                           const std::string& data) {
-  base::Optional<base::Value> registration_data =
-      base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS);
-  HRESULT hr = VerifyRegistrationData(registration_data);
-
-  credential_provider::SecurelyClearDictionaryValue(&registration_data);
-
-  if (FAILED(hr)) {
-    LOGFN(ERROR) << "VerifyRegistrationData hr=" << putHR(hr);
-    return E_FAIL;
-  }
+  LOGFN(INFO) << "MDM_URL=" << mdm_url
+              << " token=" << base::string16(id_token.c_str(), 10);
 
   switch (g_enrollment_status) {
     case EnrollmentStatus::kForceSuccess:
@@ -213,11 +206,27 @@
       break;
   }
 
-  // TODO(crbug.com/935577): Check if machine is already enrolled because
-  // attempting to enroll when already enrolled causes a crash.
-  if (IsEnrolledWithGoogleMdm(mdm_url)) {
-    LOGFN(INFO) << "Already enrolled to Google MDM";
-    return S_OK;
+  // Add the serial number to the registration data dictionary.
+  base::string16 serial_number =
+      base::win::WmiComputerSystemInfo::Get().serial_number();
+
+  if (serial_number.empty()) {
+    LOGFN(ERROR) << "Failed to get serial number.";
+    return E_FAIL;
+  }
+
+  // Build the json data needed by the server.
+  base::Value registration_data(base::Value::Type::DICTIONARY);
+  registration_data.SetStringKey("id_token", id_token);
+  registration_data.SetStringKey("access_token", access_token);
+  registration_data.SetStringKey("sid", sid);
+  registration_data.SetStringKey("username", username);
+  registration_data.SetStringKey("domain", domain);
+  registration_data.SetStringKey("serial_number", serial_number);
+  std::string registration_data_str;
+  if (!base::JSONWriter::Write(registration_data, &registration_data_str)) {
+    LOGFN(ERROR) << "JSONWriter::Write(registration_data)";
+    return E_FAIL;
   }
 
   base::ScopedNativeLibrary library(
@@ -230,7 +239,7 @@
   }
 
   std::string data_encoded;
-  base::Base64Encode(data, &data_encoded);
+  base::Base64Encode(registration_data_str, &data_encoded);
 
   // This register call is blocking.  It won't return until the machine is
   // properly registered with the MDM server.
@@ -251,61 +260,21 @@
 }
 
 HRESULT EnrollToGoogleMdmIfNeeded(const base::Value& properties) {
-  USES_CONVERSION;
   LOGFN(INFO);
 
-  base::string16 email = GetDictString(properties, kKeyEmail);
-  base::string16 id_token;
-  base::string16 access_token;
-  base::string16 sid;
-  base::string16 username;
-  base::string16 domain;
-
-  if (email.empty()) {
-    LOGFN(ERROR) << "Email is empty";
-    return E_INVALIDARG;
-  }
-
-  HRESULT hr = ExtractRegistrationData(properties, &id_token, &access_token,
-                                       &sid, &username, &domain);
-
-  if (FAILED(hr)) {
-    LOGFN(ERROR) << "ExtractRegistrationData hr=" << putHR(hr);
-    return E_INVALIDARG;
-  }
-
   // Only enroll with MDM if configured.
   base::string16 mdm_url = GetMdmUrl();
   if (mdm_url.empty())
     return S_OK;
 
-  LOGFN(INFO) << "MDM_URL=" << mdm_url
-              << " token=" << base::string16(id_token.c_str(), 10);
-
-  // Build the json data needed by the server.
-  base::string16 serial_number =
-      base::win::WmiComputerSystemInfo::Get().serial_number();
-
-  if (serial_number.empty()) {
-    LOGFN(ERROR) << "Failed to get serial number.";
-    return -1;
+  // TODO(crbug.com/935577): Check if machine is already enrolled because
+  // attempting to enroll when already enrolled causes a crash.
+  if (IsEnrolledWithGoogleMdm(mdm_url)) {
+    LOGFN(INFO) << "Already enrolled to Google MDM";
+    return S_OK;
   }
 
-  base::Value registration_data(base::Value::Type::DICTIONARY);
-  registration_data.SetStringKey("serial_number", serial_number);
-  registration_data.SetStringKey("id_token", id_token);
-  registration_data.SetStringKey("access_token", access_token);
-  registration_data.SetStringKey("sid", sid);
-  registration_data.SetStringKey("username", username);
-  registration_data.SetStringKey("domain", domain);
-  std::string registration_data_str;
-  if (!base::JSONWriter::Write(registration_data, &registration_data_str)) {
-    LOGFN(ERROR) << "JSONWriter::Write(registration_data)";
-    return E_FAIL;
-  }
-
-  hr =
-      RegisterWithGoogleDeviceManagement(mdm_url, email, registration_data_str);
+  HRESULT hr = RegisterWithGoogleDeviceManagement(mdm_url, properties);
   if (FAILED(hr))
     LOGFN(ERROR) << "RegisterWithGoogleDeviceManagement hr=" << putHR(hr);
 
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc
index 95ca300..98956654 100644
--- a/chrome/credential_provider/gaiacp/reg_utils.cc
+++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -11,6 +11,7 @@
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/win/registry.h"
+#include "base/win/win_util.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 
 namespace credential_provider {
@@ -317,10 +318,8 @@
 }
 
 HRESULT SetLogonUiUserTileEntry(const base::string16& sid, CLSID cp_guid) {
-  wchar_t guid_in_wchar[64];
-  ::StringFromGUID2(cp_guid, guid_in_wchar, base::size(guid_in_wchar));
-  return SetMachineRegString(kLogonUiUserTileRegKey, sid.c_str(),
-                             guid_in_wchar);
+  return SetMachineRegString(kLogonUiUserTileRegKey, sid,
+                             base::win::String16FromGUID(cp_guid));
 }
 
 }  // namespace credential_provider
diff --git a/chrome/credential_provider/test/gcp_setup_unittests.cc b/chrome/credential_provider/test/gcp_setup_unittests.cc
index d80b7d3..16ef99a 100644
--- a/chrome/credential_provider/test/gcp_setup_unittests.cc
+++ b/chrome/credential_provider/test/gcp_setup_unittests.cc
@@ -27,6 +27,7 @@
 #include "base/test/scoped_path_override.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
+#include "base/win/win_util.h"
 #include "build/build_config.h"
 #include "chrome/credential_provider/common/gcp_strings.h"
 #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
@@ -128,13 +129,11 @@
 void GcpSetupTest::ExpectCredentialProviderToBeRegistered(
     bool registered,
     const base::string16& product_version) {
-  wchar_t guid_in_wchar[64];
-  StringFromGUID2(CLSID_GaiaCredentialProvider, guid_in_wchar,
-                  base::size(guid_in_wchar));
+  auto guid_string = base::win::String16FromGUID(CLSID_GaiaCredentialProvider);
 
   // Make sure COM object is registered.
   base::string16 register_key_path =
-      base::StringPrintf(L"CLSID\\%ls\\InprocServer32", guid_in_wchar);
+      base::StringPrintf(L"CLSID\\%ls\\InprocServer32", guid_string.c_str());
   base::win::RegKey clsid_key(HKEY_CLASSES_ROOT, register_key_path.c_str(),
                               KEY_READ);
   EXPECT_EQ(registered, clsid_key.Valid());
@@ -150,7 +149,7 @@
   base::string16 cp_key_path = base::StringPrintf(
       L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\"
       L"Authentication\\Credential Providers\\%ls",
-      guid_in_wchar);
+      guid_string.c_str());
 
   // Make sure credential provider is registered.
   base::win::RegKey cp_key(HKEY_LOCAL_MACHINE, cp_key_path.c_str(), KEY_READ);
diff --git a/chrome/install_static/install_util_unittest.cc b/chrome/install_static/install_util_unittest.cc
index a057946..e363cd1 100644
--- a/chrome/install_static/install_util_unittest.cc
+++ b/chrome/install_static/install_util_unittest.cc
@@ -9,7 +9,9 @@
 #include <tuple>
 
 #include "base/stl_util.h"
+#include "base/strings/string_util.h"
 #include "base/test/test_reg_util_win.h"
+#include "base/win/win_util.h"
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
 #include "chrome/install_static/test/scoped_install_details.h"
@@ -519,11 +521,8 @@
   EXPECT_EQ(GetToastActivatorClsid(),
             kToastActivatorClsids[std::get<0>(GetParam())]);
 
-  const int kCLSIDSize = 39;
-  wchar_t clsid_str[kCLSIDSize];
-  ASSERT_EQ(::StringFromGUID2(GetToastActivatorClsid(), clsid_str, kCLSIDSize),
-            kCLSIDSize);
-  EXPECT_THAT(clsid_str,
+  auto clsid_str = base::win::String16FromGUID(GetToastActivatorClsid());
+  EXPECT_THAT(base::as_wcstr(clsid_str.c_str()),
               StrCaseEq(kToastActivatorClsidsString[std::get<0>(GetParam())]));
 }
 
@@ -576,11 +575,8 @@
 
   EXPECT_EQ(GetElevatorClsid(), kElevatorClsids[std::get<0>(GetParam())]);
 
-  constexpr int kCLSIDSize = 39;
-  wchar_t clsid_str[kCLSIDSize] = {};
-  ASSERT_EQ(::StringFromGUID2(GetElevatorClsid(), clsid_str, kCLSIDSize),
-            kCLSIDSize);
-  EXPECT_THAT(clsid_str,
+  auto clsid_str = base::win::String16FromGUID(GetElevatorClsid());
+  EXPECT_THAT(base::as_wcstr(clsid_str.c_str()),
               StrCaseEq(kElevatorClsidsString[std::get<0>(GetParam())]));
 }
 
@@ -645,10 +641,9 @@
 
   EXPECT_EQ(GetElevatorIid(), kElevatorIids[std::get<0>(GetParam())]);
 
-  constexpr int kIIDSize = 39;
-  wchar_t iid_str[kIIDSize] = {};
-  ASSERT_EQ(::StringFromGUID2(GetElevatorIid(), iid_str, kIIDSize), kIIDSize);
-  EXPECT_THAT(iid_str, StrCaseEq(kElevatorIidsString[std::get<0>(GetParam())]));
+  auto iid_str = base::win::String16FromGUID(GetElevatorIid());
+  EXPECT_THAT(base::as_wcstr(iid_str.c_str()),
+              StrCaseEq(kElevatorIidsString[std::get<0>(GetParam())]));
 }
 
 TEST_P(InstallStaticUtilTest, UsageStatsAbsent) {
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 447a4829..3b3710b 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -38,6 +38,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/version.h"
 #include "base/win/registry.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "build/build_config.h"
 #include "chrome/install_static/install_details.h"
@@ -912,8 +913,7 @@
 }
 
 base::string16 GetElevationServiceGuid(base::StringPiece16 prefix) {
-  base::string16 result =
-      InstallUtil::String16FromGUID(install_static::GetElevatorClsid());
+  auto result = base::win::String16FromGUID(install_static::GetElevatorClsid());
   result.insert(0, prefix.data(), prefix.size());
   return result;
 }
@@ -927,8 +927,7 @@
 }
 
 base::string16 GetElevationServiceIid(base::StringPiece16 prefix) {
-  base::string16 result =
-      InstallUtil::String16FromGUID(install_static::GetElevatorIid());
+  auto result = base::win::String16FromGUID(install_static::GetElevatorIid());
   result.insert(0, prefix.data(), prefix.size());
   return result;
 }
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 8d65d1fe..33295f1 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -27,6 +27,7 @@
 #include "base/win/registry.h"
 #include "base/win/shlwapi.h"
 #include "base/win/shortcut.h"
+#include "base/win/win_util.h"
 #include "base/win/windows_version.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
@@ -348,23 +349,9 @@
 }
 
 // static
-base::string16 InstallUtil::String16FromGUID(const GUID& guid) {
-  // A GUID has a string format of "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}",
-  // which contains 38 characters. The length is 39 inclusive of the string
-  // terminator.
-  constexpr int kGuidLength = 39;
-  base::string16 guid_string;
-
-  const int length_with_terminator = ::StringFromGUID2(
-      guid, base::WriteInto(&guid_string, kGuidLength), kGuidLength);
-  DCHECK_EQ(length_with_terminator, kGuidLength);
-  return guid_string;
-}
-
-// static
 base::string16 InstallUtil::GetToastActivatorRegistryPath() {
-  return L"Software\\Classes\\CLSID\\" +
-         String16FromGUID(install_static::GetToastActivatorClsid());
+  return STRING16_LITERAL("Software\\Classes\\CLSID\\") +
+         base::win::String16FromGUID(install_static::GetToastActivatorClsid());
 }
 
 // static
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
index 5aa98f7..79c14995 100644
--- a/chrome/installer/util/install_util.h
+++ b/chrome/installer/util/install_util.h
@@ -81,9 +81,6 @@
   // CLSID registered.
   static bool IsStartMenuShortcutWithActivatorGuidInstalled();
 
-  // Returns a string representation of |guid|.
-  static base::string16 String16FromGUID(const GUID& guid);
-
   // Returns the toast activator registry path.
   static base::string16 GetToastActivatorRegistryPath();
 
diff --git a/chrome/renderer/extensions/automation_ax_tree_wrapper.h b/chrome/renderer/extensions/automation_ax_tree_wrapper.h
index f993cc39..0d4f12d 100644
--- a/chrome/renderer/extensions/automation_ax_tree_wrapper.h
+++ b/chrome/renderer/extensions/automation_ax_tree_wrapper.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
 #define CHROME_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
 
+#include "extensions/common/api/automation.h"
 #include "ui/accessibility/ax_event_generator.h"
 #include "ui/accessibility/ax_tree.h"
 
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.h b/chrome/renderer/extensions/automation_internal_custom_bindings.h
index bb042727..4ad225b8 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.h
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.h
@@ -11,8 +11,8 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "chrome/common/extensions/api/automation.h"
 #include "chrome/renderer/extensions/automation_ax_tree_wrapper.h"
+#include "extensions/common/api/automation.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 #include "ipc/ipc_message.h"
 #include "ui/accessibility/ax_tree.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 39dc8a22..3becaca 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1915,6 +1915,8 @@
         "../browser/chromeos/login/test/network_portal_detector_mixin.h",
         "../browser/chromeos/login/test/oobe_base_test.cc",
         "../browser/chromeos/login/test/oobe_base_test.h",
+        "../browser/chromeos/login/test/session_flags_manager.cc",
+        "../browser/chromeos/login/test/session_flags_manager.h",
         "../browser/chromeos/login/ui/captive_portal_window_browsertest.cc",
         "../browser/chromeos/login/ui/login_feedback_browsertest.cc",
         "../browser/chromeos/login/ui/login_web_dialog_browsertest.cc",
@@ -5152,7 +5154,6 @@
     # Runtime dependencies
     data_deps = [
       "//ppapi:ppapi_tests",
-      "//testing/buildbot/filters:interactive_ui_tests_filters",
       "//third_party/mesa_headers",
     ]
 
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 23a0c3ce8..69aae880 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -201,6 +201,10 @@
   return nullptr;
 }
 
+StartupData* TestingBrowserProcess::startup_data() {
+  return nullptr;
+}
+
 policy::ChromeBrowserPolicyConnector*
 TestingBrowserProcess::browser_policy_connector() {
   if (!browser_policy_connector_) {
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 10d9a2e..a01b7e7 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -118,6 +118,7 @@
   void SetApplicationLocale(const std::string& actual_locale) override;
   DownloadStatusUpdater* download_status_updater() override;
   DownloadRequestLimiter* download_request_limiter() override;
+  StartupData* startup_data() override;
 
 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
   void StartAutoupdateTimer() override {}
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index ad60e62..ef2c0153 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -39,7 +39,7 @@
 #include "chrome/browser/history/web_history_service_factory.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/schema_registry_service.h"
-#include "chrome/browser/policy/schema_registry_service_profile_builder.h"
+#include "chrome/browser/policy/schema_registry_service_builder.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/browser/prefs/pref_service_syncable_util.h"
 #include "chrome/browser/prerender/prerender_manager.h"
@@ -933,9 +933,11 @@
   return schema_registry_service_.get();
 }
 
+#if !defined(OS_CHROMEOS)
 policy::UserCloudPolicyManager* TestingProfile::GetUserCloudPolicyManager() {
   return user_cloud_policy_manager_.get();
 }
+#endif
 
 policy::ProfilePolicyConnector* TestingProfile::GetProfilePolicyConnector() {
   return profile_policy_connector_.get();
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index a10711d..2bd579b 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -341,7 +341,9 @@
   base::Time GetStartTime() const override;
   ProfileKey* GetProfileKey() const override;
   policy::SchemaRegistryService* GetPolicySchemaRegistryService() override;
+#if !defined(OS_CHROMEOS)
   policy::UserCloudPolicyManager* GetUserCloudPolicyManager() override;
+#endif
   policy::ProfilePolicyConnector* GetProfilePolicyConnector() override;
   const policy::ProfilePolicyConnector* GetProfilePolicyConnector()
       const override;
diff --git a/chrome/test/logging/win/log_file_printer.cc b/chrome/test/logging/win/log_file_printer.cc
index 24b8e42..e39f509 100644
--- a/chrome/test/logging/win/log_file_printer.cc
+++ b/chrome/test/logging/win/log_file_printer.cc
@@ -20,6 +20,7 @@
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
+#include "base/win/win_util.h"
 #include "chrome/test/logging/win/log_file_reader.h"
 
 namespace {
@@ -143,9 +144,8 @@
 // Prints a useful message for events that can't be otherwise printed.
 void EventPrinter::PrintBadEvent(const EVENT_TRACE* event,
                                  const base::StringPiece& error) {
-  wchar_t guid[64];
-  StringFromGUID2(event->Header.Guid, &guid[0], base::size(guid));
-  *out_ << error << " (class=" << guid
+  *out_ << error
+        << " (class=" << base::win::String16FromGUID(event->Header.Guid)
         << ", type=" << static_cast<int>(event->Header.Class.Type) << ")";
 }
 
diff --git a/chrome/test/v8/wasm_trap_handler_browsertest.cc b/chrome/test/v8/wasm_trap_handler_browsertest.cc
index 1d66d3d..25b8751 100644
--- a/chrome/test/v8/wasm_trap_handler_browsertest.cc
+++ b/chrome/test/v8/wasm_trap_handler_browsertest.cc
@@ -120,16 +120,18 @@
 IN_PROC_BROWSER_TEST_F(WasmTrapHandlerBrowserTest,
                        TrapHandlerCorrectlyConfigured) {
   const bool is_trap_handler_enabled = IsTrapHandlerEnabled();
-// In msan builds, v8 is configured to generate arm code and run it in the
-// simulator. This results in an incorrect value here, because Chrome thinks
-// the trap handlers hould be supported but it is not.
-#if defined(MEMORY_SANITIZER)
-  ignore_result(kIsTrapHandlerSupported);
-  ASSERT_FALSE(is_trap_handler_enabled);
-#else
+#if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER) || defined(LEAK_SANITIZER) ||    \
+    defined(UNDEFINED_SANITIZER)
+  // Sanitizers may prevent signal handler installation and thereby trap handler
+  // setup. As there is no easy way to test if signal handler installation is
+  // possible, we disable this test for sanitizers.
+  ignore_result(is_trap_handler_enabled);
+  return;
+#endif
+
   ASSERT_EQ(is_trap_handler_enabled,
             kIsTrapHandlerSupported && base::FeatureList::IsEnabled(
                                            features::kWebAssemblyTrapHandler));
-#endif
 }
 }  // namespace
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn
index 0fd62a0b..0523059 100644
--- a/chromecast/browser/BUILD.gn
+++ b/chromecast/browser/BUILD.gn
@@ -288,11 +288,8 @@
       "extension_request_protocol_handler.h",
       "extensions/api/accessibility_private/accessibility_extension_api.cc",
       "extensions/api/accessibility_private/accessibility_extension_api.h",
-      "extensions/api/automation_internal/automation_event_router.cc",
-      "extensions/api/automation_internal/automation_event_router.h",
-      "extensions/api/automation_internal/automation_event_router_interface.h",
-      "extensions/api/automation_internal/automation_internal_api.cc",
-      "extensions/api/automation_internal/automation_internal_api.h",
+      "extensions/api/automation_internal/chromecast_automation_internal_api_delegate.cc",
+      "extensions/api/automation_internal/chromecast_automation_internal_api_delegate.h",
       "extensions/api/bookmarks/bookmarks_api.cc",
       "extensions/api/bookmarks/bookmarks_api.h",
       "extensions/api/braille_display_private/braille_display_private_api.cc",
diff --git a/chromecast/browser/extensions/api/automation_internal/automation_event_router.cc b/chromecast/browser/extensions/api/automation_internal/automation_event_router.cc
deleted file mode 100644
index 98cf854..0000000
--- a/chromecast/browser/extensions/api/automation_internal/automation_event_router.cc
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromecast/browser/extensions/api/automation_internal/automation_event_router.h"
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include "base/stl_util.h"
-#include "base/values.h"
-#include "build/build_config.h"
-#include "chromecast/common/extensions_api/automation_internal.h"
-#include "chromecast/common/extensions_api/cast_extension_messages.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_source.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/render_process_host.h"
-#include "extensions/browser/event_router.h"
-#include "extensions/common/extension.h"
-#include "ui/accessibility/ax_action_data.h"
-#include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/accessibility/ax_node_data.h"
-
-#if defined(USE_AURA)
-#include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h"
-#endif
-
-namespace extensions {
-namespace cast {
-
-// static
-AutomationEventRouter* AutomationEventRouter::GetInstance() {
-  return base::Singleton<
-      AutomationEventRouter,
-      base::LeakySingletonTraits<AutomationEventRouter>>::get();
-}
-
-AutomationEventRouter::AutomationEventRouter() {
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
-                 content::NotificationService::AllBrowserContextsAndSources());
-#if defined(USE_AURA)
-  // Not reset because |this| is leaked.
-  AutomationManagerAura::GetInstance()->set_event_bundle_sink(this);
-#endif
-}
-
-AutomationEventRouter::~AutomationEventRouter() {}
-
-void AutomationEventRouter::RegisterListenerForOneTree(
-    const ExtensionId& extension_id,
-    int listener_process_id,
-    ui::AXTreeID source_ax_tree_id) {
-  Register(extension_id, listener_process_id, source_ax_tree_id, false);
-}
-
-void AutomationEventRouter::RegisterListenerWithDesktopPermission(
-    const ExtensionId& extension_id,
-    int listener_process_id) {
-  Register(extension_id, listener_process_id, ui::AXTreeIDUnknown(), true);
-}
-
-void AutomationEventRouter::DispatchActionResult(
-    const ui::AXActionData& data,
-    bool result,
-    content::BrowserContext* active_profile) {
-  CHECK(!data.source_extension_id.empty());
-
-  if (listeners_.empty())
-    return;
-
-  std::unique_ptr<base::ListValue> args(
-      api::automation_internal::OnActionResult::Create(
-          data.target_tree_id.ToString(), data.request_id, result));
-  auto event = std::make_unique<Event>(
-      events::AUTOMATION_INTERNAL_ON_ACTION_RESULT,
-      api::automation_internal::OnActionResult::kEventName, std::move(args),
-      active_profile);
-  EventRouter::Get(active_profile)
-      ->DispatchEventToExtension(data.source_extension_id, std::move(event));
-}
-
-void AutomationEventRouter::DispatchAccessibilityEvents(
-    const ExtensionMsg_AccessibilityEventBundleParams& event_bundle) {
-  for (const auto& listener : listeners_) {
-    // Skip listeners that don't want to listen to this tree.
-    if (!listener.desktop && listener.tree_ids.find(event_bundle.tree_id) ==
-                                 listener.tree_ids.end()) {
-      continue;
-    }
-
-    content::RenderProcessHost* rph =
-        content::RenderProcessHost::FromID(listener.process_id);
-    rph->Send(new ExtensionMsg_AccessibilityEventBundle(event_bundle, true));
-  }
-}
-
-void AutomationEventRouter::DispatchAccessibilityLocationChange(
-    const ExtensionMsg_AccessibilityLocationChangeParams& params) {
-  for (const auto& listener : listeners_) {
-    // Skip listeners that don't want to listen to this tree.
-    if (!listener.desktop &&
-        listener.tree_ids.find(params.tree_id) == listener.tree_ids.end()) {
-      continue;
-    }
-
-    content::RenderProcessHost* rph =
-        content::RenderProcessHost::FromID(listener.process_id);
-    rph->Send(new ExtensionMsg_AccessibilityLocationChange(params));
-  }
-}
-
-void AutomationEventRouter::DispatchTreeDestroyedEvent(
-    ui::AXTreeID tree_id,
-    content::BrowserContext* browser_context) {
-  if (listeners_.empty())
-    return;
-
-  std::unique_ptr<base::ListValue> args(
-      api::automation_internal::OnAccessibilityTreeDestroyed::Create(
-          tree_id.ToString()));
-  auto event = std::make_unique<Event>(
-      events::AUTOMATION_INTERNAL_ON_ACCESSIBILITY_TREE_DESTROYED,
-      api::automation_internal::OnAccessibilityTreeDestroyed::kEventName,
-      std::move(args), browser_context);
-  EventRouter::Get(browser_context)->BroadcastEvent(std::move(event));
-}
-
-AutomationEventRouter::AutomationListener::AutomationListener() {}
-
-AutomationEventRouter::AutomationListener::AutomationListener(
-    const AutomationListener& other) = default;
-
-AutomationEventRouter::AutomationListener::~AutomationListener() {}
-
-void AutomationEventRouter::Register(const ExtensionId& extension_id,
-                                     int listener_process_id,
-                                     ui::AXTreeID ax_tree_id,
-                                     bool desktop) {
-  auto iter =
-      std::find_if(listeners_.begin(), listeners_.end(),
-                   [listener_process_id](const AutomationListener& item) {
-                     return item.process_id == listener_process_id;
-                   });
-
-  // Add a new entry if we don't have one with that process.
-  if (iter == listeners_.end()) {
-    AutomationListener listener;
-    listener.extension_id = extension_id;
-    listener.process_id = listener_process_id;
-    listener.desktop = desktop;
-    if (!desktop)
-      listener.tree_ids.insert(ax_tree_id);
-    listeners_.push_back(listener);
-    return;
-  }
-
-  // We have an entry with that process so update the set of tree ids it wants
-  // to listen to, and update its desktop permission.
-  if (desktop)
-    iter->desktop = true;
-  else
-    iter->tree_ids.insert(ax_tree_id);
-}
-
-void AutomationEventRouter::DispatchAccessibilityEvents(
-    const ui::AXTreeID& tree_id,
-    std::vector<ui::AXTreeUpdate> updates,
-    const gfx::Point& mouse_location,
-    std::vector<ui::AXEvent> events) {
-  ExtensionMsg_AccessibilityEventBundleParams event_bundle;
-  event_bundle.tree_id = tree_id;
-  event_bundle.updates = std::move(updates);
-  event_bundle.mouse_location = mouse_location;
-  event_bundle.events = std::move(events);
-
-  DispatchAccessibilityEvents(event_bundle);
-}
-
-void AutomationEventRouter::Observe(
-    int type,
-    const content::NotificationSource& source,
-    const content::NotificationDetails& details) {
-  if (type != content::NOTIFICATION_RENDERER_PROCESS_TERMINATED &&
-      type != content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
-    NOTREACHED();
-    return;
-  }
-
-  content::RenderProcessHost* rph =
-      content::Source<content::RenderProcessHost>(source).ptr();
-  int process_id = rph->GetID();
-  listeners_.erase(std::remove_if(listeners_.begin(), listeners_.end(),
-                                  [process_id](const AutomationListener& item) {
-                                    return item.process_id == process_id;
-                                  }),
-                   listeners_.end());
-}
-
-}  // namespace cast
-}  // namespace extensions
diff --git a/chromecast/browser/extensions/api/automation_internal/automation_event_router.h b/chromecast/browser/extensions/api/automation_internal/automation_event_router.h
deleted file mode 100644
index 37cc0c4..0000000
--- a/chromecast/browser/extensions/api/automation_internal/automation_event_router.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
-#define CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
-
-#include <set>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-#include "chromecast/browser/extensions/api/automation_internal/automation_event_router_interface.h"
-#include "chromecast/common/extensions_api/automation_internal.h"
-#include "content/public/browser/ax_event_notification_details.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "extensions/common/extension_id.h"
-#include "extensions/common/extension_messages.h"
-#include "ui/accessibility/ax_event_bundle_sink.h"
-#include "ui/accessibility/ax_tree_id.h"
-
-namespace content {
-class BrowserContext;
-}  // namespace content
-
-namespace ui {
-struct AXActionData;
-}  // namespace ui
-
-struct ExtensionMsg_AccessibilityEventBundleParams;
-struct ExtensionMsg_AccessibilityLocationChangeParams;
-
-namespace extensions {
-namespace cast {
-struct AutomationListener;
-
-class AutomationEventRouter : public ui::AXEventBundleSink,
-                              public AutomationEventRouterInterface,
-                              public content::NotificationObserver {
- public:
-  static AutomationEventRouter* GetInstance();
-
-  // Indicates that the listener at |listener_process_id| wants to receive
-  // automation events from the accessibility tree indicated by
-  // |source_ax_tree_id|. Automation events are forwarded from now on until the
-  // listener process dies.
-  void RegisterListenerForOneTree(const ExtensionId& extension_id,
-                                  int listener_process_id,
-                                  ui::AXTreeID source_ax_tree_id);
-
-  // Indicates that the listener at |listener_process_id| wants to receive
-  // automation events from all accessibility trees because it has Desktop
-  // permission.
-  void RegisterListenerWithDesktopPermission(const ExtensionId& extension_id,
-                                             int listener_process_id);
-
-  void DispatchAccessibilityEvents(
-      const ExtensionMsg_AccessibilityEventBundleParams& events) override;
-
-  void DispatchAccessibilityLocationChange(
-      const ExtensionMsg_AccessibilityLocationChangeParams& params) override;
-
-  // Notify all automation extensions that an accessibility tree was
-  // destroyed. If |browser_context| is null,
-  void DispatchTreeDestroyedEvent(
-      ui::AXTreeID tree_id,
-      content::BrowserContext* browser_context) override;
-
-  // Notify the source extension of the action of an action result.
-  void DispatchActionResult(const ui::AXActionData& data,
-                            bool result,
-                            content::BrowserContext* active_profile) override;
-
- private:
-  struct AutomationListener {
-    AutomationListener();
-    AutomationListener(const AutomationListener& other);
-    ~AutomationListener();
-
-    ExtensionId extension_id;
-    int process_id;
-    bool desktop;
-    std::set<ui::AXTreeID> tree_ids;
-  };
-
-  AutomationEventRouter();
-  ~AutomationEventRouter() override;
-
-  void Register(const ExtensionId& extension_id,
-                int listener_process_id,
-                ui::AXTreeID source_ax_tree_id,
-                bool desktop);
-
-  // ui::AXEventBundleSink:
-  void DispatchAccessibilityEvents(const ui::AXTreeID& tree_id,
-                                   std::vector<ui::AXTreeUpdate> updates,
-                                   const gfx::Point& mouse_location,
-                                   std::vector<ui::AXEvent> events) override;
-
-  // content::NotificationObserver interface.
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override;
-
-  content::NotificationRegistrar registrar_;
-  std::vector<AutomationListener> listeners_;
-
-  friend struct base::DefaultSingletonTraits<AutomationEventRouter>;
-
-  DISALLOW_COPY_AND_ASSIGN(AutomationEventRouter);
-};
-
-}  // namespace cast
-}  // namespace extensions
-
-#endif  // CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
diff --git a/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc b/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc
deleted file mode 100644
index 9265f092..0000000
--- a/chromecast/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ /dev/null
@@ -1,561 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// TODO(crbug/837773) This file was copied from
-// chrome/browser/extensions/api/automation_internal.
-// Copied code will be de-duped later.
-
-#include "chromecast/browser/extensions/api/automation_internal/automation_internal_api.h"
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chromecast/browser/extensions/api/automation_internal/automation_event_router.h"
-#include "chromecast/common/extensions_api/automation.h"
-#include "chromecast/common/extensions_api/automation_internal.h"
-#include "chromecast/common/extensions_api/cast_extension_messages.h"
-#include "content/public/browser/ax_event_notification_details.h"
-#include "content/public/browser/browser_accessibility_state.h"
-#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_plugin_guest_manager.h"
-#include "content/public/browser/media_player_id.h"
-#include "content/public/browser/media_session.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/render_widget_host.h"
-#include "content/public/browser/render_widget_host_view.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "extensions/common/extension_messages.h"
-#include "extensions/common/manifest_handlers/automation.h"
-#include "extensions/common/permissions/permissions_data.h"
-#include "ui/accessibility/ax_action_data.h"
-#include "ui/accessibility/ax_action_handler.h"
-#include "ui/accessibility/ax_enum_util.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
-
-#if defined(USE_AURA)
-#include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h"
-#include "ui/aura/env.h"
-#endif
-
-namespace extensions {
-namespace cast {
-class AutomationWebContentsObserver;
-}  // namespace cast
-}  // namespace extensions
-
-namespace extensions {
-namespace cast {
-
-namespace {
-
-const char kCannotRequestAutomationOnPage[] =
-    "Cannot request automation tree on url \"*\". "
-    "Extension manifest must request permission to access this host.";
-const char kRendererDestroyed[] = "The tab was closed.";
-const char kNoDocument[] = "No document.";
-const char kNodeDestroyed[] =
-    "domQuerySelector sent on node which is no longer in the tree.";
-
-// Handles sending and receiving IPCs for a single querySelector request. On
-// creation, sends the request IPC, and is destroyed either when the response is
-// received or the renderer is destroyed.
-class QuerySelectorHandler : public content::WebContentsObserver {
- public:
-  QuerySelectorHandler(
-      content::WebContents* web_contents,
-      int request_id,
-      int acc_obj_id,
-      const base::string16& query,
-      const AutomationInternalQuerySelectorFunction::Callback& callback)
-      : content::WebContentsObserver(web_contents),
-        request_id_(request_id),
-        callback_(callback) {
-    content::RenderFrameHost* rfh = web_contents->GetMainFrame();
-
-    rfh->Send(new ExtensionMsg_AutomationQuerySelector(
-        rfh->GetRoutingID(), request_id, acc_obj_id, query));
-  }
-
-  ~QuerySelectorHandler() override {}
-
-  bool OnMessageReceived(const IPC::Message& message,
-                         content::RenderFrameHost* render_frame_host) override {
-    if (message.type() != ExtensionHostMsg_AutomationQuerySelector_Result::ID)
-      return false;
-
-    // There may be several requests in flight; check this response matches.
-    int message_request_id = 0;
-    base::PickleIterator iter(message);
-    if (!iter.ReadInt(&message_request_id))
-      return false;
-
-    if (message_request_id != request_id_)
-      return false;
-
-    IPC_BEGIN_MESSAGE_MAP(QuerySelectorHandler, message)
-      IPC_MESSAGE_HANDLER(ExtensionHostMsg_AutomationQuerySelector_Result,
-                          OnQueryResponse)
-    IPC_END_MESSAGE_MAP()
-    return true;
-  }
-
-  void WebContentsDestroyed() override {
-    callback_.Run(kRendererDestroyed, 0);
-    delete this;
-  }
-
- private:
-  void OnQueryResponse(int request_id,
-                       ExtensionHostMsg_AutomationQuerySelector_Error error,
-                       int result_acc_obj_id) {
-    std::string error_string;
-    switch (error.value) {
-      case ExtensionHostMsg_AutomationQuerySelector_Error::kNone:
-        break;
-      case ExtensionHostMsg_AutomationQuerySelector_Error::kNoDocument:
-        error_string = kNoDocument;
-        break;
-      case ExtensionHostMsg_AutomationQuerySelector_Error::kNodeDestroyed:
-        error_string = kNodeDestroyed;
-        break;
-    }
-    callback_.Run(error_string, result_acc_obj_id);
-    delete this;
-  }
-
-  int request_id_;
-  const AutomationInternalQuerySelectorFunction::Callback callback_;
-};
-
-bool CanRequestAutomation(const Extension* extension,
-                          const AutomationInfo* automation_info,
-                          content::WebContents* contents) {
-  if (automation_info->desktop)
-    return true;
-
-  const GURL& url = contents->GetURL();
-  // TODO(aboxhall): check for webstore URL
-  if (automation_info->matches.MatchesURL(url))
-    return true;
-
-  return false;
-}
-
-}  // namespace
-
-// Helper class that receives accessibility data from |WebContents|.
-class AutomationWebContentsObserver
-    : public content::WebContentsObserver,
-      public content::WebContentsUserData<AutomationWebContentsObserver> {
- public:
-  ~AutomationWebContentsObserver() override {}
-
-  // content::WebContentsObserver overrides.
-  void AccessibilityEventReceived(const content::AXEventNotificationDetails&
-                                      content_event_bundle) override {
-    ExtensionMsg_AccessibilityEventBundleParams extension_event_bundle;
-    extension_event_bundle.updates = content_event_bundle.updates;
-    extension_event_bundle.events = content_event_bundle.events;
-    extension_event_bundle.tree_id = content_event_bundle.ax_tree_id;
-#if defined(USE_AURA)
-    extension_event_bundle.mouse_location =
-        aura::Env::GetInstance()->last_mouse_location();
-#endif
-    AutomationEventRouter* router = AutomationEventRouter::GetInstance();
-    router->DispatchAccessibilityEvents(extension_event_bundle);
-  }
-
-  void AccessibilityLocationChangesReceived(
-      const std::vector<content::AXLocationChangeNotificationDetails>& details)
-      override {
-    for (const auto& src : details) {
-      ExtensionMsg_AccessibilityLocationChangeParams dst;
-      dst.id = src.id;
-      dst.tree_id = src.ax_tree_id;
-      dst.new_location = src.new_location;
-      AutomationEventRouter* router = AutomationEventRouter::GetInstance();
-      router->DispatchAccessibilityLocationChange(dst);
-    }
-  }
-
-  void RenderFrameDeleted(
-      content::RenderFrameHost* render_frame_host) override {
-    ui::AXTreeID tree_id = render_frame_host->GetAXTreeID();
-    AutomationEventRouter::GetInstance()->DispatchTreeDestroyedEvent(
-        tree_id, browser_context_);
-  }
-
-  void MediaStartedPlaying(const MediaPlayerInfo& video_type,
-                           const content::MediaPlayerId& id) override {
-    content::AXEventNotificationDetails content_event_bundle;
-    content_event_bundle.ax_tree_id = id.render_frame_host->GetAXTreeID();
-    content_event_bundle.events.resize(1);
-    content_event_bundle.events[0].event_type =
-        ax::mojom::Event::kMediaStartedPlaying;
-    AccessibilityEventReceived(content_event_bundle);
-  }
-
-  void MediaStoppedPlaying(
-      const MediaPlayerInfo& video_type,
-      const content::MediaPlayerId& id,
-      WebContentsObserver::MediaStoppedReason reason) override {
-    content::AXEventNotificationDetails content_event_bundle;
-    content_event_bundle.ax_tree_id = id.render_frame_host->GetAXTreeID();
-    content_event_bundle.events.resize(1);
-    content_event_bundle.events[0].event_type =
-        ax::mojom::Event::kMediaStoppedPlaying;
-    AccessibilityEventReceived(content_event_bundle);
-  }
-
- private:
-  friend class content::WebContentsUserData<AutomationWebContentsObserver>;
-
-  explicit AutomationWebContentsObserver(content::WebContents* web_contents)
-      : content::WebContentsObserver(web_contents),
-        browser_context_(web_contents->GetBrowserContext()) {
-    if (web_contents->IsCurrentlyAudible()) {
-      content::RenderFrameHost* rfh = web_contents->GetMainFrame();
-      if (!rfh)
-        return;
-
-      content::AXEventNotificationDetails content_event_bundle;
-      content_event_bundle.ax_tree_id = rfh->GetAXTreeID();
-      content_event_bundle.events.resize(1);
-      content_event_bundle.events[0].event_type =
-          ax::mojom::Event::kMediaStartedPlaying;
-      AccessibilityEventReceived(content_event_bundle);
-    }
-  }
-
-  content::BrowserContext* browser_context_;
-
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-
-  DISALLOW_COPY_AND_ASSIGN(AutomationWebContentsObserver);
-};
-
-WEB_CONTENTS_USER_DATA_KEY_IMPL(AutomationWebContentsObserver)
-
-ExtensionFunction::ResponseAction AutomationInternalEnableTabFunction::Run() {
-  return RespondNow(Error("enableTab is unsupported by this platform"));
-}
-
-ExtensionFunction::ResponseAction AutomationInternalEnableFrameFunction::Run() {
-  // TODO(dtseng): Limited to desktop tree for now pending out of proc iframes.
-  using api::automation_internal::EnableFrame::Params;
-
-  std::unique_ptr<Params> params(Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  content::RenderFrameHost* rfh = content::RenderFrameHost::FromAXTreeID(
-      ui::AXTreeID::FromString(params->tree_id));
-  if (!rfh)
-    return RespondNow(Error("unable to load tab"));
-
-  content::WebContents* contents =
-      content::WebContents::FromRenderFrameHost(rfh);
-  AutomationWebContentsObserver::CreateForWebContents(contents);
-
-  // Only call this if this is the root of a frame tree, to avoid resetting
-  // the accessibility state multiple times.
-  if (!rfh->GetParent())
-    contents->EnableWebContentsOnlyAccessibilityMode();
-
-  return RespondNow(NoArguments());
-}
-
-ExtensionFunction::ResponseAction
-AutomationInternalPerformActionFunction::ConvertToAXActionData(
-    api::automation_internal::PerformAction::Params* params,
-    ui::AXActionData* action) {
-  action->target_tree_id = ui::AXTreeID::FromString(params->args.tree_id);
-  action->source_extension_id = extension_id();
-  action->target_node_id = params->args.automation_node_id;
-  int* request_id = params->args.request_id.get();
-  action->request_id = request_id ? *request_id : -1;
-  api::automation::ActionType action_type =
-      api::automation::ParseActionType(params->args.action_type);
-  switch (action_type) {
-    case api::automation::ACTION_TYPE_BLUR:
-      action->action = ax::mojom::Action::kBlur;
-      break;
-    case api::automation::ACTION_TYPE_CLEARACCESSIBILITYFOCUS:
-      action->action = ax::mojom::Action::kClearAccessibilityFocus;
-      break;
-    case api::automation::ACTION_TYPE_DECREMENT:
-      action->action = ax::mojom::Action::kDecrement;
-      break;
-    case api::automation::ACTION_TYPE_DODEFAULT:
-      action->action = ax::mojom::Action::kDoDefault;
-      break;
-    case api::automation::ACTION_TYPE_INCREMENT:
-      action->action = ax::mojom::Action::kIncrement;
-      break;
-    case api::automation::ACTION_TYPE_FOCUS:
-      action->action = ax::mojom::Action::kFocus;
-      break;
-    case api::automation::ACTION_TYPE_GETIMAGEDATA: {
-      api::automation_internal::GetImageDataParams get_image_data_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::GetImageDataParams::Populate(
-              params->opt_args.additional_properties, &get_image_data_params));
-      action->action = ax::mojom::Action::kGetImageData;
-      action->target_rect = gfx::Rect(0, 0, get_image_data_params.max_width,
-                                      get_image_data_params.max_height);
-      break;
-    }
-    case api::automation::ACTION_TYPE_HITTEST: {
-      api::automation_internal::HitTestParams hit_test_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::HitTestParams::Populate(
-              params->opt_args.additional_properties, &hit_test_params));
-      action->action = ax::mojom::Action::kHitTest;
-      action->target_point = gfx::Point(hit_test_params.x, hit_test_params.y);
-      action->hit_test_event_to_fire =
-          ui::ParseEvent(hit_test_params.event_to_fire.c_str());
-      if (action->hit_test_event_to_fire == ax::mojom::Event::kNone)
-        return RespondNow(NoArguments());
-      break;
-    }
-    case api::automation::ACTION_TYPE_LOADINLINETEXTBOXES:
-      action->action = ax::mojom::Action::kLoadInlineTextBoxes;
-      break;
-    case api::automation::ACTION_TYPE_SETACCESSIBILITYFOCUS:
-      action->action = ax::mojom::Action::kSetAccessibilityFocus;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLTOMAKEVISIBLE:
-      action->action = ax::mojom::Action::kScrollToMakeVisible;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLBACKWARD:
-      action->action = ax::mojom::Action::kScrollBackward;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLFORWARD:
-      action->action = ax::mojom::Action::kScrollForward;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLUP:
-      action->action = ax::mojom::Action::kScrollUp;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLDOWN:
-      action->action = ax::mojom::Action::kScrollDown;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLLEFT:
-      action->action = ax::mojom::Action::kScrollLeft;
-      break;
-    case api::automation::ACTION_TYPE_SCROLLRIGHT:
-      action->action = ax::mojom::Action::kScrollRight;
-      break;
-    case api::automation::ACTION_TYPE_SETSELECTION: {
-      api::automation_internal::SetSelectionParams selection_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::SetSelectionParams::Populate(
-              params->opt_args.additional_properties, &selection_params));
-      action->anchor_node_id = params->args.automation_node_id;
-      action->anchor_offset = selection_params.anchor_offset;
-      action->focus_node_id = selection_params.focus_node_id;
-      action->focus_offset = selection_params.focus_offset;
-      action->action = ax::mojom::Action::kSetSelection;
-      break;
-    }
-    case api::automation::ACTION_TYPE_SHOWCONTEXTMENU: {
-      action->action = ax::mojom::Action::kShowContextMenu;
-      break;
-    }
-    case api::automation::
-        ACTION_TYPE_SETSEQUENTIALFOCUSNAVIGATIONSTARTINGPOINT: {
-      action->action =
-          ax::mojom::Action::kSetSequentialFocusNavigationStartingPoint;
-      break;
-    }
-    case api::automation::ACTION_TYPE_CUSTOMACTION: {
-      api::automation_internal::PerformCustomActionParams
-          perform_custom_action_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::PerformCustomActionParams::Populate(
-              params->opt_args.additional_properties,
-              &perform_custom_action_params));
-      action->action = ax::mojom::Action::kCustomAction;
-      action->custom_action_id = perform_custom_action_params.custom_action_id;
-      break;
-    }
-    case api::automation::ACTION_TYPE_REPLACESELECTEDTEXT: {
-      api::automation_internal::ReplaceSelectedTextParams
-          replace_selected_text_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::ReplaceSelectedTextParams::Populate(
-              params->opt_args.additional_properties,
-              &replace_selected_text_params));
-      action->action = ax::mojom::Action::kReplaceSelectedText;
-      action->value = replace_selected_text_params.value;
-      break;
-    }
-    case api::automation::ACTION_TYPE_SETVALUE: {
-      api::automation_internal::SetValueParams set_value_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::SetValueParams::Populate(
-              params->opt_args.additional_properties, &set_value_params));
-      action->action = ax::mojom::Action::kSetValue;
-      action->value = set_value_params.value;
-      break;
-    }
-    // These actions are currently unused by any existing clients of
-    // automation. They also require additional arguments to be plumbed
-    // through (e.g. setValue takes a string value to be set). Future clients
-    // may wish to extend the api to support these actions.
-    case api::automation::ACTION_TYPE_SCROLLTOPOINT:
-    case api::automation::ACTION_TYPE_SETSCROLLOFFSET:
-      return RespondNow(
-          Error("Unsupported action: " + params->args.action_type));
-    case api::automation::ACTION_TYPE_GETTEXTLOCATION: {
-      api::automation_internal::GetTextLocationDataParams
-          get_text_location_params;
-      EXTENSION_FUNCTION_VALIDATE(
-          api::automation_internal::GetTextLocationDataParams::Populate(
-              params->opt_args.additional_properties,
-              &get_text_location_params));
-      action->action = ax::mojom::Action::kGetTextLocation;
-      action->start_index = get_text_location_params.start_index;
-      action->end_index = get_text_location_params.end_index;
-      break;
-    }
-    case api::automation::ACTION_TYPE_SIGNALENDOFTEST:
-    case api::automation::ACTION_TYPE_NONE:
-      break;
-  }
-  return RespondNow(NoArguments());
-}
-
-ExtensionFunction::ResponseAction
-AutomationInternalPerformActionFunction::Run() {
-  const AutomationInfo* automation_info = AutomationInfo::Get(extension());
-  EXTENSION_FUNCTION_VALIDATE(automation_info && automation_info->interact);
-
-  using api::automation_internal::PerformAction::Params;
-  std::unique_ptr<Params> params(Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-  ui::AXTreeIDRegistry* registry = ui::AXTreeIDRegistry::GetInstance();
-  ui::AXActionHandler* action_handler = registry->GetActionHandler(
-      ui::AXTreeID::FromString(params->args.tree_id));
-  if (action_handler) {
-    // Handle an AXActionHandler with a rfh first. Some actions require a rfh ->
-    // web contents and this api requires web contents to perform a permissions
-    // check.
-    content::RenderFrameHost* rfh = content::RenderFrameHost::FromAXTreeID(
-        ui::AXTreeID::FromString(params->args.tree_id));
-    if (rfh) {
-      content::WebContents* contents =
-          content::WebContents::FromRenderFrameHost(rfh);
-      if (!CanRequestAutomation(extension(), automation_info, contents)) {
-        return RespondNow(
-            Error(kCannotRequestAutomationOnPage, contents->GetURL().spec()));
-      }
-
-      // Handle internal actions.
-      api::automation_internal::ActionTypePrivate internal_action_type =
-          api::automation_internal::ParseActionTypePrivate(
-              params->args.action_type);
-      content::MediaSession* session = content::MediaSession::Get(contents);
-      switch (internal_action_type) {
-        case api::automation_internal::ACTION_TYPE_PRIVATE_STARTDUCKINGMEDIA:
-          session->StartDucking();
-          return RespondNow(NoArguments());
-        case api::automation_internal::ACTION_TYPE_PRIVATE_STOPDUCKINGMEDIA:
-          session->StopDucking();
-          return RespondNow(NoArguments());
-        case api::automation_internal::ACTION_TYPE_PRIVATE_RESUMEMEDIA:
-          session->Resume(content::MediaSession::SuspendType::kSystem);
-          return RespondNow(NoArguments());
-        case api::automation_internal::ACTION_TYPE_PRIVATE_SUSPENDMEDIA:
-          session->Suspend(content::MediaSession::SuspendType::kSystem);
-          return RespondNow(NoArguments());
-        case api::automation_internal::ACTION_TYPE_PRIVATE_NONE:
-          // Not a private action.
-          break;
-      }
-    }
-
-    ui::AXActionData data;
-    ExtensionFunction::ResponseAction result =
-        ConvertToAXActionData(params.get(), &data);
-    action_handler->PerformAction(data);
-    return result;
-  }
-  return RespondNow(Error("Unable to perform action on unknown tree."));
-}
-
-ExtensionFunction::ResponseAction
-AutomationInternalEnableDesktopFunction::Run() {
-#if defined(USE_AURA)
-  const AutomationInfo* automation_info = AutomationInfo::Get(extension());
-  if (!automation_info || !automation_info->desktop)
-    return RespondNow(Error("desktop permission must be requested"));
-
-  // This gets removed when the extension process dies.
-  AutomationEventRouter::GetInstance()->RegisterListenerWithDesktopPermission(
-      extension_id(), source_process_id());
-
-  AutomationManagerAura::GetInstance()->Enable();
-  ui::AXTreeID ax_tree_id = AutomationManagerAura::GetInstance()->ax_tree_id();
-  return RespondNow(
-      ArgumentList(api::automation_internal::EnableDesktop::Results::Create(
-          ax_tree_id.ToString())));
-#else
-  return RespondNow(Error("getDesktop is unsupported by this platform"));
-#endif  // defined(USE_AURA)
-}
-
-// static
-int AutomationInternalQuerySelectorFunction::query_request_id_counter_ = 0;
-
-ExtensionFunction::ResponseAction
-AutomationInternalQuerySelectorFunction::Run() {
-  const AutomationInfo* automation_info = AutomationInfo::Get(extension());
-  EXTENSION_FUNCTION_VALIDATE(automation_info);
-
-  using api::automation_internal::QuerySelector::Params;
-  std::unique_ptr<Params> params(Params::Create(*args_));
-  EXTENSION_FUNCTION_VALIDATE(params.get());
-
-  content::RenderFrameHost* rfh = content::RenderFrameHost::FromAXTreeID(
-      ui::AXTreeID::FromString(params->args.tree_id));
-  if (!rfh) {
-    return RespondNow(
-        Error("domQuerySelector query sent on non-web or destroyed tree."));
-  }
-
-  content::WebContents* contents =
-      content::WebContents::FromRenderFrameHost(rfh);
-
-  int request_id = query_request_id_counter_++;
-  base::string16 selector = base::UTF8ToUTF16(params->args.selector);
-
-  // QuerySelectorHandler handles IPCs and deletes itself on completion.
-  new QuerySelectorHandler(
-      contents, request_id, params->args.automation_node_id, selector,
-      base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this));
-
-  return RespondLater();
-}
-
-void AutomationInternalQuerySelectorFunction::OnResponse(
-    const std::string& error,
-    int result_acc_obj_id) {
-  if (!error.empty()) {
-    Respond(Error(error));
-    return;
-  }
-
-  Respond(OneArgument(std::make_unique<base::Value>(result_acc_obj_id)));
-}
-
-}  // namespace cast
-}  // namespace extensions
diff --git a/chromecast/browser/extensions/api/automation_internal/automation_internal_api.h b/chromecast/browser/extensions/api/automation_internal/automation_internal_api.h
deleted file mode 100644
index bca6ae1f..0000000
--- a/chromecast/browser/extensions/api/automation_internal/automation_internal_api.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-// TODO(crbug/837773) This file was copied from
-// chrome/browser/extensions/api/automation_internal.
-// Copied code will be de-duped later.
-
-#ifndef CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
-#define CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
-
-#include <string>
-
-#include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
-#include "extensions/browser/extension_function.h"
-
-namespace extensions {
-namespace cast {
-namespace api {
-namespace automation_internal {
-namespace PerformAction {
-struct Params;
-}  // namespace PerformAction
-}  // namespace automation_internal
-}  // namespace api
-}  // namespace cast
-}  // namespace extensions
-
-namespace ui {
-struct AXActionData;
-}  // namespace ui
-
-namespace extensions {
-namespace cast {
-
-// Implementation of the chrome.automation API.
-class AutomationInternalEnableTabFunction : public UIThreadExtensionFunction {
-  DECLARE_EXTENSION_FUNCTION("automationInternal.enableTab",
-                             AUTOMATIONINTERNAL_ENABLETAB)
- protected:
-  ~AutomationInternalEnableTabFunction() override {}
-
-  ExtensionFunction::ResponseAction Run() override;
-};
-
-class AutomationInternalPerformActionFunction
-    : public UIThreadExtensionFunction {
-  DECLARE_EXTENSION_FUNCTION("automationInternal.performAction",
-                             AUTOMATIONINTERNAL_PERFORMACTION)
- protected:
-  ~AutomationInternalPerformActionFunction() override {}
-
-  ExtensionFunction::ResponseAction Run() override;
-
- private:
-  // Helper function to convert extension action to ax action.
-  ExtensionFunction::ResponseAction ConvertToAXActionData(
-      api::automation_internal::PerformAction::Params* params,
-      ui::AXActionData* data);
-};
-
-class AutomationInternalEnableFrameFunction : public UIThreadExtensionFunction {
-  DECLARE_EXTENSION_FUNCTION("automationInternal.enableFrame",
-                             AUTOMATIONINTERNAL_ENABLEFRAME)
-
- protected:
-  ~AutomationInternalEnableFrameFunction() override {}
-
-  ExtensionFunction::ResponseAction Run() override;
-};
-
-class AutomationInternalEnableDesktopFunction
-    : public UIThreadExtensionFunction {
-  DECLARE_EXTENSION_FUNCTION("automationInternal.enableDesktop",
-                             AUTOMATIONINTERNAL_ENABLEDESKTOP)
- protected:
-  ~AutomationInternalEnableDesktopFunction() override {}
-
-  ResponseAction Run() override;
-};
-
-class AutomationInternalQuerySelectorFunction
-    : public UIThreadExtensionFunction {
-  DECLARE_EXTENSION_FUNCTION("automationInternal.querySelector",
-                             AUTOMATIONINTERNAL_QUERYSELECTOR)
-
- public:
-  typedef base::Callback<void(const std::string& error, int result_acc_obj_id)>
-      Callback;
-
- protected:
-  ~AutomationInternalQuerySelectorFunction() override {}
-
-  ResponseAction Run() override;
-
- private:
-  void OnResponse(const std::string& error, int result_acc_obj_id);
-
-  // Used for assigning a unique ID to each request so that the response can be
-  // routed appropriately.
-  static int query_request_id_counter_;
-};
-
-}  // namespace cast
-}  // namespace extensions
-
-#endif  // CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
diff --git a/chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.cc b/chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.cc
new file mode 100644
index 0000000..be25364
--- /dev/null
+++ b/chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.cc
@@ -0,0 +1,86 @@
+// 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 "chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "chromecast/browser/extensions/api/tabs/tabs_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/common/api/automation.h"
+#include "extensions/common/api/automation_internal.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/manifest_handlers/automation.h"
+#include "extensions/common/permissions/permissions_data.h"
+
+#if defined(USE_AURA)
+#include "chromecast/browser/ui/aura/accessibility/automation_manager_aura.h"
+#endif
+
+namespace extensions {
+
+ChromecastAutomationInternalApiDelegate::
+    ChromecastAutomationInternalApiDelegate() {}
+
+ChromecastAutomationInternalApiDelegate::
+    ~ChromecastAutomationInternalApiDelegate() {}
+
+bool ChromecastAutomationInternalApiDelegate::CanRequestAutomation(
+    const Extension* extension,
+    const AutomationInfo* automation_info,
+    content::WebContents* contents) {
+  if (automation_info->desktop)
+    return true;
+
+  const GURL& url = contents->GetURL();
+  if (automation_info->matches.MatchesURL(url))
+    return true;
+
+  return false;
+}
+
+bool ChromecastAutomationInternalApiDelegate::GetTabById(
+    int tab_id,
+    content::BrowserContext* browser_context,
+    bool include_incognito,
+    content::WebContents** contents,
+    std::string* error_msg) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+int ChromecastAutomationInternalApiDelegate::GetTabId(
+    content::WebContents* contents) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+content::WebContents*
+ChromecastAutomationInternalApiDelegate::GetActiveWebContents(
+    UIThreadExtensionFunction* function) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void ChromecastAutomationInternalApiDelegate::EnableDesktop() {
+  AutomationManagerAura::GetInstance()->Enable();
+}
+
+ui::AXTreeID ChromecastAutomationInternalApiDelegate::GetAXTreeID() {
+  return AutomationManagerAura::GetInstance()->ax_tree_id();
+}
+
+void ChromecastAutomationInternalApiDelegate::SetEventBundleSink(
+    ui::AXEventBundleSink* sink) {
+  AutomationManagerAura::GetInstance()->set_event_bundle_sink(sink);
+}
+
+content::BrowserContext*
+ChromecastAutomationInternalApiDelegate::GetActiveUserContext() {
+  // Active user profile is set by Chromecast
+  return nullptr;
+}
+
+}  // namespace extensions
diff --git a/chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.h b/chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.h
new file mode 100644
index 0000000..3493a54
--- /dev/null
+++ b/chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.h
@@ -0,0 +1,41 @@
+// 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 CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROMECAST_AUTOMATION_INTERNAL_API_DELEGATE_H_
+#define CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROMECAST_AUTOMATION_INTERNAL_API_DELEGATE_H_
+
+#include "base/macros.h"
+#include "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
+
+namespace extensions {
+
+// A delegate for chromecast specific automation api logic.
+class ChromecastAutomationInternalApiDelegate
+    : public AutomationInternalApiDelegate {
+ public:
+  ChromecastAutomationInternalApiDelegate();
+  ~ChromecastAutomationInternalApiDelegate() override;
+
+  bool CanRequestAutomation(const Extension* extension,
+                            const AutomationInfo* automation_info,
+                            content::WebContents* contents) override;
+  bool GetTabById(int tab_id,
+                  content::BrowserContext* browser_context,
+                  bool include_incognito,
+                  content::WebContents** contents,
+                  std::string* error_msg) override;
+  int GetTabId(content::WebContents* contents) override;
+  content::WebContents* GetActiveWebContents(
+      UIThreadExtensionFunction* function) override;
+  void EnableDesktop() override;
+  ui::AXTreeID GetAXTreeID() override;
+  void SetEventBundleSink(ui::AXEventBundleSink* sink) override;
+  content::BrowserContext* GetActiveUserContext() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromecastAutomationInternalApiDelegate);
+};
+
+}  // namespace extensions
+
+#endif  // CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_CHROMECAST_AUTOMATION_INTERNAL_API_DELEGATE_H_
diff --git a/chromecast/browser/extensions/cast_extensions_api_client.cc b/chromecast/browser/extensions/cast_extensions_api_client.cc
index 5071324..593e6bd 100644
--- a/chromecast/browser/extensions/cast_extensions_api_client.cc
+++ b/chromecast/browser/extensions/cast_extensions_api_client.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "chromecast/browser/extensions/api/automation_internal/chromecast_automation_internal_api_delegate.h"
 #include "chromecast/browser/extensions/cast_extension_web_contents_observer.h"
 #include "content/public/browser/browser_context.h"
 #include "extensions/browser/api/messaging/messaging_delegate.h"
@@ -46,4 +47,13 @@
   return messaging_delegate_.get();
 }
 
+AutomationInternalApiDelegate*
+CastExtensionsAPIClient::GetAutomationInternalApiDelegate() {
+  if (!extensions_automation_api_delegate_) {
+    extensions_automation_api_delegate_ =
+        std::make_unique<ChromecastAutomationInternalApiDelegate>();
+  }
+  return extensions_automation_api_delegate_.get();
+}
+
 }  // namespace extensions
diff --git a/chromecast/browser/extensions/cast_extensions_api_client.h b/chromecast/browser/extensions/cast_extensions_api_client.h
index 173bfb8..816f45a9 100644
--- a/chromecast/browser/extensions/cast_extensions_api_client.h
+++ b/chromecast/browser/extensions/cast_extensions_api_client.h
@@ -11,6 +11,7 @@
 
 namespace extensions {
 
+class ChromecastAutomationInternalApiDelegate;
 class MessagingDelegate;
 
 class CastExtensionsAPIClient : public ExtensionsAPIClient {
@@ -24,9 +25,12 @@
   WebViewGuestDelegate* CreateWebViewGuestDelegate(
       WebViewGuest* web_view_guest) const override;
   MessagingDelegate* GetMessagingDelegate() override;
+  AutomationInternalApiDelegate* GetAutomationInternalApiDelegate() override;
 
  private:
   std::unique_ptr<MessagingDelegate> messaging_delegate_;
+  std::unique_ptr<extensions::ChromecastAutomationInternalApiDelegate>
+      extensions_automation_api_delegate_;
 
   DISALLOW_COPY_AND_ASSIGN(CastExtensionsAPIClient);
 };
diff --git a/chromecast/common/extensions_api/BUILD.gn b/chromecast/common/extensions_api/BUILD.gn
index 88f14a4..258e6357 100644
--- a/chromecast/common/extensions_api/BUILD.gn
+++ b/chromecast/common/extensions_api/BUILD.gn
@@ -15,8 +15,6 @@
 schema_sources = [
   # TODO(crbug/837773) De-dupe Automation later.
   "accessibility_private.json",
-  "automation.idl",
-  "automation_internal.idl",
   "bookmarks.json",
   "braille_display_private.idl",
   "history.json",
diff --git a/chromecast/common/extensions_api/_api_features.json b/chromecast/common/extensions_api/_api_features.json
index fc8a3524..371548d 100644
--- a/chromecast/common/extensions_api/_api_features.json
+++ b/chromecast/common/extensions_api/_api_features.json
@@ -11,16 +11,6 @@
     "dependencies": ["permission:accessibilityPrivate"],
     "contexts": ["blessed_extension"]
   },
-  // TODO(crbug/837773) De-dupe automation later.
-  "automationInternal": {
-    "internal": true,
-    "dependencies": ["manifest:automation"],
-    "contexts": ["blessed_extension"]
-  },
-  "automation": {
-    "dependencies": ["manifest:automation"],
-    "contexts": ["blessed_extension"]
-  },
   "brailleDisplayPrivate": {
     "dependencies": ["permission:brailleDisplayPrivate"],
     "contexts": ["blessed_extension"]
diff --git a/chromecast/common/extensions_api/automation.idl b/chromecast/common/extensions_api/automation.idl
deleted file mode 100644
index 06759e3..0000000
--- a/chromecast/common/extensions_api/automation.idl
+++ /dev/null
@@ -1,1096 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// The <code>chrome.automation</code> API allows developers to access the
-// automation (accessibility) tree for the browser. The tree resembles the DOM
-// tree, but only exposes the <em>semantic</em> structure of a page. It can be
-// used to programmatically interact with a page by examining names, roles, and
-// states, listening for events, and performing actions on nodes.
-[nocompile] namespace automation {
-  // Keep the following enums in sync with 'ui/accessibility/ax_enums.idl'.
-  // They are kept here purely for extension docs generation.
-
-  // Possible events fired on an $(ref:automation.AutomationNode).
-  enum EventType {
-    activedescendantchanged,
-    alert,
-    ariaAttributeChanged,
-    autocorrectionOccured,
-    blur,
-    checkedStateChanged,
-    childrenChanged,
-    clicked,
-    documentSelectionChanged,
-    documentTitleChanged,
-    endOfTest,
-    expandedChanged,
-    focus,
-    focusContext,
-    imageFrameUpdated,
-    hide,
-    hitTestResult,
-    hover,
-    invalidStatusChanged,
-    layoutComplete,
-    liveRegionCreated,
-    liveRegionChanged,
-    loadComplete,
-    loadStart,
-    locationChanged,
-    mediaStartedPlaying,
-    mediaStoppedPlaying,
-    menuEnd,
-    menuListItemSelected,
-    menuListValueChanged,
-    menuPopupEnd,
-    menuPopupHide,
-    menuPopupStart,
-    menuStart,
-    mouseCanceled,
-    mouseDragged,
-    mouseMoved,
-    mousePressed,
-    mouseReleased,
-    rowCollapsed,
-    rowCountChanged,
-    rowExpanded,
-    scrollPositionChanged,
-    scrolledToAnchor,
-    selectedChildrenChanged,
-    selection,
-    selectionAdd,
-    selectionRemove,
-    show,
-    stateChanged,
-    textChanged,
-    textSelectionChanged,
-    windowActivated,
-    windowDeactivated,
-    treeChanged,
-    valueChanged
-  };
-
-  // Describes the purpose of an $(ref:automation.AutomationNode).
-  enum RoleType {
-    abbr,
-    alert,
-    alertDialog,
-    anchor,
-    annotation,
-    application,
-    article,
-    audio,
-    banner,
-    blockquote,
-    button,
-    canvas,
-    caption,
-    caret,
-    cell,
-    checkBox,
-    client,
-    colorWell,
-    column,
-    columnHeader,
-    comboBoxGrouping,
-    comboBoxMenuButton,
-    complementary,
-    contentDeletion,
-    contentInsertion,
-    contentInfo,
-    date,
-    dateTime,
-    definition,
-    descriptionList,
-    descriptionListDetail,
-    descriptionListTerm,
-    desktop,
-    details,
-    dialog,
-    directory,
-    disclosureTriangle,
-    // --------------------------------------------------------------
-    // DPub Roles:
-    // https://www.w3.org/TR/dpub-aam-1.0/#mapping_role_table
-    docAbstract,
-    docAcknowledgments,
-    docAfterword,
-    docAppendix,
-    docBackLink,
-    docBiblioEntry,
-    docBibliography,
-    docBiblioRef,
-    docChapter,
-    docColophon,
-    docConclusion,
-    docCover,
-    docCredit,
-    docCredits,
-    docDedication,
-    docEndnote,
-    docEndnotes,
-    docEpigraph,
-    docEpilogue,
-    docErrata,
-    docExample,
-    docFootnote,
-    docForeword,
-    docGlossary,
-    docGlossRef,
-    docIndex,
-    docIntroduction,
-    docNoteRef,
-    docNotice,
-    docPageBreak,
-    docPageList,
-    docPart,
-    docPreface,
-    docPrologue,
-    docPullquote,
-    docQna,
-    docSubtitle,
-    docTip,
-    docToc,
-    // End DPub roles.
-    // --------------------------------------------------------------
-    document,
-    embeddedObject,
-    feed,
-    figcaption,
-    figure,
-    footer,
-    form,
-    genericContainer,
-    // --------------------------------------------------------------
-    // ARIA Graphics module roles:
-    // https://rawgit.com/w3c/graphics-aam/master/#mapping_role_table
-    graphicsDocument,
-    graphicsObject,
-    graphicsSymbol,
-    // End ARIA Graphics module roles.
-    // --------------------------------------------------------------
-    grid,
-    group,
-    heading,
-    iframe,
-    iframePresentational,
-    ignored,
-    image,
-    imageMap,
-    inlineTextBox,
-    inputTime,
-    keyboard,
-    labelText,
-    layoutTable,
-    layoutTableCell,
-    layoutTableColumn,
-    layoutTableRow,
-    legend,
-    lineBreak,
-    link,
-    list,
-    listBox,
-    listBoxOption,
-    listGrid,  // Native
-    listItem,
-    listMarker,
-    log,
-    main,
-    mark,
-    marquee,
-    math,
-    menu,
-    menuBar,
-    menuButton,
-    menuItem,
-    menuItemCheckBox,
-    menuItemRadio,
-    menuListOption,
-    menuListPopup,
-    meter,
-    navigation,
-    note,
-    pane,
-    paragraph,
-    popUpButton,
-    pre,
-    presentational,
-    progressIndicator,
-    radioButton,
-    radioGroup,
-    region,
-    rootWebArea,
-    row,
-    rowHeader,
-    ruby,
-    scrollBar,
-    scrollView,
-    search,
-    searchBox,
-    slider,
-    sliderThumb,
-    spinButton,
-    splitter,
-    staticText,
-    status,
-    svgRoot,
-    switch,
-    tab,
-    tabList,
-    tabPanel,
-    table,
-    tableHeaderContainer,
-    term,
-    textField,
-    textFieldWithComboBox,
-    time,
-    timer,
-    titleBar,
-    toggleButton,
-    toolbar,
-    tooltip,
-    tree,
-    treeGrid,
-    treeItem,
-    unknown,
-    video,
-    webArea,
-    webView,
-    window
-  };
-
-  // Describes characteristics of an $(ref:automation.AutomationNode).
-  enum StateType {
-    autofillAvailable,
-    collapsed,
-    default,
-    editable,
-    expanded,
-    focusable,
-    focused,
-    horizontal,
-    hovered,
-    ignored,
-    invisible,
-    linked,
-    multiline,
-    multiselectable,
-    offscreen,
-    protected,
-    required,
-    richlyEditable,
-    vertical,
-    visited
-  };
-
-  // All possible actions that can be performed on automation nodes.
-  enum ActionType {
-    blur,
-    clearAccessibilityFocus,
-    customAction,
-    decrement,
-    doDefault,
-    focus,
-    getImageData,
-    getTextLocation,
-    hitTest,
-    increment,
-    loadInlineTextBoxes,
-    replaceSelectedText,
-    scrollBackward,
-    scrollDown,
-    scrollForward,
-    scrollLeft,
-    scrollRight,
-    scrollToMakeVisible,
-    scrollToPoint,
-    scrollUp,
-    setAccessibilityFocus,
-    setScrollOffset,
-    setSelection,
-    setSequentialFocusNavigationStartingPoint,
-    setValue,
-    showContextMenu,
-    signalEndOfTest
-  };
-
-  // Possible changes to the automation tree. For any given atomic change
-  // to the tree, each node that's added, removed, or changed, will appear
-  // in exactly one TreeChange, with one of these types.
-  //
-  //
-  // nodeCreated means that this node was added to the tree and its parent is
-  // new as well, so it's just one node in a new subtree that was added.
-  enum TreeChangeType {
-    /**
-     * This node was added to the tree and its parent is new as well,
-     * so it's just one node in a new subtree that was added.
-     */
-    nodeCreated,
-
-    /**
-     * This node was added to the tree but its parent was already in the
-     * tree, so it's possibly the root of a new subtree - it does not mean
-     * that it necessarily has children.
-     */
-    subtreeCreated,
-
-    /**
-     * This node changed.
-     */
-    nodeChanged,
-
-    /**
-     * This node's text (name) changed.
-     */
-    textChanged,
-
-    /**
-     * This node was removed.
-     */
-    nodeRemoved,
-    /**
-     * This subtree has finished an update.
-     */
-    subtreeUpdateEnd
-  };
-
-  // Where the node's name is from.
-  enum NameFromType {
-    uninitialized,
-    attribute,
-    attributeExplicitlyEmpty,
-    caption,
-    contents,
-    placeholder,
-    relatedElement,
-    title,
-    value
-  };
-
-  // The input restriction for a object -- even non-controls can be disabled.
-  enum Restriction {
-    disabled,
-    readOnly
-  };
-
-  // Indicates the availability and type of interactive popup element
-  enum HasPopup {
-    true,
-    menu,
-    listbox,
-    tree,
-    grid,
-    dialog
-  };
-
-  // Describes possible actions when performing a do default action.
-  enum DefaultActionVerb {
-    activate,
-    check,
-    click,
-    clickAncestor,
-    jump,
-    open,
-    press,
-    select,
-    uncheck
-};
-
-  dictionary Rect {
-    long left;
-    long top;
-    long width;
-    long height;
-  };
-
-  // Arguments for the find() and findAll() methods.
-  [nocompile, noinline_doc] dictionary FindParams {
-    RoleType? role;
-
-    // A map of $(ref:automation.StateType) to boolean, indicating for each
-    // state whether it should be set or not. For example:
-    // <code>{ StateType.disabled: false }</code> would only match if
-    // <code>StateType.disabled</code> was <em>not</em> present in the node's
-    // <code>state</code> object.
-    object? state;
-
-    // A map of attribute name to expected value, for example
-    // <code>{ name: 'Root directory', checkbox_mixed: true }</code>.
-    // String attribute values may be specified as a regex, for example
-    // <code>{ name: /stralia$/</code> }</code>.
-    // Unless specifying a regex, the expected value must be an exact match
-    // in type and value for the actual value. Thus, the type of expected value
-    // must be one of:
-    // <ul>
-    // <li>string</li>
-    // <li>integer</li>
-    // <li>float</li>
-    // <li>boolean</li>
-    // </ul>
-    object? attributes;
-  };
-
-  // Arguments for the setDocumentSelection() function.
-  [nocompile, noinline_doc] dictionary SetDocumentSelectionParams {
-    // The node where the selection begins.
-    [instanceOf=AutomationNode] object anchorObject;
-    // The offset in the anchor node where the selection begins.
-    long anchorOffset;
-    // The node where the selection ends.
-    [instanceOf=AutomationNode] object focusObject;
-    // The offset within the focus node where the selection ends.
-    long focusOffset;
-  };
-
-  // Called when the result for a <code>query</code> is available.
-  callback QueryCallback = void(AutomationNode node);
-
-  // An event in the Automation tree.
-  [nocompile, noinline_doc] dictionary AutomationEvent {
-    // The $(ref:automation.AutomationNode) to which the event was targeted.
-    AutomationNode target;
-
-    // The type of the event.
-    EventType type;
-
-    // The source of this event.
-    DOMString eventFrom;
-
-    long mouseX;
-    long mouseY;
-
-    // Stops this event from further processing except for any remaining
-    // listeners on $(ref:AutomationEvent.target).
-    static void stopPropagation();
-  };
-
-  // A listener for events on an <code>AutomationNode</code>.
-  callback AutomationListener = void(AutomationEvent event);
-
-  // A change to the Automation tree.
-  [nocompile, noinline_doc] dictionary TreeChange {
-    // The $(ref:automation.AutomationNode) that changed.
-    AutomationNode target;
-
-    // The type of change.
-    TreeChangeType type;
-  };
-
-  // Possible tree changes to listen to using addTreeChangeObserver.
-  // Note that listening to all tree changes can be expensive.
-  enum TreeChangeObserverFilter {
-    noTreeChanges,
-    liveRegionTreeChanges,
-    textMarkerChanges,
-    allTreeChanges
-  };
-
-  // A listener for changes on the <code>AutomationNode</code> tree.
-  callback TreeChangeObserver = void(TreeChange treeChange);
-
-  // Callback called for actions with a response.
-  callback PerformActionCallback = void(boolean result);
-  callback PerformActionCallbackWithNode = void(AutomationNode node);
-  callback BoundsForRangeCallback = void(Rect bounds);
-
-
-  dictionary CustomAction {
-    long id;
-    DOMString description;
-  };
-
-  // A single node in an Automation tree.
-  [nocompile, noinline_doc] dictionary AutomationNode {
-    // The root node of the tree containing this AutomationNode.
-    AutomationNode? root;
-
-    // Whether this AutomationNode is a root node.
-    boolean isRootNode;
-
-    // The role of this node.
-    RoleType? role;
-
-    // The $(ref:automation.StateType)s describing this node.
-    // <jsexterns>@type {Object<chrome.automation.StateType, boolean>}
-    // </jsexterns>
-    object? state;
-
-    // The rendered location (as a bounding box) of this node in global
-    // screen coordinates.
-    Rect? location;
-
-    // Determines the location of the text within the node specified by
-    // |startIndex| and |endIndex|, inclusively. Invokes |callback| with the
-    // bounding rectangle, in screen coordinates. |callback| can be invoked
-    // either synchronously or asynchronously.
-    static void boundsForRange(long startIndex, long endIndex,
-        BoundsForRangeCallback callback);
-
-    // The location (as a bounding box) of this node in global screen
-    // coordinates without applying any clipping from ancestors.
-    Rect? unclippedLocation;
-
-    // The purpose of the node, other than the role, if any.
-    DOMString? description;
-
-    // The placeholder for this text field, if any.
-    DOMString? placeholder;
-
-    // The role description for this node.
-    DOMString? roleDescription;
-
-    // The accessible name for this node, via the
-    // <a href="http://www.w3.org/TR/wai-aria/roles#namecalculation">
-    // Accessible Name Calculation</a> process.
-    DOMString? name;
-
-    // The source of the name.
-    NameFromType? nameFrom;
-
-    // The value for this node: for example the <code>value</code> attribute of
-    // an <code>&lt;input&gt; element.
-    DOMString? value;
-
-    // The HTML tag for this element, if this node is an HTML element.
-    DOMString? htmlTag;
-
-    // The level of a heading or tree item.
-    long? hierarchicalLevel;
-
-    // The start and end index of each word in an inline text box.
-    long[]? wordStarts;
-    long[]? wordEnds;
-
-    // The nodes, if any, which this node is specified to control via
-    // <a href="http://www.w3.org/TR/wai-aria/states_and_properties#aria-controls">
-    // <code>aria-controls</code></a>.
-    AutomationNode[]? controls;
-
-    // The nodes, if any, which form a description for this node.
-    AutomationNode[]? describedBy;
-
-    // The nodes, if any, which may optionally be navigated to after this
-    // one. See
-    // <a href="http://www.w3.org/TR/wai-aria/states_and_properties#aria-flowto">
-    // <code>aria-flowto</code></a>.
-    AutomationNode[]? flowTo;
-
-    // The nodes, if any, which form a label for this element. Generally, the
-    // text from these elements will also be exposed as the element's accessible
-    // name, via the $(ref:automation.AutomationNode.name) attribute.
-    AutomationNode[]? labelledBy;
-
-    // The node referred to by <code>aria-activedescendant</code>, where
-    // applicable
-    AutomationNode? activeDescendant;
-
-    // Reverse relationship for active descendant.
-    AutomationNode[]? activeDescendantFor;
-
-    // The target of an in-page link.
-    AutomationNode? inPageLinkTarget;
-
-    // A node that provides more details about the current node.
-    AutomationNode? details;
-
-    // A node that provides an error message for a current node.
-    AutomationNode? errorMessage;
-
-    // Reverse relationship for details.
-    AutomationNode[]? detailsFor;
-
-    // Reverse relationship for errorMessage.
-    AutomationNode[]? errorMessageFor;
-
-    // Reverse relationship for controls.
-    AutomationNode[]? controlledBy;
-
-    // Reverse relationship for describedBy.
-    AutomationNode[]? descriptionFor;
-
-    // Reverse relationship for flowTo.
-    AutomationNode[]? flowFrom;
-
-    // Reverse relationship for labelledBy.
-    AutomationNode[]? labelFor;
-
-    // The column header nodes for a table cell.
-    AutomationNode[]? tableCellColumnHeaders;
-
-    // The row header nodes for a table cell.
-    AutomationNode[]? tableCellRowHeaders;
-
-    // An array of standard actions available on this node.
-    ActionType[]? standardActions;
-
-    // An array of custom actions.
-    CustomAction[]? customActions;
-
-    // The action taken by calling <code>doDefault</code>.
-    DefaultActionVerb? defaultActionVerb;
-
-    //
-    // Link attributes.
-    //
-
-    // The URL that this link will navigate to.
-    DOMString? url;
-
-    //
-    // Document attributes.
-    //
-
-    // The URL of this document.
-    DOMString? docUrl;
-
-    // The title of this document.
-    DOMString? docTitle;
-
-    // Whether this document has finished loading.
-    boolean? docLoaded;
-
-    // The proportion (out of 1.0) that this doc has completed loading.
-    double? docLoadingProgress;
-
-    //
-    // Scrollable container attributes.
-    //
-
-    long? scrollX;
-    long? scrollXMin;
-    long? scrollXMax;
-    long? scrollY;
-    long? scrollYMin;
-    long? scrollYMax;
-
-    // Indicates whether this node is scrollable.
-    boolean? scrollable;
-
-    //
-    // Editable text field attributes.
-    //
-
-    // The character index of the start of the selection within this editable
-    // text element; -1 if no selection.
-    long? textSelStart;
-
-    // The character index of the end of the selection within this editable
-    // text element; -1 if no selection.
-    long? textSelEnd;
-
-    // The input type, like email or number.
-    DOMString? textInputType;
-
-    // An array of indexes of the start position of each text marker.
-    long[] markerStarts;
-
-    // An array of indexes of the end position of each text marker.
-    long[] markerEnds;
-
-    // An array of numerical types indicating the type of each text marker,
-    // such as a spelling error.
-    long[] markerTypes;
-
-    //
-    // Tree selection attributes (available on root nodes only)
-    //
-
-    // The anchor node of the tree selection, if any.
-    AutomationNode? anchorObject;
-    // The anchor offset of the tree selection, if any.
-    long? anchorOffset;
-    // The affinity of the tree selection anchor, if any.
-    DOMString? anchorAffinity;
-    // The focus node of the tree selection, if any.
-    AutomationNode? focusObject;
-    // The focus offset of the tree selection, if any.
-    long? focusOffset;
-    // The affinity of the tree selection focus, if any.
-    DOMString? focusAffinity;
-
-    //
-    // Range attributes.
-    //
-
-    // The current value for this range.
-    double? valueForRange;
-
-    // The minimum possible value for this range.
-    double? minValueForRange;
-
-    // The maximum possible value for this range.
-    double? maxValueForRange;
-
-    //
-    // List attributes.
-    //
-
-    // The 1-based index of an item in a set.
-    long? posInSet;
-
-    // The number of items in a set;
-    long? setSize;
-
-    //
-    // Table attributes.
-    //
-
-    // The number of rows in this table as specified in the DOM.
-    long? tableRowCount;
-
-    // The number of rows in this table as specified by the page author.
-    long? ariaRowCount;
-
-    // The number of columns in this table as specified in the DOM.
-    long? tableColumnCount;
-
-    // The number of columns in this table as specified by the page author.
-    long? ariaColumnCount;
-
-    //
-    // Table cell attributes.
-    //
-
-    // The zero-based index of the column that this cell is in as specified in
-    // the DOM.
-    long? tableCellColumnIndex;
-
-    // The ARIA column index as specified by the page author.
-    long? ariaCellColumnIndex;
-
-    // The number of columns that this cell spans (default is 1).
-    long? tableCellColumnSpan;
-
-    // The zero-based index of the row that this cell is in as specified in the
-    // DOM.
-    long? tableCellRowIndex;
-
-    // The ARIA row index as specified by the page author.
-    long? ariaCellRowIndex;
-
-    // The number of rows that this cell spans (default is 1).
-    long? tableCellRowSpan;
-
-    // The corresponding column header for this cell.
-    AutomationNode? tableColumnHeader;
-
-    // The corresponding row header for this cell.
-    AutomationNode? tableRowHeader;
-
-    // The column index of this column node.
-    long? tableColumnIndex;
-
-    // The row index of this row node.
-    long? tableRowIndex;
-
-    //
-    // Live region attributes.
-    //
-
-    // The type of region if this is the root of a live region.
-    // Possible values are 'polite' and 'assertive'.
-    DOMString? liveStatus;
-
-    // The value of aria-relevant for a live region.
-    DOMString? liveRelevant;
-
-    // The value of aria-atomic for a live region.
-    boolean? liveAtomic;
-
-    // The value of aria-busy for a live region or any other element.
-    boolean? busy;
-
-    // The type of live region if this node is inside a live region.
-    DOMString? containerLiveStatus;
-
-    // The value of aria-relevant if this node is inside a live region.
-    DOMString? containerLiveRelevant;
-
-    // The value of aria-atomic if this node is inside a live region.
-    boolean? containerLiveAtomic;
-
-    // The value of aria-busy if this node is inside a live region.
-    boolean? containerLiveBusy;
-
-    //
-    // Miscellaneous attributes.
-    //
-
-    // Aria auto complete.
-    DOMString? autoComplete;
-
-    // The name of the programmatic backing object.
-    DOMString? className;
-
-    // Marks this subtree as modal.
-    boolean? modal;
-
-    // A map containing all HTML attributes and their values
-    // <jsexterns>@type {Object<string>}</jsexterns>
-    object? htmlAttributes;
-
-    // The input type of a text field, such as "text" or "email".
-    DOMString? inputType;
-
-    // The key that activates this widget.
-    DOMString? accessKey;
-
-    // The value of the aria-invalid attribute, indicating the error type.
-    DOMString? ariaInvalidValue;
-
-    // The CSS display attribute for this node, if applicable.
-    DOMString? display;
-
-    // A data url with the contents of this object's image or thumbnail.
-    DOMString? imageDataUrl;
-
-    // The language code for this subtree.
-    DOMString? language;
-
-    // Indicates the availability and type of interactive popup element
-    // true - the popup is a menu
-    // menu - the popup is a menu
-    // listbox - the popup is a listbox
-    // tree - the popup is a tree
-    // grid - the popup is a grid
-    // dialog - the popup is a dialog
-    DOMString? hasPopup;
-
-    // Input restriction, if any, such as readonly or disabled:
-    // undefined - enabled control or other object that is not disabled
-    // Restriction.DISABLED - disallows input in itself + any descendants
-    // Restriction.READONLY - allow focus/selection but not input
-    DOMString? restriction;
-
-    // Tri-state describing checkbox or radio button:
-    // 'false' | 'true' | 'mixed'
-    DOMString? checked;
-
-    // The inner html of this element. Only populated for math content.
-    DOMString? innerHtml;
-
-    // The RGBA foreground color of this subtree, as an integer.
-    long? color;
-
-    // The RGBA background color of this subtree, as an integer.
-    long? backgroundColor;
-
-    // The RGBA color of an input element whose value is a color.
-    long? colorValue;
-
-    // Indicates node text is subscript.
-    boolean subscript;
-
-    // Indicates node text is superscript.
-    boolean superscript;
-
-    // Indicates node text is bold.
-    boolean bold;
-
-    // Indicates node text is italic.
-    boolean italic;
-
-    // Indicates node text is underline.
-    boolean underline;
-
-    // Indicates node text is line through.
-    boolean lineThrough;
-
-    // Indicates whether this node is selected, unselected, or neither.
-    boolean? selected;
-
-    //
-    // Walking the tree.
-    //
-
-    AutomationNode[] children;
-    AutomationNode? parent;
-    AutomationNode? firstChild;
-    AutomationNode? lastChild;
-    AutomationNode? previousSibling;
-    AutomationNode? nextSibling;
-    AutomationNode? previousOnLine;
-    AutomationNode? nextOnLine;
-    AutomationNode? previousFocus;
-    AutomationNode? nextFocus;
-
-    // The index of this node in its parent node's list of children. If this is
-    // the root node, this will be undefined.
-    long? indexInParent;
-
-    //
-    // Actions.
-    //
-
-    // Does the default action based on this node's role. This is generally
-    // the same action that would result from clicking the node such as
-    // expanding a treeitem, toggling a checkbox, selecting a radiobutton,
-    // or activating a button.
-    static void doDefault();
-
-    // Places focus on this node.
-    static void focus();
-
-    // Request a data url for the contents of an image, optionally
-    // resized.  Pass zero for maxWidth and/or maxHeight for the
-    // original size.
-    static void getImageData(long maxWidth, long maxHeight);
-
-    // Does a hit test of the given global screen coordinates, and fires
-    // eventToFire on the resulting object.
-    static void hitTest(
-        long x,
-        long y,
-        EventType eventToFire);
-
-    // Does a $(ref:automation.AutomationNode.hitTest), and receives a callback
-    // with the resulting hit node.
-    static void hitTestWithReply(
-        long x,
-        long y,
-        PerformActionCallbackWithNode callback);
-
-    // Scrolls this node to make it visible.
-    static void makeVisible();
-
-    // Performs custom action.
-    static void performCustomAction(long customActionId);
-
-    // Convenience method to perform a standard action supported by this node.
-    // For actions requiring additional arguments, call the specific binding
-    // e.g. <code>setSelection</code>.
-    static void performStandardAction(ActionType actionType);
-
-    // Replaces the selected text within a text field.
-    static void replaceSelectedText(DOMString value);
-
-    // Sets selection within a text field.
-    static void setSelection(long startIndex, long endIndex);
-
-    // Clears focus and sets this node as the starting point for the next
-    // time the user presses Tab or Shift+Tab.
-    static void setSequentialFocusNavigationStartingPoint();
-
-    // Sets the value of a text field.
-    static void setValue(DOMString value);
-
-    // Show the context menu for this element, as if the user right-clicked.
-    static void showContextMenu();
-
-    // Resume playing any media within this tree.
-    static void resumeMedia();
-
-    // Start ducking any media within this tree.
-    static void startDuckingMedia();
-
-    // Stop ducking any media within this tree.
-    static void stopDuckingMedia();
-
-    // Suspend any media playing within this tree.
-    static void suspendMedia();
-
-    // Scrolls this scrollable container backward.
-    static void scrollBackward(PerformActionCallback callback);
-
-    // Scrolls this scrollable container forward.
-    static void scrollForward(PerformActionCallback callback);
-
-    // Scrolls this scrollable container up.
-    static void scrollUp(PerformActionCallback callback);
-
-    // Scrolls this scrollable container down.
-    static void scrollDown(PerformActionCallback callback);
-
-    // Scrolls this scrollable container left.
-    static void scrollLeft(PerformActionCallback callback);
-
-    // Scrolls this scrollable container right.
-    static void scrollRight(PerformActionCallback callback);
-
-    // Adds a listener for the given event type and event phase.
-    static void addEventListener(
-        EventType eventType, AutomationListener listener, boolean capture);
-
-    // Removes a listener for the given event type and event phase.
-    static void removeEventListener(
-        EventType eventType, AutomationListener listener, boolean capture);
-
-    // Gets the first node in this node's subtree which matches the given CSS
-    // selector and is within the same DOM context.
-    //
-    // If this node doesn't correspond directly with an HTML node in the DOM,
-    // querySelector will be run on this node's nearest HTML node ancestor. Note
-    // that this may result in the query returning a node which is not a
-    // descendant of this node.
-    //
-    // If the selector matches a node which doesn't directly correspond to an
-    // automation node (for example an element within an ARIA widget, where the
-    // ARIA widget forms one node of the automation tree, or an element which
-    // is hidden from accessibility via hiding it using CSS or using
-    // aria-hidden), this will return the nearest ancestor which does correspond
-    // to an automation node.
-    static void domQuerySelector(DOMString selector, QueryCallback callback);
-
-    // Finds the first AutomationNode in this node's subtree which matches the
-    // given search parameters.
-    static AutomationNode find(FindParams params);
-
-    // Finds all the AutomationNodes in this node's subtree which matches the
-    // given search parameters.
-    static AutomationNode[] findAll(FindParams params);
-
-    // Returns whether this node matches the given $(ref:automation.FindParams).
-    static boolean matches(FindParams params);
-
-    static AutomationNode getNextTextMatch(
-        DOMString searchStr, boolean backward);
-  };
-
-  // Called when the <code>AutomationNode</code> for the page is available.
-  callback RootCallback = void(AutomationNode rootNode);
-
-  // Called with the <code>AutomationNode</code> that currently has focus.
-  callback FocusCallback = void(AutomationNode focusedNode);
-
-  interface Functions {
-    // Get the automation tree for the tab with the given tabId, or the current
-    // tab if no tabID is given, enabling automation if necessary. Returns a
-    // tree with a placeholder root node; listen for the "loadComplete" event to
-    // get a notification that the tree has fully loaded (the previous root node
-    // reference will stop working at or before this point).
-    [nocompile] static void getTree(optional long tabId,
-                                    optional RootCallback callback);
-
-    // Get the automation tree for the whole desktop which consists of all on
-    // screen views. Note this API is currently only supported on Chrome OS.
-    [nocompile] static void getDesktop(RootCallback callback);
-
-    // Get the automation node that currently has focus, globally. Will return
-    // null if none of the nodes in any loaded trees have focus.
-    [nocompile] static void getFocus(FocusCallback callback);
-
-    // Add a tree change observer. Tree change observers are static/global, they
-    // listen to changes across all trees. Pass a filter to determine what
-    // specific tree changes to listen to, and note that listnening to all
-    // tree changes can be expensive.
-    [nocompile] static void addTreeChangeObserver(
-        TreeChangeObserverFilter filter, TreeChangeObserver observer);
-
-    // Remove a tree change observer.
-    [nocompile] static void removeTreeChangeObserver(
-        TreeChangeObserver observer);
-
-    // Sets the selection in a tree. This creates a selection in a single
-    // tree (anchorObject and focusObject must have the same root).
-    // Everything in the tree between the two node/offset pairs gets included
-    // in the selection. The anchor is where the user started the selection,
-    // while the focus is the point at which the selection gets extended
-    // e.g. when dragging with a mouse or using the keyboard. For nodes with
-    // the role staticText, the offset gives the character offset within
-    // the value where the selection starts or ends, respectively.
-    [nocompile] static void setDocumentSelection(
-        SetDocumentSelectionParams params);
-  };
-};
diff --git a/chromecast/common/extensions_api/automation_internal.idl b/chromecast/common/extensions_api/automation_internal.idl
deleted file mode 100644
index 084f0576..0000000
--- a/chromecast/common/extensions_api/automation_internal.idl
+++ /dev/null
@@ -1,175 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// This is the implementation layer of the chrome.automation API, and is
-// essentially a translation of the internal accessibility tree update system
-// into an extension API.
-namespace automationInternal {
-  // Data for an accessibility event and/or an atomic change to an accessibility
-  // tree. See ui/accessibility/ax_tree_update.h for an extended explanation of
-  // the tree update format.
-  [nocompile] dictionary AXEventParams {
-    // The tree id of the web contents that this update is for.
-    DOMString treeID;
-
-    // ID of the node that the event applies to.
-    long targetID;
-
-    // The type of event that this update represents.
-    DOMString eventType;
-
-    // The source of this event.
-    DOMString eventFrom;
-
-    // The mouse coordinates when this event fired.
-    double mouseX;
-    double mouseY;
-
-
-    // ID of an action request resulting in this event.
-    long actionRequestID;
-  };
-
-  dictionary AXTextLocationParams {
-    DOMString treeID;
-    long nodeID;
-    boolean result;
-    long left;
-    long top;
-    long width;
-    long height;
-    long requestID;
-  };
-
-  // Actions internally used by automation.
-  enum ActionTypePrivate {
-    resumeMedia,
-    startDuckingMedia,
-    stopDuckingMedia,
-    suspendMedia
-  };
-
-  // Arguments required for all actions supplied to performAction.
-  dictionary PerformActionRequiredParams {
-    DOMString treeID;
-    long automationNodeID;
-
-    // This can be either automation::ActionType or
-    // automation_internal::ActionTypePrivate.
-    DOMString actionType;
-
-    long? requestID;
-  };
-
-  // Arguments for the customAction action. Those args are passed to
-  // performAction as opt_args.
-  dictionary PerformCustomActionParams {
-    long customActionID;
-  };
-
-  // Arguments for the setSelection action supplied to performAction.
-  dictionary SetSelectionParams {
-    // Reuses ActionRequiredParams automationNodeID to mean anchor node id,
-    // and treeID to apply to both anchor and focus node ids.
-    long focusNodeID;
-    long anchorOffset;
-    long focusOffset;
-  };
-
-  // Arguments for the replaceSelectedText action supplied to performAction.
-  dictionary ReplaceSelectedTextParams {
-    DOMString value;
-  };
-
-  // Arguments for the setValue action supplied to performAction.
-  dictionary SetValueParams {
-    DOMString value;
-  };
-
-  // Arguments for the querySelector function.
-  dictionary QuerySelectorRequiredParams {
-    DOMString treeID;
-    long automationNodeID;
-    DOMString selector;
-  };
-
-  // Arguments for the enableTab function.
-  dictionary EnableTabParams {
-    long? tabID;
-  };
-
-  // Arguments for the getImageData action.
-  dictionary GetImageDataParams {
-    long maxWidth;
-    long maxHeight;
-  };
-
-  // Arguments for the hitTest action.
-  dictionary HitTestParams {
-    long x;
-    long y;
-    DOMString eventToFire;
-  };
-
-  // Arguments for getTextLocation action.
-  dictionary GetTextLocationDataParams {
-    long startIndex;
-    long endIndex;
-  };
-
-  // Returns the accessibility tree id of the web contents who's accessibility
-  // was enabled using enableTab().
-  callback EnableTabCallback = void(DOMString tree_id);
-
-  // Callback called when enableDesktop() returns. Returns the accessibility
-  // tree id of the desktop tree.
-  callback EnableDesktopCallback = void(DOMString tree_id);
-
-  // Callback called when querySelector() returns.
-  callback QuerySelectorCallback = void(long resultAutomationNodeID);
-
-  interface Functions {
-    // Enable automation of the tab with the given id, or the active tab if no
-    // tab id is given, and retrieves accessibility tree id for use in
-    // future updates.
-    static void enableTab(EnableTabParams args,
-                          EnableTabCallback callback);
-
-    // Enable automation of the frame with the given tree id.
-    static void enableFrame(DOMString tree_id);
-
-    // Enables desktop automation.
-    static void enableDesktop(EnableDesktopCallback callback);
-
-    // Performs an action on an automation node.
-    static void performAction(PerformActionRequiredParams args,
-                              object opt_args);
-
-    // Performs a query selector query.
-    static void querySelector(QuerySelectorRequiredParams args,
-                              QuerySelectorCallback callback);
-  };
-
-  interface Events {
-    // Fired when an accessibility event occurs
-    static void onAccessibilityEvent(AXEventParams update);
-
-    static void onAccessibilityTreeDestroyed(DOMString treeID);
-
-    static void onGetTextLocationResult(AXTextLocationParams params);
-
-    static void onTreeChange(long observerID,
-                             DOMString treeID,
-                             long nodeID,
-                             DOMString changeType);
-
-    static void onChildTreeID(DOMString treeID);
-
-    static void onNodesRemoved(DOMString treeID, long[] nodeIDs);
-
-    static void onAccessibilityTreeSerializationError(DOMString treeID);
-
-    static void onActionResult(DOMString treeID, long requestID, boolean result);
-  };
-};
diff --git a/chromecast/common/extensions_api/cast_extension_messages.h b/chromecast/common/extensions_api/cast_extension_messages.h
index f947d30..fe806b5 100644
--- a/chromecast/common/extensions_api/cast_extension_messages.h
+++ b/chromecast/common/extensions_api/cast_extension_messages.h
@@ -15,7 +15,7 @@
 
 #include "base/strings/string16.h"
 #include "base/values.h"
-#include "chromecast/common/extensions_api/automation_internal.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/common/stack_frame.h"
 #include "ipc/ipc_message_macros.h"
 #include "ui/accessibility/ax_enums.mojom.h"
diff --git a/chromecast/media/cma/backend/android/media_pipeline_backend_android.cc b/chromecast/media/cma/backend/android/media_pipeline_backend_android.cc
index acc0d53..50984b1 100644
--- a/chromecast/media/cma/backend/android/media_pipeline_backend_android.cc
+++ b/chromecast/media/cma/backend/android/media_pipeline_backend_android.cc
@@ -99,7 +99,7 @@
 int64_t MediaPipelineBackendAndroid::GetCurrentPts() {
   if (audio_decoder_) {
     int64_t pts = audio_decoder_->current_pts();
-    LOG(INFO) << __func__ << ": pts=" << pts;
+    DVLOG(2) << __func__ << ": pts=" << pts;
     return pts;
   }
   LOG(INFO) << __func__ << ": pts=<invalid>";
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
index 884d25d2..01f4b82 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -246,6 +246,8 @@
         base::BindOnce(&MediaPipelineImpl::UpdateMediaTime, weak_this_));
   }
 
+  waiting_for_first_have_enough_data_ = true;
+
   // Setup the audio and video pipeline for the new timeline.
   if (audio_pipeline_) {
     scoped_refptr<BufferingState> buffering_state;
@@ -384,10 +386,18 @@
   DCHECK(buffering_controller_);
   DCHECK_EQ(is_buffering, buffering_controller_->IsBuffering());
 
-  if (!client_.buffering_state_cb.is_null()) {
+  if (waiting_for_first_have_enough_data_) {
+    waiting_for_first_have_enough_data_ = is_buffering;
+  }
+
+  if (!waiting_for_first_have_enough_data_ && client_.buffering_state_cb) {
     ::media::BufferingState state = is_buffering
                                         ? ::media::BUFFERING_HAVE_NOTHING
                                         : ::media::BUFFERING_HAVE_ENOUGH;
+    // Reports buffering state to WMPI. WMPI will change HTMLMediaElement ready
+    // state:
+    // HAVE_NOTHING -> HAVE_CURRENT_DATA
+    // HAVE_ENOUGH -> HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA
     client_.buffering_state_cb.Run(state);
   }
 
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h
index 2ab720f..53b1f324 100644
--- a/chromecast/media/cma/pipeline/media_pipeline_impl.h
+++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -123,6 +123,8 @@
   base::TimeTicks playback_stalled_time_;
   bool playback_stalled_notification_sent_;
 
+  bool waiting_for_first_have_enough_data_ = true;
+
   base::WeakPtr<MediaPipelineImpl> weak_this_;
   base::WeakPtrFactory<MediaPipelineImpl> weak_factory_;
 
diff --git a/chromecast/media/service/cast_renderer.cc b/chromecast/media/service/cast_renderer.cc
index dcd6a66..df3ce5af 100644
--- a/chromecast/media/service/cast_renderer.cc
+++ b/chromecast/media/service/cast_renderer.cc
@@ -388,11 +388,7 @@
 
 void CastRenderer::OnBufferingStateChange(::media::BufferingState state) {
   DCHECK(task_runner_->BelongsToCurrentThread());
-  // TODO(alokp): WebMediaPlayerImpl currently only handles HAVE_ENOUGH.
-  // See WebMediaPlayerImpl::OnPipelineBufferingStateChanged,
-  // http://crbug.com/144683.
-  if (state == ::media::BUFFERING_HAVE_ENOUGH)
-    client_->OnBufferingStateChange(state);
+  client_->OnBufferingStateChange(state);
 }
 
 void CastRenderer::OnWaiting(::media::WaitingReason reason) {
diff --git a/chromecast/renderer/BUILD.gn b/chromecast/renderer/BUILD.gn
index ba2c942..676efb3 100644
--- a/chromecast/renderer/BUILD.gn
+++ b/chromecast/renderer/BUILD.gn
@@ -99,6 +99,7 @@
       "//chromecast/renderer:extensions_resources",
       "//components/version_info:version_info",
       "//extensions/common",
+      "//extensions/common/api",
       "//extensions/renderer",
       "//gin:gin",
     ]
diff --git a/chromecast/renderer/extensions/automation_ax_tree_wrapper.h b/chromecast/renderer/extensions/automation_ax_tree_wrapper.h
index f84a2fe..faefb07 100644
--- a/chromecast/renderer/extensions/automation_ax_tree_wrapper.h
+++ b/chromecast/renderer/extensions/automation_ax_tree_wrapper.h
@@ -5,6 +5,7 @@
 #ifndef CHROMECAST_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
 #define CHROMECAST_RENDERER_EXTENSIONS_AUTOMATION_AX_TREE_WRAPPER_H_
 
+#include "extensions/common/api/automation.h"
 #include "ui/accessibility/ax_event_generator.h"
 #include "ui/accessibility/ax_tree.h"
 
@@ -55,7 +56,8 @@
   // Given an event, return true if the event is handled by
   // AXEventGenerator, and false if it's not. Temporary, this will be
   // removed with the AXEventGenerator refactoring is complete.
-  bool IsEventTypeHandledByAXEventGenerator(api::automation::EventType) const;
+  bool IsEventTypeHandledByAXEventGenerator(
+      extensions::api::automation::EventType) const;
 
   ui::AXTreeID tree_id_;
   ui::AXTree tree_;
diff --git a/chromecast/renderer/extensions/automation_internal_custom_bindings.h b/chromecast/renderer/extensions/automation_internal_custom_bindings.h
index 9c87780..da86d90 100644
--- a/chromecast/renderer/extensions/automation_internal_custom_bindings.h
+++ b/chromecast/renderer/extensions/automation_internal_custom_bindings.h
@@ -10,8 +10,8 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "chromecast/common/extensions_api/automation.h"
 #include "chromecast/renderer/extensions/automation_ax_tree_wrapper.h"
+#include "extensions/common/api/automation.h"
 #include "extensions/renderer/object_backed_native_handler.h"
 #include "ipc/ipc_message.h"
 #include "ui/accessibility/ax_tree.h"
diff --git a/chromeos/dbus/session_manager/fake_session_manager_client.h b/chromeos/dbus/session_manager/fake_session_manager_client.h
index 62028a40..780c256 100644
--- a/chromeos/dbus/session_manager/fake_session_manager_client.h
+++ b/chromeos/dbus/session_manager/fake_session_manager_client.h
@@ -240,6 +240,10 @@
 
   bool session_stopped() const { return session_stopped_; }
 
+  const SessionManagerClient::ActiveSessionsMap& user_sessions() const {
+    return user_sessions_;
+  }
+
  private:
   bool supports_restart_to_apply_user_flags_ = false;
 
diff --git a/chromeos/printing/printer_translator.cc b/chromeos/printing/printer_translator.cc
index 33a7706..d519b7cc 100644
--- a/chromeos/printing/printer_translator.cc
+++ b/chromeos/printing/printer_translator.cc
@@ -31,6 +31,7 @@
 const char kUri[] = "uri";
 const char kUUID[] = "uuid";
 const char kPpdResource[] = "ppd_resource";
+const char kAutoconf[] = "autoconf";
 const char kGuid[] = "guid";
 
 // Returns true if the uri was retrieved, is valid, and was set on |printer|.
@@ -148,13 +149,27 @@
   printer->set_source(Printer::SRC_POLICY);
 
   const DictionaryValue* ppd;
-  std::string make_and_model;
-  if (pref.GetDictionary(kPpdResource, &ppd) &&
-      ppd->GetString(kEffectiveModel, &make_and_model)) {
-    printer->mutable_ppd_reference()->effective_make_and_model = make_and_model;
-  } else {
-    // Make and model is mandatory
-    LOG(WARNING) << "Missing model information for policy printer.";
+  if (pref.GetDictionary(kPpdResource, &ppd)) {
+    Printer::PpdReference* ppd_reference = printer->mutable_ppd_reference();
+    std::string make_and_model;
+    if (ppd->GetString(kEffectiveModel, &make_and_model))
+      ppd_reference->effective_make_and_model = make_and_model;
+    bool autoconf;
+    if (ppd->GetBoolean(kAutoconf, &autoconf))
+      ppd_reference->autoconf = autoconf;
+  }
+  if (!printer->ppd_reference().autoconf &&
+      printer->ppd_reference().effective_make_and_model.empty()) {
+    // Either autoconf flag or make and model is mandatory.
+    LOG(WARNING)
+        << "Missing autoconf flag and model information for policy printer.";
+    return nullptr;
+  }
+  if (printer->ppd_reference().autoconf &&
+      !printer->ppd_reference().effective_make_and_model.empty()) {
+    // PPD reference can't contain both autoconf and make and model.
+    LOG(WARNING) << "Autoconf flag is set together with model information for "
+                    "policy printer.";
     return nullptr;
   }
 
diff --git a/chromeos/printing/printer_translator_unittest.cc b/chromeos/printing/printer_translator_unittest.cc
index 85c3583..bb97e26 100644
--- a/chromeos/printing/printer_translator_unittest.cc
+++ b/chromeos/printing/printer_translator_unittest.cc
@@ -129,6 +129,20 @@
   EXPECT_FALSE(printer);
 }
 
+// The test verifies that setting both true autoconf flag and non-empty
+// effective_model properties is not considered as the valid policy.
+TEST(PrinterTranslatorTest, AutoconfAndMakeModelSet) {
+  base::DictionaryValue preference;
+  preference.SetString("id", kHash);
+  preference.SetString("display_name", kName);
+  preference.SetString("uri", kUri);
+  preference.SetString("ppd_resource.effective_model", kEffectiveMakeAndModel);
+  preference.SetBoolean("ppd_resource.autoconf", true);
+
+  std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
+  EXPECT_FALSE(printer);
+}
+
 TEST(PrinterTranslatorTest, InvalidUriFails) {
   base::DictionaryValue preference;
   preference.SetString("id", kHash);
@@ -150,7 +164,11 @@
   preference.SetString("ppd_resource.effective_model", kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
-  EXPECT_TRUE(printer);
+  ASSERT_TRUE(printer);
+
+  EXPECT_EQ(kEffectiveMakeAndModel,
+            printer->ppd_reference().effective_make_and_model);
+  EXPECT_EQ(false, printer->ppd_reference().autoconf);
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinter) {
@@ -163,6 +181,7 @@
   preference.SetString("uri", kUri);
   preference.SetString("uuid", kUUID);
 
+  preference.SetBoolean("ppd_resource.autoconf", false);
   preference.SetString("ppd_resource.effective_model", kEffectiveMakeAndModel);
 
   std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
@@ -179,6 +198,25 @@
 
   EXPECT_EQ(kEffectiveMakeAndModel,
             printer->ppd_reference().effective_make_and_model);
+  EXPECT_EQ(false, printer->ppd_reference().autoconf);
+}
+
+TEST(PrinterTranslatorTest, RecommendedPrinterToPrinterAutoconf) {
+  base::DictionaryValue preference;
+  preference.SetString("id", kHash);
+  preference.SetString("display_name", kName);
+  preference.SetString("uri", kUri);
+
+  preference.SetBoolean("ppd_resource.autoconf", true);
+
+  std::unique_ptr<Printer> printer = RecommendedPrinterToPrinter(preference);
+  EXPECT_TRUE(printer);
+
+  EXPECT_EQ(kHash, printer->id());
+  EXPECT_EQ(kName, printer->display_name());
+  EXPECT_EQ(kUri, printer->uri());
+
+  EXPECT_EQ(true, printer->ppd_reference().autoconf);
 }
 
 TEST(PrinterTranslatorTest, RecommendedPrinterToPrinterBlankManufacturer) {
diff --git a/chromeos/services/secure_channel/ble_weave_client_connection_unittest.cc b/chromeos/services/secure_channel/ble_weave_client_connection_unittest.cc
index 018a88e..d7a3516 100644
--- a/chromeos/services/secure_channel/ble_weave_client_connection_unittest.cc
+++ b/chromeos/services/secure_channel/ble_weave_client_connection_unittest.cc
@@ -35,6 +35,7 @@
 
 using testing::_;
 using testing::AtLeast;
+using testing::DoAll;
 using testing::NiceMock;
 using testing::Return;
 using testing::SaveArg;
@@ -470,7 +471,7 @@
   void CharacteristicsFound(
       TestBluetoothLowEnergyWeaveClientConnection* connection) {
     EXPECT_CALL(*rx_characteristic_, StartNotifySession_(_, _))
-        .WillOnce(DoAll(SaveArg<0>(&notify_session_success_callback_),
+        .WillOnce(DoAll(MoveArg<0>(&notify_session_success_callback_),
                         MoveArg<1>(&notify_session_error_callback_)));
     EXPECT_FALSE(characteristics_finder_error_callback_.is_null());
     ASSERT_FALSE(characteristics_finder_success_callback_.is_null());
@@ -501,7 +502,7 @@
         new NiceMock<device::MockBluetoothGattNotifySession>(
             tx_characteristic_->GetWeakPtr()));
 
-    notify_session_success_callback_.Run(std::move(notify_session));
+    std::move(notify_session_success_callback_).Run(std::move(notify_session));
     task_runner_->RunUntilIdle();
 
     VerifyGattNotifySessionResult(true);
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index cccda375..dd1a57f 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -325,7 +325,7 @@
     "//components/history/core/browser",
     "//components/infobars/core",
     "//components/keyed_service/core",
-    "//components/leveldb_proto:leveldb_proto",
+    "//components/leveldb_proto",
     "//components/os_crypt",
     "//components/pref_registry",
     "//components/prefs",
@@ -440,7 +440,8 @@
     "//base/test:test_support",
     "//components/autofill/core/browser",
     "//components/autofill/core/common",
-    "//components/leveldb_proto:leveldb_proto",
+    "//components/keyed_service/core:test_support",
+    "//components/leveldb_proto",
     "//components/os_crypt",
     "//components/os_crypt:test_support",
     "//components/pref_registry",
@@ -596,6 +597,8 @@
     "//base",
     "//base/test:test_support",
     "//components/autofill/core/common",
+    "//components/keyed_service/core:test_support",
+    "//components/leveldb_proto",
     "//components/os_crypt",
     "//components/os_crypt:test_support",
     "//components/prefs:test_support",
diff --git a/components/autofill/core/browser/payments/legacy_strike_database.cc b/components/autofill/core/browser/payments/legacy_strike_database.cc
index 9baf216..5868f87 100644
--- a/components/autofill/core/browser/payments/legacy_strike_database.cc
+++ b/components/autofill/core/browser/payments/legacy_strike_database.cc
@@ -18,20 +18,26 @@
 namespace autofill {
 
 namespace {
-const char kLegacyDatabaseClientName[] = "StrikeService";
 const char kLegacyDatabaseKeyDeliminator[] = "__";
 const char kKeyPrefixForCreditCardSave[] = "creditCardSave";
 }  // namespace
 
-LegacyStrikeDatabase::LegacyStrikeDatabase(const base::FilePath& database_dir)
-    : db_(leveldb_proto::ProtoDatabaseProvider::CreateUniqueDB<StrikeData>(
-          base::CreateSequencedTaskRunnerWithTraits(
-              {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
-               base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}))),
-      weak_ptr_factory_(this) {
-  db_->Init(kLegacyDatabaseClientName, database_dir,
-            leveldb_proto::CreateSimpleOptions(),
-            base::BindRepeating(&LegacyStrikeDatabase::OnDatabaseInit,
+LegacyStrikeDatabase::LegacyStrikeDatabase(
+    leveldb_proto::ProtoDatabaseProvider* db_provider,
+    base::FilePath profile_path)
+    : weak_ptr_factory_(this) {
+  auto strike_database_path =
+      profile_path.Append(FILE_PATH_LITERAL("AutofillStrikeDatabase"));
+
+  auto database_task_runner = base::CreateSequencedTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+
+  db_ = db_provider->GetDB<StrikeData>(
+      leveldb_proto::ProtoDbType::STRIKE_DATABASE, strike_database_path,
+      database_task_runner);
+
+  db_->Init(base::BindRepeating(&LegacyStrikeDatabase::OnDatabaseInit,
                                 weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -83,7 +89,8 @@
 LegacyStrikeDatabase::LegacyStrikeDatabase()
     : db_(nullptr), weak_ptr_factory_(this) {}
 
-void LegacyStrikeDatabase::OnDatabaseInit(bool success) {}
+void LegacyStrikeDatabase::OnDatabaseInit(
+    leveldb_proto::Enums::InitStatus status) {}
 
 void LegacyStrikeDatabase::GetStrikeData(const std::string key,
                                          const GetValueCallback& callback) {
diff --git a/components/autofill/core/browser/payments/legacy_strike_database.h b/components/autofill/core/browser/payments/legacy_strike_database.h
index 38e7c29f4..4f0f7d2 100644
--- a/components/autofill/core/browser/payments/legacy_strike_database.h
+++ b/components/autofill/core/browser/payments/legacy_strike_database.h
@@ -12,7 +12,7 @@
 #include "base/callback_forward.h"
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 
 namespace autofill {
 class StrikeData;
@@ -51,7 +51,9 @@
 
   using StrikeDataProto = leveldb_proto::ProtoDatabase<StrikeData>;
 
-  explicit LegacyStrikeDatabase(const base::FilePath& database_dir);
+  explicit LegacyStrikeDatabase(
+      leveldb_proto::ProtoDatabaseProvider* db_provider,
+      base::FilePath profile_path);
   ~LegacyStrikeDatabase() override;
 
   // Passes the number of strikes for |key| to |outer_callback|. In the case
@@ -95,7 +97,7 @@
   friend class LegacyStrikeDatabaseTest;
   friend class LegacyStrikeDatabaseTester;
 
-  void OnDatabaseInit(bool success);
+  void OnDatabaseInit(leveldb_proto::Enums::InitStatus status);
 
   // Passes success status and StrikeData entry for |key| to |inner_callback|.
   void GetStrikeData(const std::string key,
diff --git a/components/autofill/core/browser/payments/legacy_strike_database_unittest.cc b/components/autofill/core/browser/payments/legacy_strike_database_unittest.cc
index cbcd36e..c23e0c87 100644
--- a/components/autofill/core/browser/payments/legacy_strike_database_unittest.cc
+++ b/components/autofill/core/browser/payments/legacy_strike_database_unittest.cc
@@ -14,6 +14,9 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/autofill/core/browser/proto/strike_data.pb.h"
+#include "components/keyed_service/core/test_simple_factory_key.h"
+#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill {
@@ -24,8 +27,9 @@
 // added for easier test setup.
 class TestLegacyStrikeDatabase : public LegacyStrikeDatabase {
  public:
-  TestLegacyStrikeDatabase(const base::FilePath& database_dir)
-      : LegacyStrikeDatabase(database_dir) {}
+  TestLegacyStrikeDatabase(leveldb_proto::ProtoDatabaseProvider* db_provider,
+                           base::FilePath profile_path)
+      : LegacyStrikeDatabase(db_provider, profile_path) {}
 
   void AddEntries(
       std::vector<std::pair<std::string, StrikeData>> entries_to_add,
@@ -51,12 +55,22 @@
 // ProtoDatabase.
 class LegacyStrikeDatabaseTest : public ::testing::Test {
  public:
-  LegacyStrikeDatabaseTest() : legacy_strike_database_(InitFilePath()) {}
+  LegacyStrikeDatabaseTest() {}
+
+  void SetUp() override {
+    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+        temp_dir_.GetPath());
+
+    legacy_strike_database_ = std::make_unique<TestLegacyStrikeDatabase>(
+        db_provider_.get(), temp_dir_.GetPath());
+  }
 
   void AddEntries(
       std::vector<std::pair<std::string, StrikeData>> entries_to_add) {
     base::RunLoop run_loop;
-    legacy_strike_database_.AddEntries(
+    legacy_strike_database_->AddEntries(
         entries_to_add,
         base::BindRepeating(&LegacyStrikeDatabaseTest::OnAddEntries,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -74,7 +88,7 @@
 
   int GetStrikes(std::string key) {
     base::RunLoop run_loop;
-    legacy_strike_database_.GetStrikes(
+    legacy_strike_database_->GetStrikes(
         key,
         base::BindRepeating(&LegacyStrikeDatabaseTest::OnGetStrikes,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -89,7 +103,7 @@
 
   int AddStrike(std::string key) {
     base::RunLoop run_loop;
-    legacy_strike_database_.AddStrike(
+    legacy_strike_database_->AddStrike(
         key,
         base::BindRepeating(&LegacyStrikeDatabaseTest::OnAddStrike,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -104,7 +118,7 @@
 
   void ClearAllStrikesForKey(const std::string key) {
     base::RunLoop run_loop;
-    legacy_strike_database_.ClearAllStrikesForKey(
+    legacy_strike_database_->ClearAllStrikesForKey(
         key,
         base::BindRepeating(&LegacyStrikeDatabaseTest::OnClearAllStrikesForKey,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -118,7 +132,7 @@
 
   void ClearAllStrikes() {
     base::RunLoop run_loop;
-    legacy_strike_database_.ClearAllStrikes(
+    legacy_strike_database_->ClearAllStrikes(
         base::BindRepeating(&LegacyStrikeDatabaseTest::OnClearAllStrikesForKey,
                             base::Unretained(this), run_loop.QuitClosure()));
     run_loop.Run();
@@ -127,15 +141,17 @@
  protected:
   base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  TestLegacyStrikeDatabase legacy_strike_database_;
+  std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> db_provider_;
+  std::unique_ptr<TestLegacyStrikeDatabase> legacy_strike_database_;
+  base::ScopedTempDir temp_dir_;
 
  private:
-  static const base::FilePath InitFilePath() {
-    base::ScopedTempDir temp_dir_;
+  leveldb_proto::ProtoDatabaseProvider* GetDBProvider() {
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
-    const base::FilePath file_path =
-        temp_dir_.GetPath().AppendASCII("LegacyStrikeDatabaseTest");
-    return file_path;
+    db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+        temp_dir_.GetPath());
+
+    return db_provider_.get();
   }
 
   base::HistogramTester histogram_tester_;
@@ -243,12 +259,12 @@
 TEST_F(LegacyStrikeDatabaseTest, GetKeyForCreditCardSave) {
   const std::string last_four = "1234";
   EXPECT_EQ("creditCardSave__1234",
-            legacy_strike_database_.GetKeyForCreditCardSave(last_four));
+            legacy_strike_database_->GetKeyForCreditCardSave(last_four));
 }
 
 TEST_F(LegacyStrikeDatabaseTest, GetPrefixFromKey) {
   const std::string key = "creditCardSave__1234";
-  EXPECT_EQ("creditCardSave", legacy_strike_database_.GetPrefixFromKey(key));
+  EXPECT_EQ("creditCardSave", legacy_strike_database_->GetPrefixFromKey(key));
 }
 
 TEST_F(LegacyStrikeDatabaseTest, CreditCardSaveNthStrikeAddedHistogram) {
@@ -256,11 +272,11 @@
   const std::string last_four2 = "9876";
   const std::string key1 = "NotACreditCard";
   // 1st strike added for |last_four1|.
-  AddStrike(legacy_strike_database_.GetKeyForCreditCardSave(last_four1));
+  AddStrike(legacy_strike_database_->GetKeyForCreditCardSave(last_four1));
   // 2nd strike added for |last_four1|.
-  AddStrike(legacy_strike_database_.GetKeyForCreditCardSave(last_four1));
+  AddStrike(legacy_strike_database_->GetKeyForCreditCardSave(last_four1));
   // 1st strike added for |last_four2|.
-  AddStrike(legacy_strike_database_.GetKeyForCreditCardSave(last_four2));
+  AddStrike(legacy_strike_database_->GetKeyForCreditCardSave(last_four2));
   // Shouldn't be counted in histogram since key doesn't have prefix for credit
   // cards.
   AddStrike(key1);
diff --git a/components/autofill/core/browser/payments/strike_database.cc b/components/autofill/core/browser/payments/strike_database.cc
index 10ff55f..fe806f2 100644
--- a/components/autofill/core/browser/payments/strike_database.cc
+++ b/components/autofill/core/browser/payments/strike_database.cc
@@ -21,20 +21,25 @@
 namespace autofill {
 
 namespace {
-const char kDatabaseClientName[] = "StrikeService";
 const int kMaxInitAttempts = 3;
 }  // namespace
 
-StrikeDatabase::StrikeDatabase(const base::FilePath& database_dir)
-    : db_(leveldb_proto::ProtoDatabaseProvider::CreateUniqueDB<StrikeData>(
-          base::CreateSequencedTaskRunnerWithTraits(
-              {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
-               base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}))),
-      database_dir_(database_dir),
-      weak_ptr_factory_(this) {
-  db_->Init(kDatabaseClientName, database_dir,
-            leveldb_proto::CreateSimpleOptions(),
-            base::BindRepeating(&StrikeDatabase::OnDatabaseInit,
+StrikeDatabase::StrikeDatabase(
+    leveldb_proto::ProtoDatabaseProvider* db_provider,
+    base::FilePath profile_path)
+    : weak_ptr_factory_(this) {
+  auto strike_database_path =
+      profile_path.Append(FILE_PATH_LITERAL("AutofillStrikeDatabase"));
+
+  auto database_task_runner = base::CreateSequencedTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
+
+  db_ = db_provider->GetDB<StrikeData>(
+      leveldb_proto::ProtoDbType::STRIKE_DATABASE, strike_database_path,
+      database_task_runner);
+
+  db_->Init(base::BindRepeating(&StrikeDatabase::OnDatabaseInit,
                                 weak_ptr_factory_.GetWeakPtr()));
 }
 
@@ -87,19 +92,17 @@
 
 StrikeDatabase::StrikeDatabase()
     : db_(nullptr),
-      database_dir_(base::FilePath(nullptr)),
       weak_ptr_factory_(this) {}
 
-void StrikeDatabase::OnDatabaseInit(bool success) {
+void StrikeDatabase::OnDatabaseInit(leveldb_proto::Enums::InitStatus status) {
+  bool success = status == leveldb_proto::Enums::InitStatus::kOK;
   database_initialized_ = success;
   if (!success) {
     base::UmaHistogramCounts100(
         "Autofill.StrikeDatabase.StrikeDatabaseInitFailed", num_init_attempts_);
     if (num_init_attempts_ < kMaxInitAttempts) {
       num_init_attempts_++;
-      db_->Init(kDatabaseClientName, database_dir_,
-                leveldb_proto::CreateSimpleOptions(),
-                base::BindRepeating(&StrikeDatabase::OnDatabaseInit,
+      db_->Init(base::BindRepeating(&StrikeDatabase::OnDatabaseInit,
                                     weak_ptr_factory_.GetWeakPtr()));
     }
     return;
diff --git a/components/autofill/core/browser/payments/strike_database.h b/components/autofill/core/browser/payments/strike_database.h
index 029aebe6..a02161c0 100644
--- a/components/autofill/core/browser/payments/strike_database.h
+++ b/components/autofill/core/browser/payments/strike_database.h
@@ -14,6 +14,7 @@
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 
 namespace autofill {
 
@@ -49,7 +50,8 @@
 
   using StrikeDataProto = leveldb_proto::ProtoDatabase<StrikeData>;
 
-  explicit StrikeDatabase(const base::FilePath& database_dir);
+  StrikeDatabase(leveldb_proto::ProtoDatabaseProvider* db_provider,
+                 base::FilePath profile_path);
   ~StrikeDatabase() override;
 
   // Increases in-memory cache by |strikes_increase| and updates underlying
@@ -86,9 +88,6 @@
   // Cached StrikeDatabase entries.
   std::map<std::string, StrikeData> strike_map_cache_;
 
-  // Directory where the ProtoDatabase is intialized at.
-  const base::FilePath database_dir_;
-
   // Whether or not the ProtoDatabase database has been initialized and entries
   // have been loaded.
   bool database_initialized_ = false;
@@ -109,7 +108,7 @@
   friend class StrikeDatabaseTest;
   friend class StrikeDatabaseTester;
 
-  void OnDatabaseInit(bool success);
+  void OnDatabaseInit(leveldb_proto::Enums::InitStatus status);
 
   void OnDatabaseLoadKeysAndEntries(
       bool success,
diff --git a/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc b/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc
index 971af06..c8edc9a 100644
--- a/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc
+++ b/components/autofill/core/browser/payments/strike_database_integrator_test_strike_database_unittest.cc
@@ -15,29 +15,45 @@
 #include "components/autofill/core/browser/proto/strike_data.pb.h"
 #include "components/autofill/core/browser/test_autofill_clock.h"
 #include "components/autofill/core/common/autofill_clock.h"
+#include "components/keyed_service/core/test_simple_factory_key.h"
+#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill {
 
 class StrikeDatabaseIntegratorTestStrikeDatabaseTest : public ::testing::Test {
  public:
-  StrikeDatabaseIntegratorTestStrikeDatabaseTest()
-      : strike_database_service_(InitFilePath()),
-        strike_database_(&strike_database_service_) {}
+  StrikeDatabaseIntegratorTestStrikeDatabaseTest() {}
+
+  void SetUp() override {
+    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+        temp_dir_.GetPath());
+
+    strike_database_service_ = std::make_unique<StrikeDatabase>(
+        db_provider_.get(), temp_dir_.GetPath());
+    strike_database_ =
+        std::make_unique<StrikeDatabaseIntegratorTestStrikeDatabase>(
+            strike_database_service_.get());
+  }
 
  protected:
   base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  StrikeDatabase strike_database_service_;
-  StrikeDatabaseIntegratorTestStrikeDatabase strike_database_;
+  std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> db_provider_;
+  base::ScopedTempDir temp_dir_;
+  std::unique_ptr<StrikeDatabase> strike_database_service_;
+  std::unique_ptr<StrikeDatabaseIntegratorTestStrikeDatabase> strike_database_;
 
  private:
-  static const base::FilePath InitFilePath() {
-    base::ScopedTempDir temp_dir_;
+  leveldb_proto::ProtoDatabaseProvider* GetDBProvider() {
     EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
-    const base::FilePath file_path =
-        temp_dir_.GetPath().AppendASCII("StrikeDatabaseTest");
-    return file_path;
+    db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+        temp_dir_.GetPath());
+
+    return db_provider_.get();
   }
 
   base::HistogramTester histogram_tester_;
@@ -45,24 +61,24 @@
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        MaxStrikesLimitReachedTest) {
-  EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached());
+  EXPECT_EQ(false, strike_database_->IsMaxStrikesLimitReached());
   // 3 strikes added.
-  strike_database_.AddStrikes(3);
-  EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached());
+  strike_database_->AddStrikes(3);
+  EXPECT_EQ(false, strike_database_->IsMaxStrikesLimitReached());
   // 4 strike added, total strike count is 7.
-  strike_database_.AddStrikes(4);
-  EXPECT_EQ(true, strike_database_.IsMaxStrikesLimitReached());
+  strike_database_->AddStrikes(4);
+  EXPECT_EQ(true, strike_database_->IsMaxStrikesLimitReached());
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        StrikeDatabaseIntegratorTestNthStrikeAddedHistogram) {
   // 2 strikes logged.
-  strike_database_.AddStrikes(2);
-  strike_database_.RemoveStrikes(2);
+  strike_database_->AddStrikes(2);
+  strike_database_->RemoveStrikes(2);
   // 1 strike logged.
-  strike_database_.AddStrike();
+  strike_database_->AddStrike();
   // 2 strikes logged.
-  strike_database_.AddStrike();
+  strike_database_->AddStrike();
   std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples(
       "Autofill.StrikeDatabase.NthStrikeAdded.StrikeDatabaseIntegratorTest");
   // There should be two buckets, for strike counts of 1 and 2.
@@ -75,81 +91,81 @@
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        AddStrikeForZeroAndNonZeroStrikesTest) {
-  EXPECT_EQ(0, strike_database_.GetStrikes());
-  strike_database_.AddStrike();
-  EXPECT_EQ(1, strike_database_.GetStrikes());
-  strike_database_.AddStrikes(2);
-  EXPECT_EQ(3, strike_database_.GetStrikes());
+  EXPECT_EQ(0, strike_database_->GetStrikes());
+  strike_database_->AddStrike();
+  EXPECT_EQ(1, strike_database_->GetStrikes());
+  strike_database_->AddStrikes(2);
+  EXPECT_EQ(3, strike_database_->GetStrikes());
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        ClearStrikesForNonZeroStrikesTest) {
-  strike_database_.AddStrikes(3);
-  EXPECT_EQ(3, strike_database_.GetStrikes());
-  strike_database_.ClearStrikes();
-  EXPECT_EQ(0, strike_database_.GetStrikes());
+  strike_database_->AddStrikes(3);
+  EXPECT_EQ(3, strike_database_->GetStrikes());
+  strike_database_->ClearStrikes();
+  EXPECT_EQ(0, strike_database_->GetStrikes());
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        ClearStrikesForZeroStrikesTest) {
-  strike_database_.ClearStrikes();
-  EXPECT_EQ(0, strike_database_.GetStrikes());
+  strike_database_->ClearStrikes();
+  EXPECT_EQ(0, strike_database_->GetStrikes());
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        RemoveExpiredStrikesTest) {
   autofill::TestAutofillClock test_clock;
   test_clock.SetNow(AutofillClock::Now());
-  strike_database_.AddStrikes(2);
-  EXPECT_EQ(2, strike_database_.GetStrikes());
+  strike_database_->AddStrikes(2);
+  EXPECT_EQ(2, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
   test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_.GetExpiryTimeMicros() + 1));
+      strike_database_->GetExpiryTimeMicros() + 1));
 
   // One strike should be removed.
-  strike_database_.RemoveExpiredStrikes();
-  EXPECT_EQ(1, strike_database_.GetStrikes());
+  strike_database_->RemoveExpiredStrikes();
+  EXPECT_EQ(1, strike_database_->GetStrikes());
 
   // Strike count is past the max limit.
-  strike_database_.AddStrikes(10);
-  EXPECT_EQ(11, strike_database_.GetStrikes());
+  strike_database_->AddStrikes(10);
+  EXPECT_EQ(11, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
   test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_.GetExpiryTimeMicros() + 1));
+      strike_database_->GetExpiryTimeMicros() + 1));
 
   // Strike count should be one less than the max limit.
-  strike_database_.RemoveExpiredStrikes();
-  EXPECT_EQ(5, strike_database_.GetStrikes());
+  strike_database_->RemoveExpiredStrikes();
+  EXPECT_EQ(5, strike_database_->GetStrikes());
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        RemoveExpiredStrikesTestLogsUMA) {
   autofill::TestAutofillClock test_clock;
   test_clock.SetNow(AutofillClock::Now());
-  strike_database_.AddStrikes(2);
-  EXPECT_EQ(2, strike_database_.GetStrikes());
+  strike_database_->AddStrikes(2);
+  EXPECT_EQ(2, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
   test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_.GetExpiryTimeMicros() + 1));
+      strike_database_->GetExpiryTimeMicros() + 1));
 
   // One strike should be removed.
-  strike_database_.RemoveExpiredStrikes();
-  EXPECT_EQ(1, strike_database_.GetStrikes());
+  strike_database_->RemoveExpiredStrikes();
+  EXPECT_EQ(1, strike_database_->GetStrikes());
 
   // Strike count is past the max limit.
-  strike_database_.AddStrikes(10);
-  EXPECT_EQ(11, strike_database_.GetStrikes());
+  strike_database_->AddStrikes(10);
+  EXPECT_EQ(11, strike_database_->GetStrikes());
 
   // Advance clock to past expiry time.
   test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_.GetExpiryTimeMicros() + 1));
+      strike_database_->GetExpiryTimeMicros() + 1));
 
   // Strike count should be one less than the max limit.
-  strike_database_.RemoveExpiredStrikes();
-  EXPECT_EQ(5, strike_database_.GetStrikes());
+  strike_database_->RemoveExpiredStrikes();
+  EXPECT_EQ(5, strike_database_->GetStrikes());
 
   std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples(
       "Autofill.StrikeDatabase.StrikesPresentWhenStrikeExpired."
@@ -170,36 +186,36 @@
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        GetKeyForStrikeDatabaseIntegratorUniqueIdTest) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id = "1234";
   EXPECT_EQ("StrikeDatabaseIntegratorTest__1234",
-            strike_database_.GetKey(unique_id));
+            strike_database_->GetKey(unique_id));
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        MaxStrikesLimitReachedUniqueIdTest) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id = "1234";
-  EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached(unique_id));
+  EXPECT_EQ(false, strike_database_->IsMaxStrikesLimitReached(unique_id));
   // 1 strike added for |unique_id|.
-  strike_database_.AddStrike(unique_id);
-  EXPECT_EQ(false, strike_database_.IsMaxStrikesLimitReached(unique_id));
+  strike_database_->AddStrike(unique_id);
+  EXPECT_EQ(false, strike_database_->IsMaxStrikesLimitReached(unique_id));
   // 6 strikes added for |unique_id|.
-  strike_database_.AddStrikes(6, unique_id);
-  EXPECT_EQ(true, strike_database_.IsMaxStrikesLimitReached(unique_id));
+  strike_database_->AddStrikes(6, unique_id);
+  EXPECT_EQ(true, strike_database_->IsMaxStrikesLimitReached(unique_id));
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        StrikeDatabaseIntegratorUniqueIdTestNthStrikeAddedHistogram) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id_1 = "1234";
   const std::string unique_id_2 = "9876";
   // 1st strike added for |unique_id_1|.
-  strike_database_.AddStrike(unique_id_1);
+  strike_database_->AddStrike(unique_id_1);
   // 2nd strike added for |unique_id_1|.
-  strike_database_.AddStrike(unique_id_1);
+  strike_database_->AddStrike(unique_id_1);
   // 1st strike added for |unique_id_2|.
-  strike_database_.AddStrike(unique_id_2);
+  strike_database_->AddStrike(unique_id_2);
   std::vector<base::Bucket> buckets = GetHistogramTester()->GetAllSamples(
       "Autofill.StrikeDatabase.NthStrikeAdded."
       "StrikeDatabaseIntegratorTest");
@@ -213,79 +229,79 @@
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        StrikeDatabaseIntegratorUniqueIdTestClearAllStrikes) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id_1 = "1234";
   const std::string unique_id_2 = "9876";
   // 1 strike added for |unique_id_1|.
-  strike_database_.AddStrike(unique_id_1);
+  strike_database_->AddStrike(unique_id_1);
   // 3 strikes added for |unique_id_2|.
-  strike_database_.AddStrikes(3, unique_id_2);
-  EXPECT_EQ(1, strike_database_.GetStrikes(unique_id_1));
-  EXPECT_EQ(3, strike_database_.GetStrikes(unique_id_2));
-  strike_database_.ClearAllStrikes();
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_1));
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_2));
+  strike_database_->AddStrikes(3, unique_id_2);
+  EXPECT_EQ(1, strike_database_->GetStrikes(unique_id_1));
+  EXPECT_EQ(3, strike_database_->GetStrikes(unique_id_2));
+  strike_database_->ClearAllStrikes();
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_1));
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_2));
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        AddStrikeForZeroAndNonZeroStrikesUniqueIdTest) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id = "1234";
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id));
-  strike_database_.AddStrike(unique_id);
-  EXPECT_EQ(1, strike_database_.GetStrikes(unique_id));
-  strike_database_.AddStrike(unique_id);
-  EXPECT_EQ(2, strike_database_.GetStrikes(unique_id));
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id));
+  strike_database_->AddStrike(unique_id);
+  EXPECT_EQ(1, strike_database_->GetStrikes(unique_id));
+  strike_database_->AddStrike(unique_id);
+  EXPECT_EQ(2, strike_database_->GetStrikes(unique_id));
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        ClearStrikesForNonZeroStrikesUniqueIdTest) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id = "1234";
-  strike_database_.AddStrike(unique_id);
-  EXPECT_EQ(1, strike_database_.GetStrikes(unique_id));
-  strike_database_.ClearStrikes(unique_id);
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id));
+  strike_database_->AddStrike(unique_id);
+  EXPECT_EQ(1, strike_database_->GetStrikes(unique_id));
+  strike_database_->ClearStrikes(unique_id);
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id));
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        ClearStrikesForZeroStrikesUniqueIdTest) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   const std::string unique_id = "1234";
-  strike_database_.ClearStrikes(unique_id);
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id));
+  strike_database_->ClearStrikes(unique_id);
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id));
 }
 
 TEST_F(StrikeDatabaseIntegratorTestStrikeDatabaseTest,
        RemoveExpiredStrikesUniqueIdTest) {
-  strike_database_.SetUniqueIdsRequired(true);
+  strike_database_->SetUniqueIdsRequired(true);
   autofill::TestAutofillClock test_clock;
   test_clock.SetNow(AutofillClock::Now());
   const std::string unique_id_1 = "1234";
   const std::string unique_id_2 = "9876";
-  strike_database_.AddStrike(unique_id_1);
+  strike_database_->AddStrike(unique_id_1);
 
   // Advance clock to past the entry for |unique_id_1|'s expiry time.
   test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_.GetExpiryTimeMicros() + 1));
+      strike_database_->GetExpiryTimeMicros() + 1));
 
-  strike_database_.AddStrike(unique_id_2);
-  strike_database_.RemoveExpiredStrikes();
+  strike_database_->AddStrike(unique_id_2);
+  strike_database_->RemoveExpiredStrikes();
 
   // |unique_id_1|'s entry should have its most recent strike expire, but
   // |unique_id_2|'s should not.
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_1));
-  EXPECT_EQ(1, strike_database_.GetStrikes(unique_id_2));
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_1));
+  EXPECT_EQ(1, strike_database_->GetStrikes(unique_id_2));
 
   // Advance clock to past |unique_id_2|'s expiry time.
   test_clock.Advance(base::TimeDelta::FromMicroseconds(
-      strike_database_.GetExpiryTimeMicros() + 1));
+      strike_database_->GetExpiryTimeMicros() + 1));
 
-  strike_database_.RemoveExpiredStrikes();
+  strike_database_->RemoveExpiredStrikes();
 
   // |unique_id_1| and |unique_id_2| should have no more unexpired strikes.
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_1));
-  EXPECT_EQ(0, strike_database_.GetStrikes(unique_id_2));
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_1));
+  EXPECT_EQ(0, strike_database_->GetStrikes(unique_id_2));
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/payments/strike_database_unittest.cc b/components/autofill/core/browser/payments/strike_database_unittest.cc
index 508a1bc7..8cbc34b 100644
--- a/components/autofill/core/browser/payments/strike_database_unittest.cc
+++ b/components/autofill/core/browser/payments/strike_database_unittest.cc
@@ -14,6 +14,9 @@
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/autofill/core/browser/proto/strike_data.pb.h"
+#include "components/keyed_service/core/test_simple_factory_key.h"
+#include "components/leveldb_proto/public/proto_database.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace autofill {
@@ -25,8 +28,9 @@
 // one in test_strike_database.h.  This one is purely for this unit test class.
 class TestStrikeDatabase : public StrikeDatabase {
  public:
-  TestStrikeDatabase(const base::FilePath& database_dir)
-      : StrikeDatabase(database_dir) {
+  TestStrikeDatabase(leveldb_proto::ProtoDatabaseProvider* db_provider,
+                     base::FilePath profile_path)
+      : StrikeDatabase(db_provider, profile_path) {
     database_initialized_ = true;
   }
 
@@ -54,12 +58,22 @@
 // ProtoDatabase.
 class StrikeDatabaseTest : public ::testing::Test {
  public:
-  StrikeDatabaseTest() : strike_database_(InitFilePath()) {}
+  StrikeDatabaseTest() {}
+
+  void SetUp() override {
+    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    db_provider_ = std::make_unique<leveldb_proto::ProtoDatabaseProvider>(
+        temp_dir_.GetPath());
+
+    strike_database_ = std::make_unique<TestStrikeDatabase>(
+        db_provider_.get(), temp_dir_.GetPath());
+  }
 
   void AddProtoEntries(
       std::vector<std::pair<std::string, StrikeData>> entries_to_add) {
     base::RunLoop run_loop;
-    strike_database_.AddProtoEntries(
+    strike_database_->AddProtoEntries(
         entries_to_add,
         base::BindRepeating(&StrikeDatabaseTest::OnAddProtoEntries,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -79,7 +93,7 @@
 
   int GetProtoStrikes(std::string key) {
     base::RunLoop run_loop;
-    strike_database_.GetProtoStrikes(
+    strike_database_->GetProtoStrikes(
         key,
         base::BindRepeating(&StrikeDatabaseTest::OnGetProtoStrikes,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -94,7 +108,7 @@
 
   void ClearAllProtoStrikesForKey(const std::string key) {
     base::RunLoop run_loop;
-    strike_database_.ClearAllProtoStrikesForKey(
+    strike_database_->ClearAllProtoStrikesForKey(
         key,
         base::BindRepeating(&StrikeDatabaseTest::OnClearAllProtoStrikesForKey,
                             base::Unretained(this), run_loop.QuitClosure()));
@@ -108,7 +122,7 @@
 
   void ClearAllProtoStrikes() {
     base::RunLoop run_loop;
-    strike_database_.ClearAllProtoStrikes(
+    strike_database_->ClearAllProtoStrikes(
         base::BindRepeating(&StrikeDatabaseTest::OnClearAllProtoStrikesForKey,
                             base::Unretained(this), run_loop.QuitClosure()));
     run_loop.Run();
@@ -117,17 +131,11 @@
  protected:
   base::HistogramTester* GetHistogramTester() { return &histogram_tester_; }
   base::test::ScopedTaskEnvironment scoped_task_environment_;
-  TestStrikeDatabase strike_database_;
+  std::unique_ptr<leveldb_proto::ProtoDatabaseProvider> db_provider_;
+  std::unique_ptr<TestStrikeDatabase> strike_database_;
+  base::ScopedTempDir temp_dir_;
 
  private:
-  static const base::FilePath InitFilePath() {
-    base::ScopedTempDir temp_dir_;
-    EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
-    const base::FilePath file_path =
-        temp_dir_.GetPath().AppendASCII("StrikeDatabaseTest");
-    return file_path;
-  }
-
   base::HistogramTester histogram_tester_;
   int num_strikes_;
   std::unique_ptr<StrikeData> strike_data_;
diff --git a/components/autofill/core/browser/ui/payments/save_card_bubble_controller.h b/components/autofill/core/browser/ui/payments/save_card_bubble_controller.h
index 04ba8d4..6e9afd0 100644
--- a/components/autofill/core/browser/ui/payments/save_card_bubble_controller.h
+++ b/components/autofill/core/browser/ui/payments/save_card_bubble_controller.h
@@ -61,8 +61,8 @@
   // Returns whether or not a sign in / sync promo needs to be shown.
   virtual bool ShouldShowSignInPromo() const = 0;
 
-  // Returns true iff the card saved animation can be shown.
-  virtual bool CanAnimate() const = 0;
+  // Returns true iff the card saved animation should be shown.
+  virtual bool ShouldShowCardSavedAnimation() const = 0;
 
   // Interaction.
   // OnSyncPromoAccepted is called when the Dice Sign-in promo is clicked.
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 4963e046..2d48f06 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -20,7 +20,6 @@
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
 #include "components/browser_sync/browser_sync_client.h"
-#include "components/history/core/browser/sync/history_delete_directives_data_type_controller.h"
 #include "components/history/core/browser/sync/history_delete_directives_model_type_controller.h"
 #include "components/history/core/browser/sync/typed_url_model_type_controller.h"
 #include "components/password_manager/core/browser/password_store.h"
@@ -31,7 +30,6 @@
 #include "components/send_tab_to_self/send_tab_to_self_sync_service.h"
 #include "components/sync/base/report_unrecoverable_error.h"
 #include "components/sync/device_info/device_info_sync_service.h"
-#include "components/sync/driver/async_directory_type_controller.h"
 #include "components/sync/driver/data_type_manager_impl.h"
 #include "components/sync/driver/glue/sync_engine_impl.h"
 #include "components/sync/driver/model_type_controller.h"
@@ -55,7 +53,6 @@
 using sync_bookmarks::BookmarkChangeProcessor;
 using sync_bookmarks::BookmarkDataTypeController;
 using sync_bookmarks::BookmarkModelAssociator;
-using syncer::AsyncDirectoryTypeController;
 using syncer::DataTypeController;
 using syncer::DataTypeManager;
 using syncer::DataTypeManagerImpl;
@@ -264,18 +261,10 @@
 
     // Delete directive sync is enabled by default.
     if (!disabled_types.Has(syncer::HISTORY_DELETE_DIRECTIVES)) {
-      if (base::FeatureList::IsEnabled(
-              switches::kSyncPseudoUSSHistoryDeleteDirectives)) {
-        controllers.push_back(
-            std::make_unique<HistoryDeleteDirectivesModelTypeController>(
-                dump_stack, sync_service,
-                sync_client_->GetModelTypeStoreService(), sync_client_));
-
-      } else {
-        controllers.push_back(
-            std::make_unique<HistoryDeleteDirectivesDataTypeController>(
-                dump_stack, sync_service, sync_client_));
-      }
+      controllers.push_back(
+          std::make_unique<HistoryDeleteDirectivesModelTypeController>(
+              dump_stack, sync_service,
+              sync_client_->GetModelTypeStoreService(), sync_client_));
     }
 
     // Session sync is enabled by default.  This is disabled if history is
@@ -300,31 +289,22 @@
     // Favicon sync is enabled by default. Register unless explicitly disabled.
     if (!disabled_types.Has(syncer::FAVICON_IMAGES) &&
         !disabled_types.Has(syncer::FAVICON_TRACKING)) {
-      if (base::FeatureList::IsEnabled(switches::kSyncPseudoUSSFavicons)) {
-        controllers.push_back(
-            std::make_unique<SyncableServiceBasedModelTypeController>(
-                syncer::FAVICON_IMAGES,
-                sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
-                base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
-                               base::Unretained(sync_client_),
-                               syncer::FAVICON_IMAGES),
-                dump_stack));
-        controllers.push_back(
-            std::make_unique<SyncableServiceBasedModelTypeController>(
-                syncer::FAVICON_TRACKING,
-                sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
-                base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
-                               base::Unretained(sync_client_),
-                               syncer::FAVICON_TRACKING),
-                dump_stack));
-      } else {
-        controllers.push_back(std::make_unique<AsyncDirectoryTypeController>(
-            syncer::FAVICON_IMAGES, base::RepeatingClosure(), sync_service,
-            sync_client_, syncer::GROUP_UI, ui_thread_));
-        controllers.push_back(std::make_unique<AsyncDirectoryTypeController>(
-            syncer::FAVICON_TRACKING, base::RepeatingClosure(), sync_service,
-            sync_client_, syncer::GROUP_UI, ui_thread_));
-      }
+      controllers.push_back(
+          std::make_unique<SyncableServiceBasedModelTypeController>(
+              syncer::FAVICON_IMAGES,
+              sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
+              base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
+                             base::Unretained(sync_client_),
+                             syncer::FAVICON_IMAGES),
+              dump_stack));
+      controllers.push_back(
+          std::make_unique<SyncableServiceBasedModelTypeController>(
+              syncer::FAVICON_TRACKING,
+              sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
+              base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
+                             base::Unretained(sync_client_),
+                             syncer::FAVICON_TRACKING),
+              dump_stack));
     }
   }
 
@@ -347,8 +327,7 @@
     if (override_prefs_controller_to_uss_for_test_) {
       controllers.push_back(CreateModelTypeControllerForModelRunningOnUIThread(
           syncer::PREFERENCES));
-    } else if (base::FeatureList::IsEnabled(
-                   switches::kSyncPseudoUSSPreferences)) {
+    } else {
       controllers.push_back(
           std::make_unique<SyncableServiceBasedModelTypeController>(
               syncer::PREFERENCES,
@@ -357,29 +336,18 @@
                              base::Unretained(sync_client_),
                              syncer::PREFERENCES),
               dump_stack));
-    } else {
-      controllers.push_back(std::make_unique<AsyncDirectoryTypeController>(
-          syncer::PREFERENCES, dump_stack, sync_service, sync_client_,
-          syncer::GROUP_UI, ui_thread_));
     }
   }
 
   if (!disabled_types.Has(syncer::PRIORITY_PREFERENCES)) {
-    if (base::FeatureList::IsEnabled(
-            switches::kSyncPseudoUSSPriorityPreferences)) {
-      controllers.push_back(
-          std::make_unique<SyncableServiceBasedModelTypeController>(
-              syncer::PRIORITY_PREFERENCES,
-              sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
-              base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
-                             base::Unretained(sync_client_),
-                             syncer::PRIORITY_PREFERENCES),
-              dump_stack));
-    } else {
-      controllers.push_back(std::make_unique<AsyncDirectoryTypeController>(
-          syncer::PRIORITY_PREFERENCES, dump_stack, sync_service, sync_client_,
-          syncer::GROUP_UI, ui_thread_));
-    }
+    controllers.push_back(
+        std::make_unique<SyncableServiceBasedModelTypeController>(
+            syncer::PRIORITY_PREFERENCES,
+            sync_client_->GetModelTypeStoreService()->GetStoreFactory(),
+            base::BindOnce(&syncer::SyncClient::GetSyncableServiceForType,
+                           base::Unretained(sync_client_),
+                           syncer::PRIORITY_PREFERENCES),
+            dump_stack));
   }
 
 #if defined(OS_CHROMEOS)
diff --git a/components/cast_channel/cast_message_handler.cc b/components/cast_channel/cast_message_handler.cc
index 6e1f85e..23838b4 100644
--- a/components/cast_channel/cast_message_handler.cc
+++ b/components/cast_channel/cast_message_handler.cc
@@ -250,16 +250,16 @@
   return request_id;
 }
 
-Result CastMessageHandler::SendSetVolumeRequest(int channel_id,
-                                                const base::Value& body,
-                                                const std::string& source_id,
-                                                ResultCallback callback) {
+void CastMessageHandler::SendSetVolumeRequest(int channel_id,
+                                              const base::Value& body,
+                                              const std::string& source_id,
+                                              ResultCallback callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   CastSocket* socket = socket_service_->GetSocket(channel_id);
   if (!socket) {
     DVLOG(2) << __func__ << ": socket not found: " << channel_id;
-    return Result::kFailed;
+    std::move(callback).Run(Result::kFailed);
   }
 
   auto* requests = GetOrCreatePendingRequests(channel_id);
@@ -268,7 +268,6 @@
   requests->AddVolumeRequest(std::make_unique<SetVolumeRequest>(
       request_id, std::move(callback), clock_));
   SendCastMessage(socket, CreateSetVolumeRequest(body, request_id, source_id));
-  return Result::kOk;
 }
 
 void CastMessageHandler::AddObserver(Observer* observer) {
diff --git a/components/cast_channel/cast_message_handler.h b/components/cast_channel/cast_message_handler.h
index 9023302..8c4407b 100644
--- a/components/cast_channel/cast_message_handler.h
+++ b/components/cast_channel/cast_message_handler.h
@@ -206,10 +206,10 @@
   // Sends a set system volume command |body|. |callback| will be invoked
   // with the result of the operation. It is invalid to call this with
   // a message body that is not a volume request.
-  virtual Result SendSetVolumeRequest(int channel_id,
-                                      const base::Value& body,
-                                      const std::string& source_id,
-                                      ResultCallback callback);
+  virtual void SendSetVolumeRequest(int channel_id,
+                                    const base::Value& body,
+                                    const std::string& source_id,
+                                    ResultCallback callback);
 
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
diff --git a/components/cast_channel/cast_message_handler_unittest.cc b/components/cast_channel/cast_message_handler_unittest.cc
index 908f75e..2139463 100644
--- a/components/cast_channel/cast_message_handler_unittest.cc
+++ b/components/cast_channel/cast_message_handler_unittest.cc
@@ -136,13 +136,11 @@
     for (int i = 0; i < 2; i++) {
       handler_.RequestAppAvailability(&cast_socket_, "theAppId",
                                       get_app_availability_callback_.Get());
-      EXPECT_EQ(
-          Result::kOk,
-          handler_.SendSetVolumeRequest(
-              channel_id_,
-              *ParseJsonDeprecated(
-                  R"({"sessionId": "theSessionId", "type": "SET_VOLUME"})"),
-              "theSourceId", set_volume_callback_.Get()));
+      handler_.SendSetVolumeRequest(
+          channel_id_,
+          *ParseJsonDeprecated(
+              R"({"sessionId": "theSessionId", "type": "SET_VOLUME"})"),
+          "theSourceId", set_volume_callback_.Get());
     }
     handler_.StopSession(channel_id_, "theSessionId", "theSourceId",
                          stop_session_callback_.Get());
@@ -428,9 +426,8 @@
     "sessionId": "theSessionId",
     "type": "SET_VOLUME",
   })";
-  EXPECT_EQ(Result::kOk, handler_.SendSetVolumeRequest(
-                             channel_id_, *ParseJsonDeprecated(message_str),
-                             "theSourceId", base::DoNothing::Once<Result>()));
+  handler_.SendSetVolumeRequest(channel_id_, *ParseJsonDeprecated(message_str),
+                                "theSourceId", base::DoNothing::Once<Result>());
 }
 
 // Check that closing a socket removes pending requests, and that the pending
@@ -517,9 +514,8 @@
     "type": "SET_VOLUME",
   })";
   base::MockCallback<ResultCallback> callback;
-  EXPECT_EQ(Result::kOk, handler_.SendSetVolumeRequest(
-                             channel_id_, *ParseJsonDeprecated(message_str),
-                             "theSourceId", callback.Get()));
+  handler_.SendSetVolumeRequest(channel_id_, *ParseJsonDeprecated(message_str),
+                                "theSourceId", callback.Get());
   EXPECT_CALL(callback, Run(Result::kFailed));
   thread_bundle_.FastForwardBy(kRequestTimeout);
 }
diff --git a/components/cast_channel/cast_test_util.h b/components/cast_channel/cast_test_util.h
index 6afa7c4..9b0152e 100644
--- a/components/cast_channel/cast_test_util.h
+++ b/components/cast_channel/cast_test_util.h
@@ -194,10 +194,10 @@
                                    const std::string& source_id,
                                    const std::string& destination_id));
   MOCK_METHOD4(SendSetVolumeRequest,
-               Result(int channel_id,
-                      const base::Value& body,
-                      const std::string& source_id,
-                      ResultCallback callback));
+               void(int channel_id,
+                    const base::Value& body,
+                    const std::string& source_id,
+                    ResultCallback callback));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockCastMessageHandler);
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index 501fd258..a10f65a 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/buildflag_header.gni")
+import("//build/config/c++/c++.gni")
 import("//build/config/ios/rules.gni")
 import("//build/config/mac/symbols.gni")
 import("//build/mac/tweak_info_plist.gni")
@@ -169,6 +170,7 @@
   public_deps = [
     "//components/grpc_support",
   ]
+
   configs += [ "//build/config/compiler:enable_arc" ]
 }
 
@@ -180,6 +182,16 @@
   deps = [
     ":cronet_static",
   ]
+
+  if (use_custom_libcxx) {
+    deps += [
+      # Add shared_library_deps to include custom libc++ into dependencies.
+      # They are by default only added to executable(), loadable_module(), and
+      # shared_library() targets, but cronet_static_complete library needs it as well to
+      # avoid linking with different versions of libc++.
+      "//build/config:shared_library_deps",
+    ]
+  }
 }
 
 # A static library which contains cronet and all dependendencies hidden inside.
diff --git a/components/cronet/native/url_request.cc b/components/cronet/native/url_request.cc
index 6237f025..a993f40 100644
--- a/components/cronet/native/url_request.cc
+++ b/components/cronet/native/url_request.cc
@@ -755,7 +755,7 @@
     int64_t received_bytes_count) {
   DCHECK_CALLED_ON_VALID_THREAD(network_thread_checker_);
   base::AutoLock lock(url_request_->lock_);
-  DCHECK_EQ(url_request_->metrics_, nullptr)
+  DCHECK_EQ(url_request_->metrics_.get(), nullptr)
       << "Metrics collection should only happen once.";
   auto metrics = std::make_unique<Cronet_Metrics>();
   using native_metrics_util::ConvertTime;
diff --git a/components/cronet/tools/hide_symbols.py b/components/cronet/tools/hide_symbols.py
index 9680cba..f38bc81 100755
--- a/components/cronet/tools/hide_symbols.py
+++ b/components/cronet/tools/hide_symbols.py
@@ -120,6 +120,11 @@
   ]
   subprocess.check_call(command)
 
+  ret = os.system('xcrun nm -u "' + options.output_obj + '" | grep ___cxa_pure_virtual')
+  if ret == 0:
+    print "ERROR: Found undefined libc++ symbols, is libc++ indcluded in dependencies?"
+    exit(2)
+
 
 if __name__ == "__main__":
   main()
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc
index 65206b7..4d99b68a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.cc
@@ -54,6 +54,30 @@
   return config;
 }
 
+// Creates a new ClientConfig with no proxies from the given parameters.
+ClientConfig CreateEmptyProxyConfig(const std::string& session_key,
+                                    int64_t expire_duration_seconds,
+                                    int64_t expire_duration_nanoseconds,
+                                    float reporting_fraction,
+                                    bool ignore_long_term_black_list_rules) {
+  ClientConfig config;
+
+  config.set_session_key(session_key);
+  config.mutable_refresh_duration()->set_seconds(expire_duration_seconds);
+  config.mutable_refresh_duration()->set_nanos(expire_duration_nanoseconds);
+
+  // Leave the pageload_metrics_config empty when |reporting_fraction| is not
+  // inclusively between zero and one.
+  if (reporting_fraction >= 0.0f && reporting_fraction <= 1.0f) {
+    config.mutable_pageload_metrics_config()->set_reporting_fraction(
+        reporting_fraction);
+  }
+  config.set_ignore_long_term_black_list_rules(
+      ignore_long_term_black_list_rules);
+  config.mutable_proxy_config()->clear_http_proxy_servers();
+  return config;
+}
+
 // Takes |config| and returns the base64 encoding of its serialized byte stream.
 std::string EncodeConfig(const ClientConfig& config) {
   std::string config_data;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h
index 5123e53e..9c5052e 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_test_utils.h
@@ -25,6 +25,13 @@
                           float reporting_fraction,
                           bool ignore_long_term_black_list_rules);
 
+// Creates a new ClientConfig with no proxies from the given parameters.
+ClientConfig CreateEmptyProxyConfig(const std::string& session_key,
+                                    int64_t expire_duration_seconds,
+                                    int64_t expire_duration_nanoseconds,
+                                    float reporting_fraction,
+                                    bool ignore_long_term_black_list_rules);
+
 // Takes |config| and returns the base64 encoding of its serialized byte stream.
 std::string EncodeConfig(const ClientConfig& config);
 
diff --git a/components/gwp_asan/client/BUILD.gn b/components/gwp_asan/client/BUILD.gn
index 0c5c102..25b2b9c 100644
--- a/components/gwp_asan/client/BUILD.gn
+++ b/components/gwp_asan/client/BUILD.gn
@@ -7,8 +7,6 @@
 component("client") {
   output_name = "gwp_asan_client"
   sources = [
-    "crash_key.cc",
-    "crash_key.h",
     "export.h",
     "guarded_page_allocator.cc",
     "guarded_page_allocator.h",
diff --git a/components/gwp_asan/client/crash_key.cc b/components/gwp_asan/client/crash_key.cc
deleted file mode 100644
index 43a49854..0000000
--- a/components/gwp_asan/client/crash_key.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-#include "components/gwp_asan/client/crash_key.h"
-
-#include "base/debug/crash_logging.h"
-#include "base/strings/stringprintf.h"
-#include "components/crash/core/common/crash_key.h"
-#include "components/gwp_asan/common/crash_key_name.h"
-
-namespace gwp_asan {
-namespace internal {
-
-void RegisterAllocatorAddress(uintptr_t ptr) {
-  static crash_reporter::CrashKeyString<24> gpa_crash_key(kGpaCrashKey);
-  gpa_crash_key.Set(base::StringPrintf("%zx", ptr));
-}
-
-}  // namespace internal
-}  // namespace gwp_asan
diff --git a/components/gwp_asan/client/crash_key.h b/components/gwp_asan/client/crash_key.h
deleted file mode 100644
index 3725691a..0000000
--- a/components/gwp_asan/client/crash_key.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_GWP_ASAN_CLIENT_CRASH_KEY_H_
-#define COMPONENTS_GWP_ASAN_CLIENT_CRASH_KEY_H_
-
-#include "components/gwp_asan/common/allocator_state.h"
-
-namespace gwp_asan {
-namespace internal {
-
-// Registers a crash key that both signals to the crash handler that GWP-ASan
-// has been enabled and also where to find the AllocatorState for this process.
-void RegisterAllocatorAddress(uintptr_t ptr);
-
-}  // namespace internal
-}  // namespace gwp_asan
-
-#endif  // COMPONENTS_GWP_ASAN_CLIENT_CRASH_KEY_H_
diff --git a/components/gwp_asan/client/guarded_page_allocator.cc b/components/gwp_asan/client/guarded_page_allocator.cc
index fae3e07d..9bd94c7 100644
--- a/components/gwp_asan/client/guarded_page_allocator.cc
+++ b/components/gwp_asan/client/guarded_page_allocator.cc
@@ -295,8 +295,8 @@
   metadata_[metadata_idx].dealloc.trace_collected = true;
 }
 
-uintptr_t GuardedPageAllocator::GetCrashKeyAddress() const {
-  return reinterpret_cast<uintptr_t>(&state_);
+std::string GuardedPageAllocator::GetCrashKey() const {
+  return base::StringPrintf("%zx", reinterpret_cast<uintptr_t>(&state_));
 }
 
 }  // namespace internal
diff --git a/components/gwp_asan/client/guarded_page_allocator.h b/components/gwp_asan/client/guarded_page_allocator.h
index 0d6a72669..49315e1 100644
--- a/components/gwp_asan/client/guarded_page_allocator.h
+++ b/components/gwp_asan/client/guarded_page_allocator.h
@@ -7,6 +7,7 @@
 
 #include <atomic>
 #include <memory>
+#include <string>
 #include <vector>
 
 #include "base/compiler_specific.h"
@@ -62,9 +63,9 @@
   // previously returned by a call to Allocate, and not have been deallocated.
   size_t GetRequestedSize(const void* ptr) const;
 
-  // Get the address of the GuardedPageAllocator crash key (the address of the
-  // the shared allocator state with the crash handler.)
-  uintptr_t GetCrashKeyAddress() const;
+  // Retrieves the textual address of the shared allocator state required by the
+  // crash handler.
+  std::string GetCrashKey() const;
 
   // Returns true if ptr points to memory managed by this class.
   inline bool PointerIsMine(const void* ptr) const {
diff --git a/components/gwp_asan/client/sampling_allocator_shims.cc b/components/gwp_asan/client/sampling_allocator_shims.cc
index 6a201fa5..f09acc9 100644
--- a/components/gwp_asan/client/sampling_allocator_shims.cc
+++ b/components/gwp_asan/client/sampling_allocator_shims.cc
@@ -14,9 +14,10 @@
 #include "base/process/process_metrics.h"
 #include "base/rand_util.h"
 #include "build/build_config.h"
-#include "components/gwp_asan/client/crash_key.h"
+#include "components/crash/core/common/crash_key.h"
 #include "components/gwp_asan/client/export.h"
 #include "components/gwp_asan/client/guarded_page_allocator.h"
+#include "components/gwp_asan/common/crash_key_name.h"
 
 #if defined(OS_MACOSX)
 #include <pthread.h>
@@ -325,9 +326,10 @@
                            size_t num_metadata,
                            size_t total_pages,
                            size_t sampling_frequency) {
+  static crash_reporter::CrashKeyString<24> malloc_crash_key(kGpaCrashKey);
   gpa = new GuardedPageAllocator();
   gpa->Init(max_allocated_pages, num_metadata, total_pages);
-  RegisterAllocatorAddress(gpa->GetCrashKeyAddress());
+  malloc_crash_key.Set(gpa->GetCrashKey());
   sampling_state.Init(sampling_frequency);
   base::allocator::InsertAllocatorDispatch(&g_allocator_dispatch);
 }
diff --git a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
index 8892d85b..017f62c 100644
--- a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
+++ b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
@@ -229,14 +229,10 @@
 MULTIPROCESS_TEST_MAIN_WITH_SETUP(
     CrashKey,
     SamplingAllocatorShimsTest::multiprocessTestSetup) {
-  std::string crash_key = crash_reporter::GetCrashKeyValue(kGpaCrashKey);
-
-  uint64_t value;
-  if (!base::HexStringToUInt64(crash_key, &value))
+  if (crash_reporter::GetCrashKeyValue(kGpaCrashKey) !=
+      GetGpaForTesting().GetCrashKey()) {
     return kFailure;
-
-  if (value != GetGpaForTesting().GetCrashKeyAddress())
-    return kFailure;
+  }
 
   return kSuccess;
 }
diff --git a/components/gwp_asan/crash_handler/crash_handler_unittest.cc b/components/gwp_asan/crash_handler/crash_handler_unittest.cc
index 56889d1..1aafd2e 100644
--- a/components/gwp_asan/crash_handler/crash_handler_unittest.cc
+++ b/components/gwp_asan/crash_handler/crash_handler_unittest.cc
@@ -85,12 +85,11 @@
   std::string test_name = cmd_line->GetSwitchValueASCII("test-name");
   CHECK(!test_name.empty());
 
-  static char gpa_addr_buf[32];
-  snprintf(gpa_addr_buf, sizeof(gpa_addr_buf), "%zx",
-           gpa->GetCrashKeyAddress());
+  std::string gpa_addr = gpa->GetCrashKey();
   static crashpad::Annotation gpa_annotation(
-      crashpad::Annotation::Type::kString, kGpaCrashKey, gpa_addr_buf);
-  gpa_annotation.SetSize(strlen(gpa_addr_buf));
+      crashpad::Annotation::Type::kString, kGpaCrashKey,
+      const_cast<char*>(gpa_addr.c_str()));
+  gpa_annotation.SetSize(gpa_addr.size());
 
   base::FilePath metrics_dir(FILE_PATH_LITERAL(""));
   std::map<std::string, std::string> annotations;
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn
index d63477b6..91dbec5 100644
--- a/components/history/core/browser/BUILD.gn
+++ b/components/history/core/browser/BUILD.gn
@@ -52,8 +52,6 @@
     "page_usage_data.h",
     "sync/delete_directive_handler.cc",
     "sync/delete_directive_handler.h",
-    "sync/history_delete_directives_data_type_controller.cc",
-    "sync/history_delete_directives_data_type_controller.h",
     "sync/history_delete_directives_model_type_controller.cc",
     "sync/history_delete_directives_model_type_controller.h",
     "sync/history_model_worker.cc",
diff --git a/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc b/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc
deleted file mode 100644
index 7f86bc6..0000000
--- a/components/history/core/browser/sync/history_delete_directives_data_type_controller.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/history/core/browser/sync/history_delete_directives_data_type_controller.h"
-
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/driver/sync_user_settings.h"
-
-namespace browser_sync {
-
-HistoryDeleteDirectivesDataTypeController::
-    HistoryDeleteDirectivesDataTypeController(const base::Closure& dump_stack,
-                                              syncer::SyncService* sync_service,
-                                              syncer::SyncClient* sync_client)
-    : syncer::AsyncDirectoryTypeController(
-          syncer::HISTORY_DELETE_DIRECTIVES,
-          dump_stack,
-          sync_service,
-          sync_client,
-          syncer::GROUP_UI,
-          base::ThreadTaskRunnerHandle::Get()) {}
-
-HistoryDeleteDirectivesDataTypeController::
-    ~HistoryDeleteDirectivesDataTypeController() {}
-
-bool HistoryDeleteDirectivesDataTypeController::ReadyForStart() const {
-  DCHECK(CalledOnValidThread());
-  return !sync_service()->GetUserSettings()->IsEncryptEverythingEnabled();
-}
-
-bool HistoryDeleteDirectivesDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  if (DisableTypeIfNecessary())
-    return false;
-  sync_service()->AddObserver(this);
-  return true;
-}
-
-void HistoryDeleteDirectivesDataTypeController::StopModels() {
-  DCHECK(CalledOnValidThread());
-  sync_service()->RemoveObserver(this);
-}
-
-void HistoryDeleteDirectivesDataTypeController::OnStateChanged(
-    syncer::SyncService* sync) {
-  DisableTypeIfNecessary();
-}
-
-bool HistoryDeleteDirectivesDataTypeController::DisableTypeIfNecessary() {
-  DCHECK(CalledOnValidThread());
-  if (!sync_service()->IsSyncFeatureActive())
-    return false;
-
-  if (ReadyForStart())
-    return false;
-
-  sync_service()->RemoveObserver(this);
-  syncer::SyncError error(FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
-                          "Delete directives not supported with encryption.",
-                          type());
-  CreateErrorHandler()->OnUnrecoverableError(error);
-  return true;
-}
-
-}  // namespace browser_sync
diff --git a/components/history/core/browser/sync/history_delete_directives_data_type_controller.h b/components/history/core/browser/sync/history_delete_directives_data_type_controller.h
deleted file mode 100644
index c550a5e..0000000
--- a/components/history/core/browser/sync/history_delete_directives_data_type_controller.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_DELETE_DIRECTIVES_DATA_TYPE_CONTROLLER_H_
-#define COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_DELETE_DIRECTIVES_DATA_TYPE_CONTROLLER_H_
-
-#include "base/macros.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-#include "components/sync/driver/sync_service_observer.h"
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-namespace browser_sync {
-
-// A controller for delete directives, which cannot sync when full encryption
-// is enabled.
-class HistoryDeleteDirectivesDataTypeController
-    : public syncer::AsyncDirectoryTypeController,
-      public syncer::SyncServiceObserver {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  HistoryDeleteDirectivesDataTypeController(const base::Closure& dump_stack,
-                                            syncer::SyncService* sync_service,
-                                            syncer::SyncClient* sync_client);
-  ~HistoryDeleteDirectivesDataTypeController() override;
-
-  // AsyncDirectoryTypeController override.
-  bool ReadyForStart() const override;
-  bool StartModels() override;
-  void StopModels() override;
-
-  // syncer::SyncServiceObserver implementation.
-  void OnStateChanged(syncer::SyncService* sync) override;
-
- private:
-  // Triggers a SingleDataTypeUnrecoverable error and returns true if the
-  // type is no longer ready, else does nothing and returns false.
-  bool DisableTypeIfNecessary();
-
-  DISALLOW_COPY_AND_ASSIGN(HistoryDeleteDirectivesDataTypeController);
-};
-
-}  // namespace browser_sync
-
-#endif  // COMPONENTS_HISTORY_CORE_BROWSER_SYNC_HISTORY_DELETE_DIRECTIVES_DATA_TYPE_CONTROLLER_H_
diff --git a/components/leveldb_proto/content/BUILD.gn b/components/leveldb_proto/content/BUILD.gn
index 87447864..7915c49 100644
--- a/components/leveldb_proto/content/BUILD.gn
+++ b/components/leveldb_proto/content/BUILD.gn
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+assert(!is_ios)
+
 source_set("factory") {
   sources = [
     "proto_database_provider_factory.cc",
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.cc b/components/leveldb_proto/public/shared_proto_database_client_list.cc
index 1639282..d4c5385a 100644
--- a/components/leveldb_proto/public/shared_proto_database_client_list.cc
+++ b/components/leveldb_proto/public/shared_proto_database_client_list.cc
@@ -63,6 +63,8 @@
       return "NotificationSchedulerNotifications";
     case ProtoDbType::BUDGET_DATABASE:
       return "BudgetManager";
+    case ProtoDbType::STRIKE_DATABASE:
+      return "StrikeService";
     case ProtoDbType::LAST:
       NOTREACHED();
       return std::string();
diff --git a/components/leveldb_proto/public/shared_proto_database_client_list.h b/components/leveldb_proto/public/shared_proto_database_client_list.h
index cffafde4..211cacd 100644
--- a/components/leveldb_proto/public/shared_proto_database_client_list.h
+++ b/components/leveldb_proto/public/shared_proto_database_client_list.h
@@ -36,6 +36,7 @@
   NOTIFICATION_SCHEDULER_IMPRESSION_STORE = 16,
   NOTIFICATION_SCHEDULER_NOTIFICATION_STORE = 17,
   BUDGET_DATABASE = 18,
+  STRIKE_DATABASE = 19,
 
   LAST,
 };
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
index 728fb24..d9bfeb9 100644
--- a/components/ntp_snippets/features.cc
+++ b/components/ntp_snippets/features.cc
@@ -71,7 +71,7 @@
 const char kNotificationsIgnoredLimitParam[] = "ignored_limit";
 
 const base::Feature kKeepPrefetchedContentSuggestions{
-    "KeepPrefetchedContentSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+    "KeepPrefetchedContentSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kContentSuggestionsDebugLog{
     "ContentSuggestionsDebugLog", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/omnibox/browser/autocomplete_match.cc b/components/omnibox/browser/autocomplete_match.cc
index 15f8b68..1584416 100644
--- a/components/omnibox/browser/autocomplete_match.cc
+++ b/components/omnibox/browser/autocomplete_match.cc
@@ -929,10 +929,6 @@
   return res;
 }
 
-bool AutocompleteMatch::IsExceptedFromLineReversal() const {
-  return !!answer && answer->type() == SuggestionAnswer::ANSWER_TYPE_DICTIONARY;
-}
-
 bool AutocompleteMatch::ShouldShowTabMatch() const {
   return has_tab_match && !associated_keyword;
 }
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h
index 175e7d5..c2b1aa3 100644
--- a/components/omnibox/browser/autocomplete_match.h
+++ b/components/omnibox/browser/autocomplete_match.h
@@ -375,10 +375,6 @@
   // See base/trace_event/memory_usage_estimator.h for more info.
   size_t EstimateMemoryUsage() const;
 
-  // Some types of matches (answers for dictionary definitions, e.g.) do not
-  // follow the common rules for reversing lines.
-  bool IsExceptedFromLineReversal() const;
-
   // Not to be confused with |has_tab_match|, this returns true if the match
   // has a matching tab and will use a switch-to-tab button. It returns false,
   // for example, when the switch button is not shown because a keyword match
diff --git a/components/omnibox/browser/history_url_provider.cc b/components/omnibox/browser/history_url_provider.cc
index 3c74a8e7..cf9bc70 100644
--- a/components/omnibox/browser/history_url_provider.cc
+++ b/components/omnibox/browser/history_url_provider.cc
@@ -523,6 +523,20 @@
   const bool trim_http = !AutocompleteInput::HasHTTPScheme(input.text());
   AutocompleteMatch what_you_typed_match(SuggestExactInput(
       fixed_up_input, fixed_up_input.canonicalized_url(), trim_http));
+
+  // If the input fix-up above added characters, show them as an
+  // autocompletion, unless directed not to.
+  if (!input.prevent_inline_autocomplete() &&
+      fixed_up_input.text().size() > input.text().size() &&
+      base::StartsWith(fixed_up_input.text(), input.text(),
+                       base::CompareCase::SENSITIVE)) {
+    what_you_typed_match.fill_into_edit = fixed_up_input.text();
+    what_you_typed_match.inline_autocompletion =
+        fixed_up_input.text().substr(input.text().size());
+    what_you_typed_match.contents_class.push_back(
+        {input.text().length(), ACMatchClassification::URL});
+  }
+
   what_you_typed_match.relevance = CalculateRelevance(WHAT_YOU_TYPED, 0);
 
   // Add the what-you-typed match as a fallback in case we can't get the history
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index b7f2e280..3aba494c 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -579,7 +579,17 @@
       omnibox::kHideSteadyStateUrlTrivialSubdomains);
 }
 
-int OmniboxFieldTrial::GetSuggestionVerticalMargin() {
+base::Optional<int>
+OmniboxFieldTrial::GetSuggestionVerticalMarginFieldTrialOverride() {
+  if (!base::FeatureList::IsEnabled(omnibox::kUIExperimentVerticalMargin))
+    return base::nullopt;
+
+  if (base::FeatureList::IsEnabled(
+          omnibox::kUIExperimentVerticalMarginLimitToNonTouchOnly) &&
+      ui::MaterialDesignController::touch_ui()) {
+    return base::nullopt;
+  }
+
   // When the vertical margin is set to 2dp, the suggestion height is the
   // closest to the pre-Refresh height. In fact it's 1dp taller than the
   // pre-Refresh height on Linux.
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index a0faf4b7..0d35b71 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "components/omnibox/browser/autocomplete_match_type.h"
 #include "third_party/metrics_proto/omnibox_event.pb.h"
@@ -401,9 +402,10 @@
 // subdomains is enabled.
 bool IsHideSteadyStateUrlTrivialSubdomainsEnabled();
 
-// Returns the size of the vertical margin that should be used in the
-// suggestion view.
-int GetSuggestionVerticalMargin();
+// Returns the field trial override for the vertical margin size that should be
+// used in the suggestion view. Returns base::nullopt if the UI code should use
+// the default vertical margin.
+base::Optional<int> GetSuggestionVerticalMarginFieldTrialOverride();
 
 // Simply a convenient wrapper for testing a flag. Used downstream for an
 // assortment of keyword mode experiments.
diff --git a/components/omnibox/browser/suggestion_answer.cc b/components/omnibox/browser/suggestion_answer.cc
index 8bc3ea34..151e55f7 100644
--- a/components/omnibox/browser/suggestion_answer.cc
+++ b/components/omnibox/browser/suggestion_answer.cc
@@ -336,15 +336,6 @@
                                  TextStyle::POSITIVE);
       second_line_.SetTextStyles(SuggestionAnswer::DESCRIPTION_NEGATIVE,
                                  TextStyle::NEGATIVE);
-      second_line_.SetTextStyles(SuggestionAnswer::ANSWER_TEXT_LARGE,
-                                 TextStyle::BOLD);
-      break;
-    }
-    case SuggestionAnswer::ANSWER_TYPE_DICTIONARY: {
-      // Because dictionary answers are excepted from line reversal, they
-      // get the expected normal first line and dim second line.
-      first_line_.SetTextStyles(0, TextStyle::NORMAL);
-      second_line_.SetTextStyles(0, TextStyle::NORMAL_DIM);
       break;
     }
     default:
@@ -353,8 +344,17 @@
 
   // Most answers uniformly apply different styling for each answer line.
   // Any old styles not replaced above will get these by default.
-  first_line_.SetTextStyles(0, TextStyle::NORMAL_DIM);
-  second_line_.SetTextStyles(0, TextStyle::NORMAL);
+  if (IsExceptedFromLineReversal()) {
+    first_line_.SetTextStyles(0, TextStyle::NORMAL);
+    second_line_.SetTextStyles(0, TextStyle::NORMAL_DIM);
+  } else {
+    first_line_.SetTextStyles(0, TextStyle::NORMAL_DIM);
+    second_line_.SetTextStyles(0, TextStyle::NORMAL);
+  }
+}
+
+bool SuggestionAnswer::IsExceptedFromLineReversal() const {
+  return type() == SuggestionAnswer::ANSWER_TYPE_DICTIONARY;
 }
 
 // static
diff --git a/components/omnibox/browser/suggestion_answer.h b/components/omnibox/browser/suggestion_answer.h
index 0116eb18..31be937c 100644
--- a/components/omnibox/browser/suggestion_answer.h
+++ b/components/omnibox/browser/suggestion_answer.h
@@ -244,6 +244,10 @@
   // For new answers, replace old answer text types with appropriate new types.
   void InterpretTextTypes();
 
+  // Some types of matches (answers for dictionary definitions, e.g.) do not
+  // follow the common rules for reversing lines.
+  bool IsExceptedFromLineReversal() const;
+
   // Logs which answer type was used (if any) at the time a user used the
   // omnibox to go somewhere.
   static void LogAnswerUsed(const base::Optional<SuggestionAnswer>& answer);
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index cda0d01..79adb02 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -203,6 +203,12 @@
 const base::Feature kUIExperimentVerticalMargin{
     "OmniboxUIExperimentVerticalMargin", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature used to limit the vertical margin UI experiment to non-touch
+// devices only. Has no effect if kUIExperimentVerticalMargin is not enabled.
+const base::Feature kUIExperimentVerticalMarginLimitToNonTouchOnly{
+    "OmniboxUIExperimentVerticalMarginLimitToNonTouchOnly",
+    base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Feature used to color "blue" the generic search icon and search terms.
 // Technically, this makes the search icon and search terms match the color of
 // Omnibox link text, which is blue by convention.
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 02b8932..b5416dba 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -38,6 +38,7 @@
 extern const base::Feature kUIExperimentShowSuggestionFavicons;
 extern const base::Feature kUIExperimentSwapTitleAndUrl;
 extern const base::Feature kUIExperimentVerticalMargin;
+extern const base::Feature kUIExperimentVerticalMarginLimitToNonTouchOnly;
 extern const base::Feature kUIExperimentBlueSearchLoopAndSearchQuery;
 extern const base::Feature kUIExperimentBlueTitlesAndGrayUrlsOnPageSuggestions;
 extern const base::Feature kUIExperimentBlueTitlesOnPageSuggestions;
diff --git a/components/password_manager/core/browser/fake_form_fetcher.cc b/components/password_manager/core/browser/fake_form_fetcher.cc
index a6421ad3..dd68207 100644
--- a/components/password_manager/core/browser/fake_form_fetcher.cc
+++ b/components/password_manager/core/browser/fake_form_fetcher.cc
@@ -34,28 +34,27 @@
   return stats_;
 }
 
-const std::vector<const autofill::PasswordForm*>&
-FakeFormFetcher::GetNonFederatedMatches() const {
+std::vector<const PasswordForm*> FakeFormFetcher::GetNonFederatedMatches()
+    const {
   return non_federated_;
 }
 
-const std::vector<const autofill::PasswordForm*>&
-FakeFormFetcher::GetFederatedMatches() const {
+std::vector<const PasswordForm*> FakeFormFetcher::GetFederatedMatches() const {
   return federated_;
 }
 
-const std::vector<const autofill::PasswordForm*>&
-FakeFormFetcher::GetBlacklistedMatches() const {
+std::vector<const PasswordForm*> FakeFormFetcher::GetBlacklistedMatches()
+    const {
   return blacklisted_;
 }
 
 void FakeFormFetcher::SetNonFederated(
-    const std::vector<const autofill::PasswordForm*>& non_federated) {
+    const std::vector<const PasswordForm*>& non_federated) {
   non_federated_ = non_federated;
 }
 
 void FakeFormFetcher::SetBlacklisted(
-    const std::vector<const autofill::PasswordForm*>& blacklisted) {
+    const std::vector<const PasswordForm*>& blacklisted) {
   blacklisted_ = blacklisted;
 }
 
diff --git a/components/password_manager/core/browser/fake_form_fetcher.h b/components/password_manager/core/browser/fake_form_fetcher.h
index 4a36222..d487c76 100644
--- a/components/password_manager/core/browser/fake_form_fetcher.h
+++ b/components/password_manager/core/browser/fake_form_fetcher.h
@@ -48,13 +48,13 @@
     stats_ = stats;
   }
 
-  const std::vector<const autofill::PasswordForm*>& GetNonFederatedMatches()
+  std::vector<const autofill::PasswordForm*> GetNonFederatedMatches()
       const override;
 
-  const std::vector<const autofill::PasswordForm*>& GetFederatedMatches()
+  std::vector<const autofill::PasswordForm*> GetFederatedMatches()
       const override;
 
-  const std::vector<const autofill::PasswordForm*>& GetBlacklistedMatches()
+  std::vector<const autofill::PasswordForm*> GetBlacklistedMatches()
       const override;
 
   void set_federated(
diff --git a/components/password_manager/core/browser/form_fetcher.h b/components/password_manager/core/browser/form_fetcher.h
index 32d43984..a124269 100644
--- a/components/password_manager/core/browser/form_fetcher.h
+++ b/components/password_manager/core/browser/form_fetcher.h
@@ -63,18 +63,18 @@
 
   // Non-federated matches obtained from the backend. Valid only if GetState()
   // returns NOT_WAITING.
-  virtual const std::vector<const autofill::PasswordForm*>&
-  GetNonFederatedMatches() const = 0;
+  virtual std::vector<const autofill::PasswordForm*> GetNonFederatedMatches()
+      const = 0;
 
   // Federated matches obtained from the backend. Valid only if GetState()
   // returns NOT_WAITING.
-  virtual const std::vector<const autofill::PasswordForm*>&
-  GetFederatedMatches() const = 0;
+  virtual std::vector<const autofill::PasswordForm*> GetFederatedMatches()
+      const = 0;
 
   // Blacklisted matches obtained from the backend. Valid only if GetState()
   // returns NOT_WAITING.
-  virtual const std::vector<const autofill::PasswordForm*>&
-  GetBlacklistedMatches() const = 0;
+  virtual std::vector<const autofill::PasswordForm*> GetBlacklistedMatches()
+      const = 0;
 
   // Fetches stored matching logins. In addition the statistics is fetched on
   // platforms with the password bubble. This is called automatically during
diff --git a/components/password_manager/core/browser/form_fetcher_impl.cc b/components/password_manager/core/browser/form_fetcher_impl.cc
index 964028b..030bbb2 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.cc
+++ b/components/password_manager/core/browser/form_fetcher_impl.cc
@@ -117,19 +117,18 @@
   return interactions_stats_;
 }
 
-const std::vector<const PasswordForm*>&
-FormFetcherImpl::GetNonFederatedMatches() const {
-  return weak_non_federated_;
+std::vector<const PasswordForm*> FormFetcherImpl::GetNonFederatedMatches()
+    const {
+  return MakeWeakCopies(non_federated_);
 }
 
-const std::vector<const PasswordForm*>& FormFetcherImpl::GetFederatedMatches()
-    const {
-  return weak_federated_;
+std::vector<const PasswordForm*> FormFetcherImpl::GetFederatedMatches() const {
+  return MakeWeakCopies(federated_);
 }
 
-const std::vector<const PasswordForm*>& FormFetcherImpl::GetBlacklistedMatches()
+std::vector<const PasswordForm*> FormFetcherImpl::GetBlacklistedMatches()
     const {
-  return weak_blacklisted_;
+  return MakeWeakCopies(blacklisted_);
 }
 
 void FormFetcherImpl::OnGetPasswordStoreResults(
@@ -170,7 +169,7 @@
 }
 
 void FormFetcherImpl::ProcessMigratedForms(
-    std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
+    std::vector<std::unique_ptr<PasswordForm>> forms) {
   ProcessPasswordStoreResults(std::move(forms));
 }
 
@@ -220,15 +219,10 @@
     return std::move(result);
   }
 
-  result->non_federated_ = MakeCopies(this->non_federated_);
-  result->federated_ = MakeCopies(this->federated_);
-  result->blacklisted_ = MakeCopies(this->blacklisted_);
+  result->non_federated_ = MakeCopies(non_federated_);
+  result->federated_ = MakeCopies(federated_);
+  result->blacklisted_ = MakeCopies(blacklisted_);
   result->interactions_stats_ = this->interactions_stats_;
-
-  result->weak_non_federated_ = MakeWeakCopies(result->non_federated_);
-  result->weak_federated_ = MakeWeakCopies(result->federated_);
-  result->weak_blacklisted_ = MakeWeakCopies(result->blacklisted_);
-
   result->state_ = this->state_;
   result->need_to_refetch_ = this->need_to_refetch_;
 
@@ -236,7 +230,7 @@
 }
 
 void FormFetcherImpl::ProcessPasswordStoreResults(
-    std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
+    std::vector<std::unique_ptr<PasswordForm>> results) {
   DCHECK_EQ(State::WAITING, state_);
   state_ = State::NOT_WAITING;
   SplitMatches matches = SplitResults(std::move(results));
@@ -244,10 +238,6 @@
   non_federated_ = std::move(matches.non_federated);
   blacklisted_ = std::move(matches.blacklisted);
 
-  weak_non_federated_ = MakeWeakCopies(non_federated_);
-  weak_federated_ = MakeWeakCopies(federated_);
-  weak_blacklisted_ = MakeWeakCopies(blacklisted_);
-
   for (auto* consumer : consumers_)
     consumer->OnFetchCompleted();
 }
diff --git a/components/password_manager/core/browser/form_fetcher_impl.h b/components/password_manager/core/browser/form_fetcher_impl.h
index c3d7d7e..f5c8de6 100644
--- a/components/password_manager/core/browser/form_fetcher_impl.h
+++ b/components/password_manager/core/browser/form_fetcher_impl.h
@@ -38,12 +38,14 @@
   void RemoveConsumer(FormFetcher::Consumer* consumer) override;
   State GetState() const override;
   const std::vector<InteractionsStats>& GetInteractionsStats() const override;
-  const std::vector<const autofill::PasswordForm*>& GetNonFederatedMatches()
+
+  std::vector<const autofill::PasswordForm*> GetNonFederatedMatches()
       const override;
-  const std::vector<const autofill::PasswordForm*>& GetFederatedMatches()
+  std::vector<const autofill::PasswordForm*> GetFederatedMatches()
       const override;
-  const std::vector<const autofill::PasswordForm*>& GetBlacklistedMatches()
+  std::vector<const autofill::PasswordForm*> GetBlacklistedMatches()
       const override;
+
   void Fetch() override;
   std::unique_ptr<FormFetcher> Clone() override;
 
@@ -78,12 +80,6 @@
   // Statistics for the current domain.
   std::vector<InteractionsStats> interactions_stats_;
 
-  // Non-owning copies of the vectors above.
-  // TODO(https://crbug.com/945864): Clean this up.
-  std::vector<const autofill::PasswordForm*> weak_non_federated_;
-  std::vector<const autofill::PasswordForm*> weak_federated_;
-  std::vector<const autofill::PasswordForm*> weak_blacklisted_;
-
   // Consumers of the fetcher, all are assumed to outlive |this|.
   std::set<FormFetcher::Consumer*> consumers_;
 
diff --git a/components/policy/core/common/policy_map.cc b/components/policy/core/common/policy_map.cc
index e770bd9..1b0d35c 100644
--- a/components/policy/core/common/policy_map.cc
+++ b/components/policy/core/common/policy_map.cc
@@ -121,15 +121,21 @@
   return error_string;
 }
 
-bool PolicyMap::Entry::IsBlocked() const {
+bool PolicyMap::Entry::IsBlockedOrIgnored() const {
   return error_message_ids_.find(IDS_POLICY_BLOCKED) !=
-         error_message_ids_.end();
+             error_message_ids_.end() ||
+         error_message_ids_.find(IDS_POLICY_IGNORED_BY_GROUP_MERGING) !=
+             error_message_ids_.end();
 }
 
 void PolicyMap::Entry::SetBlocked() {
   error_message_ids_.insert(IDS_POLICY_BLOCKED);
 }
 
+void PolicyMap::Entry::SetIgnoredByPolicyAtomicGroup() {
+  error_message_ids_.insert(IDS_POLICY_IGNORED_BY_GROUP_MERGING);
+}
+
 PolicyMap::PolicyMap() {}
 
 PolicyMap::~PolicyMap() {
@@ -138,26 +144,28 @@
 
 const PolicyMap::Entry* PolicyMap::Get(const std::string& policy) const {
   auto entry = map_.find(policy);
-  return entry != map_.end() && !entry->second.IsBlocked() ? &entry->second
-                                                           : nullptr;
+  return entry != map_.end() && !entry->second.IsBlockedOrIgnored()
+             ? &entry->second
+             : nullptr;
 }
 
 PolicyMap::Entry* PolicyMap::GetMutable(const std::string& policy) {
   auto entry = map_.find(policy);
-  return entry != map_.end() && !entry->second.IsBlocked() ? &entry->second
-                                                           : nullptr;
+  return entry != map_.end() && !entry->second.IsBlockedOrIgnored()
+             ? &entry->second
+             : nullptr;
 }
 
 const base::Value* PolicyMap::GetValue(const std::string& policy) const {
   auto entry = map_.find(policy);
-  return entry != map_.end() && !entry->second.IsBlocked()
+  return entry != map_.end() && !entry->second.IsBlockedOrIgnored()
              ? entry->second.value.get()
              : nullptr;
 }
 
 base::Value* PolicyMap::GetMutableValue(const std::string& policy) {
   auto entry = map_.find(policy);
-  return entry != map_.end() && !entry->second.IsBlocked()
+  return entry != map_.end() && !entry->second.IsBlockedOrIgnored()
              ? entry->second.value.get()
              : nullptr;
 }
diff --git a/components/policy/core/common/policy_map.h b/components/policy/core/common/policy_map.h
index 55762158..6ac0dcd 100644
--- a/components/policy/core/common/policy_map.h
+++ b/components/policy/core/common/policy_map.h
@@ -75,10 +75,17 @@
     // Removes all the conflicts.
     void ClearConflicts();
 
-    bool IsBlocked() const;
+    // Returns true if the policy is either blocked or ignored.
+    bool IsBlockedOrIgnored() const;
 
+    // Marks the policy as blocked because it is not supported in the current
+    // environment.
     void SetBlocked();
 
+    // Marks the policy as ignored because it does not share the priority of
+    // its policy atomic group.
+    void SetIgnoredByPolicyAtomicGroup();
+
     // Callback used to look up a localized string given its l10n message ID. It
     // should return a UTF-16 string.
     typedef base::RepeatingCallback<base::string16(int message_id)>
diff --git a/components/policy/core/common/policy_map_unittest.cc b/components/policy/core/common/policy_map_unittest.cc
index e65fc95..d124eaea 100644
--- a/components/policy/core/common/policy_map_unittest.cc
+++ b/components/policy/core/common/policy_map_unittest.cc
@@ -307,7 +307,7 @@
   EXPECT_TRUE(a.Equals(c));
 }
 
-TEST_F(PolicyMapTest, MergeValues) {
+TEST_F(PolicyMapTest, MergeValuesList) {
   std::vector<base::Value> abcd = GetListStorage({"a", "b", "c", "d"});
   std::vector<base::Value> abc = GetListStorage({"a", "b", "c"});
   std::vector<base::Value> ab = GetListStorage({"a", "b"});
@@ -372,6 +372,10 @@
   PolicyMap::Entry merged_cloud_machine_mandatory(
       POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_MERGED,
       std::make_unique<base::Value>(abcd), nullptr);
+  auto merged_cloud_machine_mandatory_blocked_by_group =
+      merged_cloud_machine_mandatory.DeepCopy();
+  merged_cloud_machine_mandatory_blocked_by_group
+      .SetIgnoredByPolicyAtomicGroup();
   merged_cloud_machine_mandatory.AddConflictingPolicy(cloud_machine_mandatory);
 
   // Case 4 - kTestPolicyName4
@@ -458,6 +462,88 @@
   EXPECT_TRUE(list_merged_wildcard.Equals(expected_list_merged_wildcard));
 }
 
+TEST_F(PolicyMapTest, MergeValuesGroup) {
+  std::vector<base::Value> abc = GetListStorage({"a", "b", "c"});
+  std::vector<base::Value> ab = GetListStorage({"a", "b"});
+  std::vector<base::Value> cd = GetListStorage({"c", "d"});
+  std::vector<base::Value> ef = GetListStorage({"e", "f"});
+
+  // Case 1 - kTestPolicyName1
+  // Should not be affected by the atomic groups
+  PolicyMap::Entry platform_user_mandatory(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_PLATFORM,
+      std::make_unique<base::Value>(abc), nullptr);
+
+  platform_user_mandatory.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
+      std::make_unique<base::Value>(cd), nullptr));
+
+  platform_user_mandatory.AddConflictingPolicy(
+      PolicyMap::Entry(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+                       POLICY_SOURCE_ENTERPRISE_DEFAULT,
+                       std::make_unique<base::Value>(ef), nullptr));
+
+  platform_user_mandatory.AddConflictingPolicy(
+      PolicyMap::Entry(POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER,
+                       POLICY_SOURCE_ENTERPRISE_DEFAULT,
+                       std::make_unique<base::Value>(ef), nullptr));
+
+  // Case 2 - policy::key::kExtensionInstallBlacklist
+  // This policy is part of the atomic group "Extensions" and has the highest
+  // source in its group, its value should remain the same.
+  PolicyMap::Entry cloud_machine_mandatory(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+      POLICY_SOURCE_PRIORITY_CLOUD, std::make_unique<base::Value>(ab), nullptr);
+
+  cloud_machine_mandatory.AddConflictingPolicy(PolicyMap::Entry(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE, POLICY_SOURCE_PLATFORM,
+      std::make_unique<base::Value>(cd), nullptr));
+
+  // Case 3 - policy::key::kExtensionInstallWhitelist
+  // This policy is part of the atomic group "Extensions" and has a lower
+  // source than policy::key::kExtensionInstallBlacklist from the same group,
+  // its value should be ignored.
+  PolicyMap::Entry ad_machine_mandatory(
+      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+      POLICY_SOURCE_ACTIVE_DIRECTORY, std::make_unique<base::Value>(ef),
+      nullptr);
+  auto ad_machine_mandatory_ignored = ad_machine_mandatory.DeepCopy();
+  ad_machine_mandatory_ignored.SetIgnoredByPolicyAtomicGroup();
+
+  // Case 4 - policy::key::kExtensionInstallBlacklist
+  // This policy is part of the atomic group "Extensions" and has the highest
+  // source in its group, its value should remain the same.
+  PolicyMap::Entry cloud_machine_recommended(
+      POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_MACHINE,
+      POLICY_SOURCE_PRIORITY_CLOUD, std::make_unique<base::Value>(ab), nullptr);
+
+  PolicyMap policy_not_merged;
+  policy_not_merged.Set(kTestPolicyName1, platform_user_mandatory.DeepCopy());
+  policy_not_merged.Set(policy::key::kExtensionInstallBlacklist,
+                        cloud_machine_mandatory.DeepCopy());
+  policy_not_merged.Set(policy::key::kExtensionInstallWhitelist,
+                        ad_machine_mandatory.DeepCopy());
+  policy_not_merged.Set(policy::key::kExtensionInstallForcelist,
+                        cloud_machine_recommended.DeepCopy());
+
+  PolicyMap group_merged;
+  group_merged.CopyFrom(policy_not_merged);
+  PolicyGroupMerger group_merger;
+  group_merged.MergeValues({&group_merger});
+
+  PolicyMap expected_group_merged;
+  expected_group_merged.Set(kTestPolicyName1,
+                            platform_user_mandatory.DeepCopy());
+  expected_group_merged.Set(policy::key::kExtensionInstallBlacklist,
+                            cloud_machine_mandatory.DeepCopy());
+  expected_group_merged.Set(policy::key::kExtensionInstallWhitelist,
+                            ad_machine_mandatory_ignored.DeepCopy());
+  expected_group_merged.Set(policy::key::kExtensionInstallForcelist,
+                            cloud_machine_recommended.DeepCopy());
+
+  EXPECT_TRUE(group_merged.Equals(expected_group_merged));
+}
+
 TEST_F(PolicyMapTest, GetDifferingKeys) {
   PolicyMap a;
   a.Set(kTestPolicyName1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
diff --git a/components/policy/core/common/policy_merger.cc b/components/policy/core/common/policy_merger.cc
index 37b95f4..940a67a 100644
--- a/components/policy/core/common/policy_merger.cc
+++ b/components/policy/core/common/policy_merger.cc
@@ -14,18 +14,19 @@
 PolicyMerger::PolicyMerger() = default;
 PolicyMerger::~PolicyMerger() = default;
 
-void PolicyMerger::Merge(PolicyMap::PolicyMapType* result) const {
-  for (auto it = result->begin(); it != result->end(); it++) {
-    if (CanMerge(it->first, it->second))
-      (*result)[it->first] = Merge(it->second);
-  }
-}
-
 PolicyListMerger::PolicyListMerger(
     const std::set<std::string> policies_to_merge)
     : policies_to_merge_(std::move(policies_to_merge)) {}
 PolicyListMerger::~PolicyListMerger() = default;
 
+void PolicyListMerger::Merge(PolicyMap::PolicyMapType* policies) const {
+  DCHECK(policies);
+  for (auto it = policies->begin(); it != policies->end(); it++) {
+    if (CanMerge(it->first, it->second))
+      (*policies)[it->first] = DoMerge(it->second);
+  }
+}
+
 bool PolicyListMerger::CanMerge(const std::string& policy_name,
                                 PolicyMap::Entry& policy) const {
   if (policy.source == POLICY_SOURCE_MERGED)
@@ -45,7 +46,8 @@
   return true;
 }
 
-PolicyMap::Entry PolicyListMerger::Merge(const PolicyMap::Entry& policy) const {
+PolicyMap::Entry PolicyListMerger::DoMerge(
+    const PolicyMap::Entry& policy) const {
   std::vector<const base::Value*> value;
   std::set<std::string> duplicates;
   bool merged = false;
@@ -65,9 +67,9 @@
         it.scope == POLICY_SCOPE_USER &&
         (it.source == POLICY_SOURCE_CLOUD ||
          it.source == POLICY_SOURCE_PRIORITY_CLOUD);
-    if (it.IsBlocked() || it.source == POLICY_SOURCE_ENTERPRISE_DEFAULT ||
-        is_user_cloud_policy || it.level != policy.level ||
-        it.scope != policy.scope) {
+    if (it.IsBlockedOrIgnored() ||
+        it.source == POLICY_SOURCE_ENTERPRISE_DEFAULT || is_user_cloud_policy ||
+        it.level != policy.level || it.scope != policy.scope) {
       continue;
     }
 
@@ -95,4 +97,67 @@
   return result;
 }
 
+PolicyGroupMerger::PolicyGroupMerger() = default;
+PolicyGroupMerger::~PolicyGroupMerger() = default;
+
+void PolicyGroupMerger::Merge(PolicyMap::PolicyMapType* policies) const {
+  for (size_t i = 0; i < kPolicyAtomicGroupMappingsLength; ++i) {
+    const AtomicGroup& group = kPolicyAtomicGroupMappings[i];
+    bool use_highest_set_priority = false;
+
+    // Defaults to the lowest priority.
+    PolicyMap::Entry highest_set_priority;
+
+    // Find the policy with the highest priority that is both in |policies| and
+    // |group.policies|, an array ending with a nullptr.
+    for (const char* const* policy_name = group.policies; *policy_name;
+         ++policy_name) {
+      auto policy_it = policies->find(*policy_name);
+
+      if (policy_it == policies->end())
+        continue;
+
+      use_highest_set_priority = true;
+
+      PolicyMap::Entry& policy = policy_it->second;
+
+      if (!policy.has_higher_priority_than(highest_set_priority))
+        continue;
+
+      // Do not set POLICY_SOURCE_MERGED as the highest acceptable source
+      // because it is a computed source. In case of an already merged policy,
+      // the highest acceptable source must be the highest of the ones used to
+      // compute the merged value.
+      if (policy.source != POLICY_SOURCE_MERGED) {
+        highest_set_priority = policy.DeepCopy();
+      } else {
+        for (const auto& conflict : policy.conflicts) {
+          if (conflict.has_higher_priority_than(highest_set_priority) &&
+              conflict.source > highest_set_priority.source) {
+            highest_set_priority = conflict.DeepCopy();
+          }
+        }
+      }
+    }
+
+    if (!use_highest_set_priority)
+      continue;
+
+    // Ignore the policies from |group.policies|, an array ending with a
+    // nullptr, that do not share the same source as the one with the highest
+    // priority.
+    for (const char* const* policy_name = group.policies; *policy_name;
+         ++policy_name) {
+      auto policy_it = policies->find(*policy_name);
+      if (policy_it == policies->end())
+        continue;
+
+      PolicyMap::Entry& policy = policy_it->second;
+
+      if (policy.source < highest_set_priority.source)
+        policy.SetIgnoredByPolicyAtomicGroup();
+    }
+  }
+}
+
 }  // namespace policy
\ No newline at end of file
diff --git a/components/policy/core/common/policy_merger.h b/components/policy/core/common/policy_merger.h
index 8301e43..f071a1d90 100644
--- a/components/policy/core/common/policy_merger.h
+++ b/components/policy/core/common/policy_merger.h
@@ -11,41 +11,62 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/singleton.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/policy_export.h"
 
 namespace policy {
 
+// Abstract class that provides an interface to apply custom merging logic on a
+// set of policies.
 class POLICY_EXPORT PolicyMerger {
  public:
   PolicyMerger();
   virtual ~PolicyMerger();
-
-  virtual void Merge(PolicyMap::PolicyMapType* result) const;
-  virtual bool CanMerge(const std::string& policy_name,
-                        PolicyMap::Entry& policy) const = 0;
-
- protected:
-  virtual PolicyMap::Entry Merge(const PolicyMap::Entry& policy) const = 0;
+  virtual void Merge(PolicyMap::PolicyMapType* policies) const = 0;
 };
 
+// PolicyListMerger allows the merging of policy lists that have multiple
+// sources. Each policy that has to be merged will have the values from its
+// multiple sources concatenated without duplicates.
 class POLICY_EXPORT PolicyListMerger : public PolicyMerger {
  public:
   explicit PolicyListMerger(const std::set<std::string> policies_to_merge);
-
   ~PolicyListMerger() override;
-  bool CanMerge(const std::string& policy_name,
-                PolicyMap::Entry& policy) const override;
 
- protected:
-  PolicyMap::Entry Merge(const PolicyMap::Entry& policy) const override;
+  // Merges the list policies from |policies| that have multiple sources.
+  void Merge(PolicyMap::PolicyMapType* policies) const override;
 
  private:
+  // Returns True if |policy_name| is in the list of policies to merge and if
+  // |policy| has values from different sources that share the same level,
+  // target and scope.
+  bool CanMerge(const std::string& policy_name, PolicyMap::Entry& policy) const;
+
+  // Returns a new entry that has merged the value from the different
+  // conflicting sources from |policy|. The resulting policy has |policy| and
+  // its conflicts as conflicts.
+  PolicyMap::Entry DoMerge(const PolicyMap::Entry& policy) const;
+
   const std::set<std::string> policies_to_merge_;
+
   DISALLOW_COPY_AND_ASSIGN(PolicyListMerger);
 };
 
+// PolicyGroupMerger enforces atomic policy groups. It disables the policies
+// from a group that do not share the highest priority from that group.
+class POLICY_EXPORT PolicyGroupMerger : public PolicyMerger {
+ public:
+  PolicyGroupMerger();
+  ~PolicyGroupMerger() override;
+
+  // Disables policies from atomic groups that do not share the highest priority
+  // from that group.
+  void Merge(PolicyMap::PolicyMapType* result) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PolicyGroupMerger);
+};
+
 }  // namespace policy
 
 #endif  // COMPONENTS_POLICY_CORE_COMMON_POLICY_MERGER_H_
diff --git a/components/policy/core/common/policy_service_impl.cc b/components/policy/core/common/policy_service_impl.cc
index d336030e..946800b 100644
--- a/components/policy/core/common/policy_service_impl.cc
+++ b/components/policy/core/common/policy_service_impl.cc
@@ -216,9 +216,10 @@
   }
 
   PolicyListMerger policy_list_merger(std::move(policy_lists_to_merge));
+  PolicyGroupMerger policy_group_merger;
 
   for (auto it = bundle.begin(); it != bundle.end(); ++it)
-    it->second->MergeValues({&policy_list_merger});
+    it->second->MergeValues({&policy_list_merger, &policy_group_merger});
 
   // Swap first, so that observers that call GetPolicies() see the current
   // values.
diff --git a/components/policy/core/common/policy_service_impl_unittest.cc b/components/policy/core/common/policy_service_impl_unittest.cc
index e1515187..4332bbc 100644
--- a/components/policy/core/common/policy_service_impl_unittest.cc
+++ b/components/policy/core/common/policy_service_impl_unittest.cc
@@ -271,7 +271,7 @@
                  POLICY_SOURCE_CLOUD, std::make_unique<base::Value>("value"),
                  nullptr);
 
-  std::unique_ptr<PolicyBundle> bundle(new PolicyBundle());
+  auto bundle = std::make_unique<PolicyBundle>();
   // The initial setup includes a policy for chrome that is now changing.
   bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
       .CopyFrom(policy_map);
@@ -525,9 +525,9 @@
 }
 
 TEST_F(PolicyServiceTest, NamespaceMerge) {
-  std::unique_ptr<PolicyBundle> bundle0(new PolicyBundle());
-  std::unique_ptr<PolicyBundle> bundle1(new PolicyBundle());
-  std::unique_ptr<PolicyBundle> bundle2(new PolicyBundle());
+  auto bundle0 = std::make_unique<PolicyBundle>();
+  auto bundle1 = std::make_unique<PolicyBundle>();
+  auto bundle2 = std::make_unique<PolicyBundle>();
 
   AddTestPolicies(bundle0.get(), "bundle0",
                   POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER);
@@ -740,21 +740,21 @@
   const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
 
   std::unique_ptr<base::ListValue> list1 = std::make_unique<base::ListValue>();
-  list1->Append(std::make_unique<base::Value>("google.com"));
-  list1->Append(std::make_unique<base::Value>("gmail.com"));
+  list1->GetList().push_back(base::Value("google.com"));
+  list1->GetList().push_back(base::Value("gmail.com"));
   std::unique_ptr<base::ListValue> list2 = std::make_unique<base::ListValue>();
-  list2->Append(std::make_unique<base::Value>("example.com"));
-  list2->Append(std::make_unique<base::Value>("gmail.com"));
+  list2->GetList().push_back(base::Value("example.com"));
+  list2->GetList().push_back(base::Value("gmail.com"));
   std::unique_ptr<base::ListValue> result = std::make_unique<base::ListValue>();
-  result->Append(std::make_unique<base::Value>("google.com"));
-  result->Append(std::make_unique<base::Value>("gmail.com"));
-  result->Append(std::make_unique<base::Value>("example.com"));
+  result->GetList().push_back(base::Value("google.com"));
+  result->GetList().push_back(base::Value("gmail.com"));
+  result->GetList().push_back(base::Value("example.com"));
 
   std::unique_ptr<base::ListValue> policy = std::make_unique<base::ListValue>();
   policy->GetList().push_back(
       base::Value(policy::key::kExtensionInstallForcelist));
 
-  std::unique_ptr<PolicyBundle> policy_bundle1(new PolicyBundle());
+  auto policy_bundle1 = std::make_unique<PolicyBundle>();
   PolicyMap& policy_map1 = policy_bundle1->Get(chrome_namespace);
   policy_map1.Set(key::kPolicyListMultipleSourceMergeList,
                   POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
@@ -765,7 +765,7 @@
                                 nullptr);
   policy_map1.Set(key::kExtensionInstallForcelist, entry_list_1.DeepCopy());
 
-  std::unique_ptr<PolicyBundle> policy_bundle2(new PolicyBundle());
+  auto policy_bundle2 = std::make_unique<PolicyBundle>();
   PolicyMap& policy_map2 = policy_bundle2->Get(chrome_namespace);
   PolicyMap::Entry entry_list_2(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
                                 POLICY_SOURCE_CLOUD, std::move(list2), nullptr);
@@ -790,4 +790,67 @@
   EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
 }
 
+TEST_F(PolicyServiceTest, GroupPoliciesMerging) {
+  const PolicyNamespace chrome_namespace(POLICY_DOMAIN_CHROME, std::string());
+
+  std::unique_ptr<base::ListValue> list1 = std::make_unique<base::ListValue>();
+  list1->GetList().push_back(base::Value("google.com"));
+  std::unique_ptr<base::ListValue> list2 = std::make_unique<base::ListValue>();
+  list2->GetList().push_back(base::Value("example.com"));
+  std::unique_ptr<base::ListValue> list3 = std::make_unique<base::ListValue>();
+  list3->GetList().push_back(base::Value("example_xyz.com"));
+  std::unique_ptr<base::ListValue> result = std::make_unique<base::ListValue>();
+  result->GetList().push_back(base::Value("google.com"));
+  result->GetList().push_back(base::Value("example.com"));
+
+  std::unique_ptr<base::ListValue> policy = std::make_unique<base::ListValue>();
+  policy->GetList().push_back(
+      base::Value(policy::key::kExtensionInstallForcelist));
+  policy->GetList().push_back(
+      base::Value(policy::key::kExtensionInstallBlacklist));
+
+  auto policy_bundle1 = std::make_unique<PolicyBundle>();
+  PolicyMap& policy_map1 = policy_bundle1->Get(chrome_namespace);
+  policy_map1.Set(key::kPolicyListMultipleSourceMergeList,
+                  POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                  POLICY_SOURCE_PLATFORM,
+                  base::Value::ToUniquePtrValue(policy->Clone()), nullptr);
+  PolicyMap::Entry entry_list_1(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                                POLICY_SOURCE_PLATFORM, std::move(list1),
+                                nullptr);
+  policy_map1.Set(key::kExtensionInstallForcelist, entry_list_1.DeepCopy());
+  policy_map1.Set(key::kExtensionInstallBlacklist, entry_list_1.DeepCopy());
+
+  auto policy_bundle2 = std::make_unique<PolicyBundle>();
+  PolicyMap& policy_map2 = policy_bundle2->Get(chrome_namespace);
+  PolicyMap::Entry entry_list_2(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                                POLICY_SOURCE_CLOUD, std::move(list2), nullptr);
+  PolicyMap::Entry entry_list_3(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                                POLICY_SOURCE_CLOUD, std::move(list3), nullptr);
+  policy_map2.Set(key::kExtensionInstallForcelist, entry_list_2.DeepCopy());
+  policy_map2.Set(key::kExtensionInstallBlacklist, entry_list_2.DeepCopy());
+  policy_map2.Set(key::kExtensionInstallWhitelist, entry_list_3.DeepCopy());
+
+  PolicyMap expected_chrome;
+  expected_chrome.Set(key::kPolicyListMultipleSourceMergeList,
+                      POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                      POLICY_SOURCE_PLATFORM,
+                      base::Value::ToUniquePtrValue(policy->Clone()), nullptr);
+
+  PolicyMap::Entry merged(POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+                          POLICY_SOURCE_MERGED, std::move(result), nullptr);
+  merged.AddConflictingPolicy(entry_list_2.DeepCopy());
+  merged.AddConflictingPolicy(entry_list_1.DeepCopy());
+  expected_chrome.Set(key::kExtensionInstallForcelist, merged.DeepCopy());
+  expected_chrome.Set(key::kExtensionInstallBlacklist, std::move(merged));
+  entry_list_3.SetIgnoredByPolicyAtomicGroup();
+  expected_chrome.Set(key::kExtensionInstallWhitelist, std::move(entry_list_3));
+
+  provider0_.UpdatePolicy(std::move(policy_bundle1));
+  provider1_.UpdatePolicy(std::move(policy_bundle2));
+  RunUntilIdle();
+
+  EXPECT_TRUE(VerifyPolicies(chrome_namespace, expected_chrome));
+}
+
 }  // namespace policy
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index c8f5263..644310a 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -239,6 +239,14 @@
 #   document a differing default value for devices enrolled into enterprise
 #   management. This is for documentation only - the enrollment-dependent
 #   handling must be manually implemented.
+#
+# Atomic Policy Group:
+#   An atomic policy group is a group of policies that logically belong together and influence
+#   a certain aspect of the browser only when considered together and should be treated as a single policy
+#   when merging policies from multiple sources. They all have to be set in the same
+#   source to take effect. In case members of a policy group are set at different sources,
+#   only the policies from the source with the highest priority will be used.
+#
 
   'risk_tag_definitions' : [
     # All following tags are ordered by severity of their impact.
@@ -11487,6 +11495,8 @@
       See https://developers.google.com/safe-browsing for more info on Safe Browsing.''',
     },
     {
+      # TODO(nikitapodguzov): Move the ppd_resource properties description to
+      # the schema after adding display of schemas in the HTML page.
       'name': 'NativePrinters',
       'type': 'list',
       'schema': {
@@ -11509,7 +11519,8 @@
               'type': 'object',
               'id': 'PpdResource',
               'properties': {
-                'effective_model': { 'type': 'string' }
+                'effective_model': { 'type': 'string' },
+                'autoconf': { 'type': 'boolean' }
               }
             }
           }
@@ -11531,7 +11542,7 @@
         '"model": "Color Laser 2004", '
         '"uri": "ipps://print-server.intranet.example.com:443/ipp/cl2k4", '
         '"uuid": "1c395fdb-5d93-4904-b246-b2c046e79d12", '
-        '"ppd_resource": { "effective_model": "Printer Manufacturer ColorLaser2k4" } '
+        '"ppd_resource": { "effective_model": "Printer Manufacturer ColorLaser2k4", "autoconf": false } '
         '}'
       ],
       'id': 350,
@@ -11546,6 +11557,10 @@
 
       <ph name="PRINTER_EFFECTIVE_MODEL">effective_model</ph> must match one of the strings which represent a <ph name="PRODUCT_NAME">$2<ex>Google Chrome OS</ex></ph> supported printer. The string will be used to identify and install the appropriate PPD for the printer. More information can be found at https://support.google.com/chrome?p=noncloudprint.
 
+      <ph name="PRINTER_AUTOCONF">autoconf</ph> is a boolean flag indicating whether IPP Everywhere should be used to setup the printer. This flag is supported on <ph name="PRODUCT_OS_NAME">$2<ex>Google Chrome OS</ex></ph> version 76 and higher.
+
+      Either <ph name="PRINTER_EFFECTIVE_MODEL">effective_model</ph> should contain the name of the printer or <ph name="PRINTER_AUTOCONF">autoconf</ph> should be set to true. The printers with both or without any properties will be ignored.
+
       Printer setup is completed upon the first use of a printer.  PPDs are not downloaded until the printer is used.  After that time, frequently used PPDs are cached.
 
       This policy has no effect on whether users can configure printers on individual devices.  It is intended to be supplementary to the configuration of printers by individual users.
@@ -16211,6 +16226,367 @@
     'DeviceBatteryChargeCustomStopCharging': 'device_battery_charge_mode.custom_charge_stop',
     'DeviceScheduledUpdateCheck': 'device_scheduled_update_check.device_scheduled_update_check_settings'
   },
+  'policy_atomic_group_definitions': [
+    {
+      'name': 'Homepage',
+      'policies': [
+        'HomepageLocation',
+        'HomepageIsNewTabPage',
+        'NewTabPageLocation',
+        'ShowHomeButton',
+      ],
+    },
+    {
+      'name': 'RemoteAccess',
+      'policies': [
+        'RemoteAccessClientFirewallTraversal',
+        'RemoteAccessHostClientDomain',
+        'RemoteAccessHostClientDomainList',
+        'RemoteAccessHostFirewallTraversal',
+        'RemoteAccessHostDomain',
+        'RemoteAccessHostDomainList',
+        'RemoteAccessHostRequireTwoFactor',
+        'RemoteAccessHostTalkGadgetPrefix',
+        'RemoteAccessHostRequireCurtain',
+        'RemoteAccessHostAllowClientPairing',
+        'RemoteAccessHostAllowGnubbyAuth',
+        'RemoteAccessHostAllowRelayedConnection',
+        'RemoteAccessHostUdpPortRange',
+        'RemoteAccessHostMatchUsername',
+        'RemoteAccessHostTokenUrl',
+        'RemoteAccessHostTokenValidationUrl',
+        'RemoteAccessHostTokenValidationCertificateIssuer',
+        'RemoteAccessHostDebugOverridePolicies',
+        'RemoteAccessHostAllowUiAccessForRemoteAssistance',
+        'RemoteAccessHostAllowFileTransfer',
+      ],
+    },
+    {
+      'name': 'PasswordManager',
+      'policies': [
+        'PasswordManagerEnabled',
+        'PasswordManagerAllowShowPasswords',
+      ],
+    },
+    {
+      'name': 'Proxy',
+      'policies': [
+        'ProxyMode',
+        'ProxyServerMode',
+        'ProxyServer',
+        'ProxyPacUrl',
+        'ProxyBypassList',
+        'ProxySettings',
+      ],
+    },
+    {
+      'name': 'Extensions',
+      'policies': [
+        'ExtensionInstallBlacklist',
+        'ExtensionInstallWhitelist',
+        'ExtensionInstallForcelist',
+        'ExtensionInstallSources',
+        'ExtensionAllowedTypes',
+        'ExtensionAllowInsecureUpdates',
+        'ExtensionSettings',
+      ],
+    },
+    {
+      'name': 'RestoreOnStartupGroup',
+      'policies': [
+        'RestoreOnStartup',
+        'RestoreOnStartupURLs',
+      ],
+    },
+    {
+      'name': 'DefaultSearchProvider',
+      'policies': [
+        'DefaultSearchProviderEnabled',
+        'DefaultSearchProviderName',
+        'DefaultSearchProviderKeyword',
+        'DefaultSearchProviderSearchURL',
+        'DefaultSearchProviderSuggestURL',
+        'DefaultSearchProviderInstantURL',
+        'DefaultSearchProviderIconURL',
+        'DefaultSearchProviderEncodings',
+        'DefaultSearchProviderAlternateURLs',
+        'DefaultSearchProviderSearchTermsReplacementKey',
+        'DefaultSearchProviderImageURL',
+        'DefaultSearchProviderNewTabURL',
+        'DefaultSearchProviderSearchURLPostParams',
+        'DefaultSearchProviderSuggestURLPostParams',
+        'DefaultSearchProviderInstantURLPostParams',
+        'DefaultSearchProviderImageURLPostParams',
+      ],
+    },
+    {
+      'name': 'ImageSettings',
+      'policies': [
+        'DefaultImagesSetting',
+        'ImagesAllowedForUrls',
+        'ImagesBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'CookiesSettings',
+      'policies': [
+        'DefaultCookiesSetting',
+        'CookiesAllowedForUrls',
+        'CookiesBlockedForUrls',
+        'CookiesSessionOnlyForUrls',
+      ],
+    },
+    {
+      'name': 'JavascriptSettings',
+      'policies': [
+        'DefaultJavaScriptSetting',
+        'JavaScriptAllowedForUrls',
+        'JavaScriptBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'PluginsSettings',
+      'policies': [
+        'DefaultPluginsSetting',
+        'PluginsAllowedForUrls',
+        'PluginsBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'PopupsSettings',
+      'policies': [
+        'DefaultPopupsSetting',
+        'PopupsAllowedForUrls',
+        'PopupsBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'KeygenSettings',
+      'policies': [
+        'DefaultKeygenSetting',
+        'KeygenAllowedForUrls',
+        'KeygenBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'NotificationsSettings',
+      'policies': [
+        'DefaultNotificationsSetting',
+        'NotificationsAllowedForUrls',
+        'NotificationsBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'WebUsbSettings',
+      'policies': [
+        'DefaultWebUsbGuardSetting',
+        'WebUsbAllowDevicesForUrls',
+        'WebUsbAskForUrls',
+        'WebUsbBlockedForUrls',
+      ],
+    },
+    {
+      'name': 'NativeMessaging',
+      'policies': [
+        'NativeMessagingBlacklist',
+        'NativeMessagingWhitelist',
+        'NativeMessagingUserLevelHosts',
+      ],
+    },
+    {
+      'name': 'Drive',
+      'policies': [
+        'DriveDisabled',
+        'DriveDisabledOverCellular',
+      ],
+    },
+    {
+      'name': 'Attestation',
+      'policies': [
+        'AttestationEnabledForDevice',
+        'AttestationEnabledForUser',
+        'AttestationExtensionWhitelist',
+        'AttestationForContentProtectionEnabled',
+      ],
+    },
+    {
+      'name': 'ContentPack',
+      'policies': [
+        'ContentPackDefaultFilteringBehavior',
+        'ContentPackManualBehaviorHosts',
+        'ContentPackManualBehaviorURLs',
+      ],
+    },
+    {
+      'name': 'SupervisedUsers',
+      'policies': [
+        'SupervisedUsersEnabled',
+        'SupervisedUserCreationEnabled',
+        'SupervisedUserContentProviderEnabled',
+      ],
+    },
+    {
+      'name': 'GoogleCast',
+      'policies': [
+        'CastReceiverEnabled',
+        'CastReceiverName',
+      ],
+    },
+    {
+      'name': 'QuickUnlock',
+      'policies': [
+        'QuickUnlockModeWhitelist',
+        'QuickUnlockTimeout',
+      ],
+    },
+    {
+      'name': 'PinUnlock',
+      'policies': [
+        'PinUnlockMinimumLength',
+        'PinUnlockMaximumLength',
+        'PinUnlockWeakPinsAllowed',
+      ],
+    },
+    {
+      'name': 'SafeBrowsing',
+      'policies': [
+        'SafeBrowsingEnabled',
+        'SafeBrowsingExtendedReportingEnabled',
+        'SafeBrowsingExtendedReportingOptInAllowed',
+        'SafeBrowsingWhitelistDomains',
+      ],
+    },
+    {
+      'name': 'PasswordProtection',
+      'policies': [
+        'PasswordProtectionWarningTrigger',
+        'PasswordProtectionLoginURLs',
+        'PasswordProtectionChangePasswordURL',
+      ],
+    },
+    {
+      'name': 'NetworkFileShares',
+      'policies': [
+        'NetworkFileSharesAllowed',
+        'NetBiosShareDiscoveryEnabled',
+        'NTLMShareAuthenticationEnabled',
+        'NetworkFileSharesPreconfiguredShares',
+      ],
+    },
+    {
+      'name': 'ChromeReportingExtension',
+      'policies': [
+        'ReportVersionData',
+        'ReportPolicyData',
+        'ReportMachineIDData',
+        'ReportUserIDData',
+        'ReportExtensionsAndPluginsData',
+        'ReportSafeBrowsingData',
+        'CloudReportingEnabled',
+      ],
+    },
+    {
+      'name': 'BrowserSwitcher',
+      'policies': [
+        'AlternativeBrowserPath',
+        'AlternativeBrowserParameters',
+        'BrowserSwitcherChromePath',
+        'BrowserSwitcherChromeParameters',
+        'BrowserSwitcherDelay',
+        'BrowserSwitcherEnabled',
+        'BrowserSwitcherExternalSitelistUrl',
+        'BrowserSwitcherKeepLastChromeTab',
+        'BrowserSwitcherUrlList',
+        'BrowserSwitcherUrlGreylist',
+        'BrowserSwitcherUseIeSitelist',
+      ],
+    },
+    {
+      'name': 'PluginVm',
+      'policies': [
+        'PluginVmAllowed',
+        'PluginVmLicenseKey',
+        'PluginVmImage',
+      ],
+    },
+    {
+      'name': 'DeviceSAML',
+      'policies': [
+        'DeviceSamlLoginAuthenticationType',
+        'DeviceTransferSAMLCookies',
+      ],
+    },
+    {
+      'name': 'DeviceLoginScreenOrigins',
+      'policies': [
+        'DeviceLoginScreenIsolateOrigins',
+        'DeviceLoginScreenSitePerProcess',
+      ],
+    },
+    {
+      'name': 'UserAndDeviceReporting',
+      'policies': [
+        'ReportDeviceVersionInfo',
+        'ReportDeviceBootMode',
+        'ReportDeviceUsers',
+        'ReportDeviceActivityTimes',
+        'ReportDeviceLocation',
+        'ReportDeviceNetworkInterfaces',
+        'ReportDeviceHardwareStatus',
+        'ReportDeviceSessionStatus',
+        'ReportDeviceBoardStatus',
+        'ReportDevicePowerStatus',
+        'ReportDeviceStorageStatus',
+        'ReportUploadFrequency',
+        'ReportArcStatusEnabled',
+        'HeartbeatEnabled',
+        'HeartbeatFrequency',
+        'LogUploadEnabled',
+        'DeviceMetricsReportingEnabled',
+      ],
+    },
+    {
+      'name': 'DeviceWiFi',
+      'policies': [
+        'DeviceWiFiFastTransitionEnabled',
+        'DeviceWiFiAllowed'
+      ],
+    },
+    {
+      'name': 'Kiosk',
+      'policies': [
+        'DeviceLocalAccounts',
+        'DeviceLocalAccountAutoLoginId',
+        'DeviceLocalAccountAutoLoginDelay',
+        'DeviceLocalAccountAutoLoginBailoutEnabled',
+        'DeviceLocalAccountPromptForNetworkWhenOffline',
+      ],
+    },
+    {
+      'name': 'DateAndTime',
+      'policies': [
+        'SystemTimezone',
+        'SystemTimezoneAutomaticDetection',
+      ]
+    },
+    {
+      'name': 'Display',
+      'policies': [
+        'DeviceDisplayResolution',
+        'DisplayRotationDefault',
+      ]
+    },
+    {
+      'name': 'ActiveDirectoryManagement',
+      'policies': [
+        'DeviceMachinePasswordChangeRate',
+        'DeviceUserPolicyLoopbackProcessingMode',
+        'DeviceKerberosEncryptionTypes',
+        'DeviceGpoCacheLifetime',
+        'DeviceAuthDataCacheLifetime',
+      ]
+    },
+  ],
   'placeholders': [],
   'deleted_policy_ids': [412],
   'highest_id_currently_used':  561
diff --git a/components/policy/tools/generate_policy_source.py b/components/policy/tools/generate_policy_source.py
index d89a8da..8411d46 100755
--- a/components/policy/tools/generate_policy_source.py
+++ b/components/policy/tools/generate_policy_source.py
@@ -159,6 +159,32 @@
     return result
 
 
+class PolicyAtomicGroup:
+  """Parses a policy atomic group and caches its name and policy names"""
+
+  def __init__(self, policy_group, available_policies,
+               policies_already_in_group):
+    self.name = policy_group['name']
+    self.policies = policy_group.get('policies', None)
+    self._CheckPoliciesValidity(available_policies, policies_already_in_group)
+
+  def _CheckPoliciesValidity(self, available_policies,
+                             policies_already_in_group):
+    if self.policies == None or len(self.policies) <= 0:
+      raise RuntimeError('Atomic policy group ' + self.name +
+                         ' has to contain a list of '
+                         'policies!\n')
+    for policy in self.policies:
+      if policy in policies_already_in_group:
+        raise RuntimeError('Policy: ' + policy +
+                           ' cannot be in more than one atomic group '
+                           'in policy_templates.json)!')
+      policies_already_in_group.add(policy)
+      if not policy in available_policies:
+        raise RuntimeError('Invalid policy:' + policy + ' in atomic group ' +
+                           self.name + '.\n')
+
+
 def ParseVersionFile(version_path):
   major_version = None
   for line in open(version_path, 'r').readlines():
@@ -261,12 +287,23 @@
   risk_tags.ComputeMaxTags(policy_details)
   sorted_policy_details = sorted(policy_details, key=lambda policy: policy.name)
 
+  policy_details_set = map((lambda x: x.name), policy_details)
+  policies_already_in_group = set()
+  policy_atomic_groups = [
+      PolicyAtomicGroup(group, policy_details_set, policies_already_in_group)
+      for group in template_file_contents['policy_atomic_group_definitions']
+  ]
+  sorted_policy_atomic_groups = sorted(
+      policy_atomic_groups, key=lambda group: group.name)
+
+
   def GenerateFile(path, writer, sorted=False, xml=False):
     if path:
       with open(path, 'w') as f:
         _OutputGeneratedWarningHeader(f, template_file_name, xml)
-        writer(sorted and sorted_policy_details or policy_details, os, f,
-               risk_tags)
+        writer(sorted and sorted_policy_details or policy_details,
+               sorted and sorted_policy_atomic_groups or policy_atomic_groups,
+               os, f, risk_tags)
 
   if opts.header_path:
     GenerateFile(opts.header_path, _WritePolicyConstantHeader, sorted=True)
@@ -350,7 +387,8 @@
 #------------------ policy constants header ------------------------#
 
 
-def _WritePolicyConstantHeader(policies, os, f, risk_tags):
+def _WritePolicyConstantHeader(policies, policy_atomic_groups, os, f,
+                               risk_tags):
   f.write('#ifndef CHROME_COMMON_POLICY_CONSTANTS_H_\n'
           '#define CHROME_COMMON_POLICY_CONSTANTS_H_\n'
           '\n'
@@ -395,6 +433,19 @@
     f.write('extern const char k' + policy.name + '[];\n')
   f.write('\n}  // namespace key\n\n')
 
+  f.write('// Group names for the policy settings.\n' 'namespace group {\n\n')
+  for group in policy_atomic_groups:
+    f.write('extern const char k' + group.name + '[];\n')
+  f.write('\n}  // namespace group\n\n')
+
+  f.write('struct AtomicGroup {\n'
+          '  const char* policy_group;\n'
+          '  const char* const* policies;\n'
+          '};\n\n')
+
+  f.write('extern const AtomicGroup kPolicyAtomicGroupMappings[];\n\n')
+  f.write('extern const size_t kPolicyAtomicGroupMappingsLength;\n\n')
+
   f.write('enum class StringPolicyType {\n'
           '  STRING,\n'
           '  JSON,\n'
@@ -891,7 +942,8 @@
   return [], None
 
 
-def _WritePolicyConstantSource(policies, os, f, risk_tags):
+def _WritePolicyConstantSource(policies, policy_atomic_groups, os, f,
+                               risk_tags):
   f.write('#include "components/policy/policy_constants.h"\n'
           '\n'
           '#include <algorithm>\n'
@@ -1053,6 +1105,30 @@
     f.write('const char k{name}[] = "{name}";\n'.format(name=policy.name))
   f.write('\n}  // namespace key\n\n')
 
+  f.write('namespace group {\n\n')
+  for group in policy_atomic_groups:
+    f.write('const char k{name}[] = "{name}";\n'.format(name=group.name))
+  f.write('\n')
+  f.write('namespace {\n\n')
+  for group in policy_atomic_groups:
+    f.write('const char* const %s[] = {' % (group.name))
+    for policy in group.policies:
+      f.write('key::k%s, ' % (policy))
+    f.write('nullptr};\n')
+  f.write('\n}  // namespace\n')
+  f.write('\n}  // namespace group\n\n')
+
+  atomic_groups_length = 0
+  f.write('const AtomicGroup kPolicyAtomicGroupMappings[] = {\n')
+  for group in policy_atomic_groups:
+    atomic_groups_length += 1
+    f.write('  {')
+    f.write('  group::k{name}, group::{name}'.format(name=group.name))
+    f.write('  },\n')
+  f.write('};\n\n')
+  f.write('const size_t kPolicyAtomicGroupMappingsLength = %s;\n\n' %
+          (atomic_groups_length))
+
   supported_user_policies = [
       p for p in policies if p.is_supported and not p.is_device_only
   ]
@@ -1153,7 +1229,7 @@
           "-", "_").upper()
 
 
-def _WritePolicyRiskTagHeader(policies, os, f, risk_tags):
+def _WritePolicyRiskTagHeader(policies, policy_atomic_groups, os, f, risk_tags):
   f.write('#ifndef CHROME_COMMON_POLICY_RISK_TAG_H_\n'
           '#define CHROME_COMMON_POLICY_RISK_TAG_H_\n'
           '\n'
@@ -1267,7 +1343,8 @@
   ]
 
 
-def _WriteChromeSettingsProtobuf(policies, os, f, risk_tags):
+def _WriteChromeSettingsProtobuf(policies, policy_atomic_groups, os, f,
+                                 risk_tags):
   f.write(CHROME_SETTINGS_PROTO_HEAD)
   fields = []
   f.write('// PBs for individual settings.\n\n')
@@ -1284,7 +1361,8 @@
   f.write('}\n\n')
 
 
-def _WriteChromeSettingsFullRuntimeProtobuf(policies, os, f, risk_tags):
+def _WriteChromeSettingsFullRuntimeProtobuf(policies, policy_atomic_groups, os,
+                                            f, risk_tags):
   # For full runtime, disable LITE_RUNTIME switch and import full runtime
   # version of cloud_policy.proto.
   f.write(
@@ -1308,7 +1386,7 @@
   f.write('}\n\n')
 
 
-def _WriteCloudPolicyProtobuf(policies, os, f, risk_tags):
+def _WriteCloudPolicyProtobuf(policies, policy_atomic_groups, os, f, risk_tags):
   f.write(CLOUD_POLICY_PROTO_HEAD)
   f.write('message CloudPolicySettings {\n')
   for policy in policies:
@@ -1319,7 +1397,8 @@
   f.write('}\n\n')
 
 
-def _WriteCloudPolicyFullRuntimeProtobuf(policies, os, f, risk_tags):
+def _WriteCloudPolicyFullRuntimeProtobuf(policies, policy_atomic_groups, os, f,
+                                         risk_tags):
   # For full runtime, disable LITE_RUNTIME switch
   f.write(
       CLOUD_POLICY_PROTO_HEAD.replace("option optimize_for = LITE_RUNTIME;",
@@ -1385,7 +1464,8 @@
 
 
 # Writes policy_constants.h for use in Chrome OS.
-def _WriteChromeOSPolicyConstantsHeader(policies, os, f, risk_tags):
+def _WriteChromeOSPolicyConstantsHeader(policies, policy_atomic_groups, os, f,
+                                        risk_tags):
   f.write('#ifndef __BINDINGS_POLICY_CONSTANTS_H_\n'
           '#define __BINDINGS_POLICY_CONSTANTS_H_\n\n')
 
@@ -1437,7 +1517,8 @@
 
 
 # Writes policy_constants.cc for use in Chrome OS.
-def _WriteChromeOSPolicyConstantsSource(policies, os, f, risk_tags):
+def _WriteChromeOSPolicyConstantsSource(policies, policy_atomic_groups, os, f,
+                                        risk_tags):
   f.write('#include "bindings/cloud_policy.pb.h"\n'
           '#include "bindings/policy_constants.h"\n\n'
           'namespace em = enterprise_management;\n\n'
@@ -1469,7 +1550,7 @@
 #------------------ app restrictions -------------------------------#
 
 
-def _WriteAppRestrictions(policies, os, f, risk_tags):
+def _WriteAppRestrictions(policies, policy_atomic_groups, os, f, risk_tags):
 
   def WriteRestrictionCommon(key):
     f.write('    <restriction\n' '        android:key="%s"\n' % key)
diff --git a/components/policy/tools/syntax_check_policy_template_json.py b/components/policy/tools/syntax_check_policy_template_json.py
index 848297d..46c2725 100755
--- a/components/policy/tools/syntax_check_policy_template_json.py
+++ b/components/policy/tools/syntax_check_policy_template_json.py
@@ -769,8 +769,17 @@
         parent_element=None,
         container_name='The root element',
         offending=None)
+    policy_atomic_group_definitions = self._CheckContains(
+        data,
+        'policy_atomic_group_definitions',
+        list,
+        parent_element=None,
+        container_name='The root element',
+        offending=None)
+
     self._CheckDevicePolicyProtoMappingUniqueness(
         device_policy_proto_map, legacy_device_policy_proto_map)
+
     if policy_definitions is not None:
       policy_ids = set()
       for policy in policy_definitions:
@@ -803,6 +812,20 @@
         else:
           policy_in_groups.add(policy_name)
 
+    policy_in_atomic_groups = set()
+    for group in policy_atomic_group_definitions:
+      for policy_name in group['policies']:
+        self._CheckContains(
+            policy_names,
+            policy_name,
+            bool,
+            parent_element='policy_definitions')
+        if policy_name in policy_in_atomic_groups:
+          self._Error('Policy %s defined in several atomic policy groups.' %
+                      (policy_name))
+        else:
+          policy_in_atomic_groups.add(policy_name)
+
     # Second part: check formatting.
     self._CheckFormat(filename)
 
diff --git a/components/policy_strings.grdp b/components/policy_strings.grdp
index 06436b4..2d46158 100644
--- a/components/policy_strings.grdp
+++ b/components/policy_strings.grdp
@@ -461,6 +461,9 @@
   <message name="IDS_POLICY_BLOCKED" desc="Text explaining that a policy is blocked, therefore ignored.">
     This policy is blocked, its value will be ignored.
   </message>
+  <message name="IDS_POLICY_IGNORED_BY_GROUP_MERGING" desc="Text explaining that a policy is ignored because another policy of the same group has a higher priority">
+    This policy is ignored because another policy from the same policy group has a higher priority.
+  </message>
   <message name="IDS_POLICY_INVALID_VALUE"  desc="Text explaining that the policy value is invalid">
     Policy value is not valid.
   </message>
diff --git a/components/previews/content/previews_user_data.cc b/components/previews/content/previews_user_data.cc
index e507654..29fd906 100644
--- a/components/previews/content/previews_user_data.cc
+++ b/components/previews/content/previews_user_data.cc
@@ -4,6 +4,8 @@
 
 #include "components/previews/content/previews_user_data.h"
 
+#include "base/rand_util.h"
+
 namespace previews {
 
 const void* const kPreviewsUserDataKey = &kPreviewsUserDataKey;
@@ -15,6 +17,7 @@
 
 PreviewsUserData::PreviewsUserData(const PreviewsUserData& other)
     : page_id_(other.page_id_),
+      random_coin_flip_for_navigation_(base::RandInt(0, 1)),
       navigation_ect_(other.navigation_ect_),
       data_savings_inflation_percent_(other.data_savings_inflation_percent_),
       cache_control_no_transform_directive_(
@@ -23,7 +26,8 @@
       black_listed_for_lite_page_(other.black_listed_for_lite_page_),
       committed_previews_type_(other.committed_previews_type_),
       allowed_previews_state_(other.allowed_previews_state_),
-      committed_previews_state_(other.committed_previews_state_) {
+      committed_previews_state_(other.committed_previews_state_),
+      coin_flip_holdback_result_(other.coin_flip_holdback_result_) {
   if (other.server_lite_page_info_) {
     server_lite_page_info_ =
         std::make_unique<ServerLitePageInfo>(*other.server_lite_page_info_);
@@ -41,4 +45,8 @@
   committed_previews_type_ = previews_type;
 }
 
+void PreviewsUserData::SetRandomCoinFlipForNavigationForTesting(bool decision) {
+  random_coin_flip_for_navigation_ = decision;
+}
+
 }  // namespace previews
diff --git a/components/previews/content/previews_user_data.h b/components/previews/content/previews_user_data.h
index 0e6475a..8b43022 100644
--- a/components/previews/content/previews_user_data.h
+++ b/components/previews/content/previews_user_data.h
@@ -52,6 +52,11 @@
   // A session unique ID related to this navigation.
   uint64_t page_id() const { return page_id_; }
 
+  // A random bool that is used in the coin flip holdback logic.
+  bool random_coin_flip_for_navigation() const {
+    return random_coin_flip_for_navigation_;
+  }
+
   // The effective connection type value for the navigation.
   net::EffectiveConnectionType navigation_ect() const {
     return navigation_ect_;
@@ -112,6 +117,9 @@
   // Sets the committed previews type for testing. Can be called multiple times.
   void SetCommittedPreviewsTypeForTesting(previews::PreviewsType previews_type);
 
+  // Sets |random_coin_flip_for_navigation_| for testing;
+  void SetRandomCoinFlipForNavigationForTesting(bool decision);
+
   bool offline_preview_used() const { return offline_preview_used_; }
   // Whether an offline preview is being served.
   void set_offline_preview_used(bool offline_preview_used) {
@@ -136,6 +144,15 @@
     committed_previews_state_ = committed_previews_state;
   }
 
+  // The result of a coin flip (if present) for this page load.
+  CoinFlipHoldbackResult coin_flip_holdback_result() {
+    return coin_flip_holdback_result_;
+  }
+  void set_coin_flip_holdback_result(
+      CoinFlipHoldbackResult coin_flip_holdback_result) {
+    coin_flip_holdback_result_ = coin_flip_holdback_result;
+  }
+
   // Metadata for an attempted or committed Lite Page Redirect preview.
   ServerLitePageInfo* server_lite_page_info() {
     return server_lite_page_info_.get();
@@ -148,6 +165,10 @@
   // A session unique ID related to this navigation.
   const uint64_t page_id_;
 
+  // A random bool that is set once for a navigation and used in the coin flip
+  // holdback logic.
+  bool random_coin_flip_for_navigation_;
+
   // The effective connection type at the time of navigation. This is the value
   // to compare to the preview's triggering ect threshold.
   net::EffectiveConnectionType navigation_ect_ =
@@ -179,6 +200,10 @@
   // The PreviewsState that was committed for the navigation.
   content::PreviewsState committed_previews_state_ = content::PREVIEWS_OFF;
 
+  // The state of a random coin flip holdback, if any.
+  CoinFlipHoldbackResult coin_flip_holdback_result_ =
+      CoinFlipHoldbackResult::kNotSet;
+
   // Metadata for an attempted or committed Lite Page Redirect preview. See
   // struct comments for more detail.
   std::unique_ptr<ServerLitePageInfo> server_lite_page_info_;
diff --git a/components/previews/core/previews_experiments.cc b/components/previews/core/previews_experiments.cc
index 6af6e4a..7218cbd 100644
--- a/components/previews/core/previews_experiments.cc
+++ b/components/previews/core/previews_experiments.cc
@@ -393,6 +393,11 @@
       100);
 }
 
+bool ShouldOverrideCoinFlipHoldbackResult() {
+  return base::GetFieldTrialParamByFeatureAsBool(
+      features::kCoinFlipHoldback, "force_coin_flip_always_holdback", false);
+}
+
 }  // namespace params
 
 std::string GetStringNameForType(PreviewsType type) {
diff --git a/components/previews/core/previews_experiments.h b/components/previews/core/previews_experiments.h
index 53cc42e..38b2146 100644
--- a/components/previews/core/previews_experiments.h
+++ b/components/previews/core/previews_experiments.h
@@ -50,6 +50,20 @@
   LAST = 9,
 };
 
+enum class CoinFlipHoldbackResult {
+  // Either the page load was not eligible for any previews, or the coin flip
+  // holdback experiment was disabled.
+  kNotSet = 0,
+
+  // A preview was likely for the page load, and a random coin flip allowed the
+  // preview to be shown to the user.
+  kAllowed = 1,
+
+  // A preview was likely for the page load, and a random coin flip did not
+  // allow the preview to be shown to the user.
+  kHoldback = 2,
+};
+
 typedef std::vector<std::pair<PreviewsType, int>> PreviewsTypeList;
 
 // Gets the string representation of |type|.
@@ -199,6 +213,9 @@
 // PreviewsOfflineHelper.
 size_t OfflinePreviewsHelperMaxPrefSize();
 
+// Forces the coin flip holdback, if enabled, to always come up "holdback".
+bool ShouldOverrideCoinFlipHoldbackResult();
+
 }  // namespace params
 
 }  // namespace previews
diff --git a/components/previews/core/previews_features.cc b/components/previews/core/previews_features.cc
index c4927c84..a2cafb4 100644
--- a/components/previews/core/previews_features.cc
+++ b/components/previews/core/previews_features.cc
@@ -114,5 +114,9 @@
     "OfflinePreviewsFalsePositivePrevention",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enables a per-page load holdback experiment using a random coin flip.
+const base::Feature kCoinFlipHoldback{"PreviewsCoinFlipHoldback_UKMOnly",
+                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace previews
diff --git a/components/previews/core/previews_features.h b/components/previews/core/previews_features.h
index 25478c3..92b8cae 100644
--- a/components/previews/core/previews_features.h
+++ b/components/previews/core/previews_features.h
@@ -27,6 +27,7 @@
 extern const base::Feature kPreviewsReloadsAreSoftOptOuts;
 extern const base::Feature kOptimizationHintsFetching;
 extern const base::Feature kOfflinePreviewsFalsePositivePrevention;
+extern const base::Feature kCoinFlipHoldback;
 
 }  // namespace features
 }  // namespace previews
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn
index f977166..0fc603c1 100644
--- a/components/search_engines/BUILD.gn
+++ b/components/search_engines/BUILD.gn
@@ -17,8 +17,6 @@
     "keyword_table.h",
     "keyword_web_data_service.cc",
     "keyword_web_data_service.h",
-    "search_engine_data_type_controller.cc",
-    "search_engine_data_type_controller.h",
     "search_engines_pref_names.cc",
     "search_engines_pref_names.h",
     "search_engines_switches.cc",
@@ -122,7 +120,6 @@
   sources = [
     "default_search_manager_unittest.cc",
     "keyword_table_unittest.cc",
-    "search_engine_data_type_controller_unittest.cc",
     "search_host_to_urls_map_unittest.cc",
     "template_url_data_unittest.cc",
     "template_url_prepopulate_data_unittest.cc",
diff --git a/components/search_engines/search_engine_data_type_controller.cc b/components/search_engines/search_engine_data_type_controller.cc
deleted file mode 100644
index d1627a53..0000000
--- a/components/search_engines/search_engine_data_type_controller.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/search_engines/search_engine_data_type_controller.h"
-
-#include "base/bind.h"
-#include "base/threading/thread_task_runner_handle.h"
-
-namespace browser_sync {
-
-SearchEngineDataTypeController::SearchEngineDataTypeController(
-    const base::Closure& dump_stack,
-    syncer::SyncService* sync_service,
-    syncer::SyncClient* sync_client,
-    TemplateURLService* template_url_service)
-    : AsyncDirectoryTypeController(syncer::SEARCH_ENGINES,
-                                   dump_stack,
-                                   sync_service,
-                                   sync_client,
-                                   syncer::GROUP_UI,
-                                   base::ThreadTaskRunnerHandle::Get()),
-      template_url_service_(template_url_service) {}
-
-TemplateURLService::Subscription*
-SearchEngineDataTypeController::GetSubscriptionForTesting() {
-  return template_url_subscription_.get();
-}
-
-SearchEngineDataTypeController::~SearchEngineDataTypeController() {}
-
-// We want to start the TemplateURLService before we begin associating.
-bool SearchEngineDataTypeController::StartModels() {
-  DCHECK(CalledOnValidThread());
-  // If the TemplateURLService is loaded, continue with association. We force
-  // a load here to prevent the rest of Sync from waiting on
-  // TemplateURLService's lazy load.
-  DCHECK(template_url_service_);
-  template_url_service_->Load();
-  if (template_url_service_->loaded()) {
-    return true;  // Continue to Associate().
-  }
-
-  // Register a callback and continue when the TemplateURLService is loaded.
-  template_url_subscription_ = template_url_service_->RegisterOnLoadedCallback(
-      base::Bind(&SearchEngineDataTypeController::OnTemplateURLServiceLoaded,
-                 base::AsWeakPtr(this)));
-
-  return false;  // Don't continue Start.
-}
-
-void SearchEngineDataTypeController::StopModels() {
-  DCHECK(CalledOnValidThread());
-  template_url_subscription_.reset();
-}
-
-void SearchEngineDataTypeController::OnTemplateURLServiceLoaded() {
-  DCHECK(CalledOnValidThread());
-  DCHECK_EQ(MODEL_STARTING, state());
-  template_url_subscription_.reset();
-  OnModelLoaded();
-}
-
-}  // namespace browser_sync
diff --git a/components/search_engines/search_engine_data_type_controller.h b/components/search_engines/search_engine_data_type_controller.h
deleted file mode 100644
index 7c5dc733..0000000
--- a/components/search_engines/search_engine_data_type_controller.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINE_DATA_TYPE_CONTROLLER_H__
-#define COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINE_DATA_TYPE_CONTROLLER_H__
-
-#include <memory>
-#include <string>
-
-#include "base/macros.h"
-#include "components/search_engines/template_url_service.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-
-namespace syncer {
-class SyncClient;
-class SyncService;
-}  // namespace syncer
-
-namespace browser_sync {
-
-// Controller for the SEARCH_ENGINES sync data type. This class tells sync
-// how to load the model for this data type, and the superclasses manage
-// controlling the rest of the state of the datatype with regards to sync.
-class SearchEngineDataTypeController
-    : public syncer::AsyncDirectoryTypeController {
- public:
-  // |dump_stack| is called when an unrecoverable error occurs.
-  SearchEngineDataTypeController(const base::Closure& dump_stack,
-                                 syncer::SyncService* sync_service,
-                                 syncer::SyncClient* sync_client,
-                                 TemplateURLService* template_url_service);
-  ~SearchEngineDataTypeController() override;
-
-  TemplateURLService::Subscription* GetSubscriptionForTesting();
-
- private:
-  // AsyncDirectoryTypeController:
-  bool StartModels() override;
-  void StopModels() override;
-
-  void OnTemplateURLServiceLoaded();
-
-  // A pointer to the template URL service that this data type will use.
-  TemplateURLService* template_url_service_;
-
-  // A subscription to the OnLoadedCallback so it can be cleared if necessary.
-  std::unique_ptr<TemplateURLService::Subscription> template_url_subscription_;
-
-  DISALLOW_COPY_AND_ASSIGN(SearchEngineDataTypeController);
-};
-
-}  // namespace browser_sync
-
-#endif  // COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINE_DATA_TYPE_CONTROLLER_H__
diff --git a/components/search_engines/search_engine_data_type_controller_unittest.cc b/components/search_engines/search_engine_data_type_controller_unittest.cc
deleted file mode 100644
index 52f9c3e3..0000000
--- a/components/search_engines/search_engine_data_type_controller_unittest.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/search_engines/search_engine_data_type_controller.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/memory/ptr_util.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/test/scoped_task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/search_engines/template_url_service.h"
-#include "components/sync/driver/configure_context.h"
-#include "components/sync/driver/data_type_controller_mock.h"
-#include "components/sync/driver/fake_generic_change_processor.h"
-#include "components/sync/driver/fake_sync_service.h"
-#include "components/sync/driver/sync_client_mock.h"
-#include "components/sync/model/fake_syncable_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::DoAll;
-using testing::InvokeWithoutArgs;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace browser_sync {
-namespace {
-
-class SyncSearchEngineDataTypeControllerTest : public testing::Test {
- public:
-  SyncSearchEngineDataTypeControllerTest()
-      : template_url_service_(nullptr, 0),
-        search_engine_dtc_(base::RepeatingClosure(),
-                           &sync_service_,
-                           &sync_client_,
-                           &template_url_service_) {
-    // Disallow the TemplateURLService from loading until
-    // PreloadTemplateURLService() is called .
-    template_url_service_.set_disable_load(true);
-
-    ON_CALL(sync_client_, GetSyncableServiceForType(syncer::SEARCH_ENGINES))
-        .WillByDefault(testing::Return(syncable_service_.AsWeakPtr()));
-  }
-
-  void TearDown() override {
-    // Must be done before we pump the loop.
-    syncable_service_.StopSyncing(syncer::SEARCH_ENGINES);
-  }
-
- protected:
-  void PreloadTemplateURLService() {
-    template_url_service_.set_disable_load(false);
-    template_url_service_.Load();
-  }
-
-  void SetStartExpectations() {
-    search_engine_dtc_.SetGenericChangeProcessorFactoryForTest(
-        std::make_unique<syncer::FakeGenericChangeProcessorFactory>(
-            std::make_unique<syncer::FakeGenericChangeProcessor>(
-                syncer::SEARCH_ENGINES)));
-    EXPECT_CALL(model_load_callback_, Run(_, _));
-  }
-
-  void Start() {
-    search_engine_dtc_.LoadModels(
-        syncer::ConfigureContext(),
-        base::Bind(&syncer::ModelLoadCallbackMock::Run,
-                   base::Unretained(&model_load_callback_)));
-    search_engine_dtc_.StartAssociating(base::Bind(
-        &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
-    base::RunLoop().RunUntilIdle();
-  }
-
-  base::test::ScopedTaskEnvironment task_environment_;
-  syncer::FakeSyncService sync_service_;
-  TemplateURLService template_url_service_;
-  syncer::FakeSyncableService syncable_service_;
-  testing::NiceMock<syncer::SyncClientMock> sync_client_;
-  syncer::StartCallbackMock start_callback_;
-  syncer::ModelLoadCallbackMock model_load_callback_;
-  SearchEngineDataTypeController search_engine_dtc_;
-};
-
-TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceReady) {
-  SetStartExpectations();
-  // We want to start ready.
-  PreloadTemplateURLService();
-  EXPECT_CALL(start_callback_, Run(syncer::DataTypeController::OK, _, _));
-
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(syncer::DataTypeController::RUNNING, search_engine_dtc_.state());
-  EXPECT_TRUE(syncable_service_.syncing());
-}
-
-TEST_F(SyncSearchEngineDataTypeControllerTest, StartURLServiceNotReady) {
-  EXPECT_CALL(model_load_callback_, Run(_, _));
-  EXPECT_FALSE(syncable_service_.syncing());
-  search_engine_dtc_.LoadModels(
-      syncer::ConfigureContext(),
-      base::Bind(&syncer::ModelLoadCallbackMock::Run,
-                 base::Unretained(&model_load_callback_)));
-  EXPECT_TRUE(search_engine_dtc_.GetSubscriptionForTesting());
-  EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING,
-            search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-
-  // Send the notification that the TemplateURLService has started.
-  PreloadTemplateURLService();
-  EXPECT_EQ(nullptr, search_engine_dtc_.GetSubscriptionForTesting());
-  EXPECT_EQ(syncer::DataTypeController::MODEL_LOADED,
-            search_engine_dtc_.state());
-
-  // Wait until WebDB is loaded before we shut it down.
-  base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(SyncSearchEngineDataTypeControllerTest, StartAssociationFailed) {
-  SetStartExpectations();
-  PreloadTemplateURLService();
-  EXPECT_CALL(start_callback_,
-              Run(syncer::DataTypeController::ASSOCIATION_FAILED, _, _));
-  syncable_service_.set_merge_data_and_start_syncing_error(
-      syncer::SyncError(FROM_HERE,
-                        syncer::SyncError::DATATYPE_ERROR,
-                        "Error",
-                        syncer::SEARCH_ENGINES));
-
-  Start();
-  EXPECT_EQ(syncer::DataTypeController::FAILED, search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  search_engine_dtc_.Stop(syncer::STOP_SYNC);
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-TEST_F(SyncSearchEngineDataTypeControllerTest, Stop) {
-  SetStartExpectations();
-  PreloadTemplateURLService();
-  EXPECT_CALL(start_callback_, Run(syncer::DataTypeController::OK, _, _));
-
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  Start();
-  EXPECT_EQ(syncer::DataTypeController::RUNNING, search_engine_dtc_.state());
-  EXPECT_TRUE(syncable_service_.syncing());
-  search_engine_dtc_.Stop(syncer::STOP_SYNC);
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            search_engine_dtc_.state());
-  // AsyncDirectoryTypeController::Stop posts call to StopLocalService to model
-  // thread. We run message loop for this call to take effect.
-  base::RunLoop().RunUntilIdle();
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-TEST_F(SyncSearchEngineDataTypeControllerTest, StopBeforeLoaded) {
-  EXPECT_FALSE(syncable_service_.syncing());
-  search_engine_dtc_.LoadModels(
-      syncer::ConfigureContext(),
-      base::Bind(&syncer::ModelLoadCallbackMock::Run,
-                 base::Unretained(&model_load_callback_)));
-  EXPECT_TRUE(search_engine_dtc_.GetSubscriptionForTesting());
-  EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING,
-            search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-  search_engine_dtc_.Stop(syncer::STOP_SYNC);
-  EXPECT_EQ(nullptr, search_engine_dtc_.GetSubscriptionForTesting());
-  EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING,
-            search_engine_dtc_.state());
-  EXPECT_FALSE(syncable_service_.syncing());
-}
-
-}  // namespace
-}  // namespace browser_sync
diff --git a/components/sync/driver/sync_driver_switches.cc b/components/sync/driver/sync_driver_switches.cc
index 5cc1ad0..911f871 100644
--- a/components/sync/driver/sync_driver_switches.cc
+++ b/components/sync/driver/sync_driver_switches.cc
@@ -53,35 +53,6 @@
 const base::Feature kStopSyncInPausedState{"StopSyncInPausedState",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
-// For each below, if enabled, the SyncableService implementation of the
-// corresponding datatype(s) is wrapped within the USS architecture.
-const base::Feature kSyncPseudoUSSAppList{"SyncPseudoUSSAppList",
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSApps{"SyncPseudoUSSApps",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSArcPackage{"SyncPseudoUSSArcPackage",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSDictionary{"SyncPseudoUSSDictionary",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSExtensionSettings{
-    "SyncPseudoUSSExtensionSettings", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSExtensions{"SyncPseudoUSSExtensions",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSFavicons{"SyncPseudoUSSFavicons",
-                                           base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSHistoryDeleteDirectives{
-    "SyncPseudoUSSHistoryDeleteDirectives", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSPreferences{"SyncPseudoUSSPreferences",
-                                              base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSPriorityPreferences{
-    "SyncPseudoUSSPriorityPreferences", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSSearchEngines{
-    "SyncPseudoUSSSearchEngines", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSSupervisedUsers{
-    "SyncPseudoUSSSupervisedUsers", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kSyncPseudoUSSThemes{"SyncPseudoUSSThemes",
-                                         base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls whether a user can receive tabs from their synced devices
 const base::Feature kSyncSendTabToSelf{"SyncSendTabToSelf",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/sync/driver/sync_driver_switches.h b/components/sync/driver/sync_driver_switches.h
index efad97f..b990576 100644
--- a/components/sync/driver/sync_driver_switches.h
+++ b/components/sync/driver/sync_driver_switches.h
@@ -29,19 +29,6 @@
 extern const base::Feature kStopSyncInPausedState;
 extern const base::Feature
     kSyncAllowWalletDataInTransportModeWithCustomPassphrase;
-extern const base::Feature kSyncPseudoUSSAppList;
-extern const base::Feature kSyncPseudoUSSApps;
-extern const base::Feature kSyncPseudoUSSArcPackage;
-extern const base::Feature kSyncPseudoUSSDictionary;
-extern const base::Feature kSyncPseudoUSSExtensionSettings;
-extern const base::Feature kSyncPseudoUSSExtensions;
-extern const base::Feature kSyncPseudoUSSFavicons;
-extern const base::Feature kSyncPseudoUSSHistoryDeleteDirectives;
-extern const base::Feature kSyncPseudoUSSPreferences;
-extern const base::Feature kSyncPseudoUSSPriorityPreferences;
-extern const base::Feature kSyncPseudoUSSSearchEngines;
-extern const base::Feature kSyncPseudoUSSSupervisedUsers;
-extern const base::Feature kSyncPseudoUSSThemes;
 extern const base::Feature kSyncSendTabToSelf;
 extern const base::Feature kSyncSupportSecondaryAccount;
 extern const base::Feature kSyncUSSBookmarks;
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index c8f160b..0b9427b 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -104,23 +104,14 @@
 // information identical to the Directory's value, for the fields that are
 // stored in both. We mostly care about cache GUID and store birthday.
 void RecordConsistencyBetweenDirectoryAndPrefs(
-    syncable::DirOpenResult open_result,
     const syncable::Directory* directory,
     const SyncManager::InitArgs* args) {
   DCHECK(directory);
 
-  std::string directory_cache_guid;
-  std::string directory_birthday;
-
-  // We mimic the directory being empty if it was just opened (OPENED_NEW),
-  // because that means a random cache GUID was just generated and it's not
-  // possible to match empty prefs.
-  DCHECK(open_result == syncable::OPENED_EXISTING ||
-         open_result == syncable::OPENED_NEW);
-  if (open_result == syncable::OPENED_EXISTING) {
-    directory_cache_guid = directory->legacy_cache_guid_for_uma();
-    directory_birthday = directory->legacy_store_birthday_for_uma();
-  }
+  const std::string directory_cache_guid =
+      directory->legacy_cache_guid_for_uma();
+  const std::string directory_birthday =
+      directory->legacy_store_birthday_for_uma();
 
   const StringConsistency cache_guid_consistency =
       CompareStringsForConsistency(args->cache_guid, directory_cache_guid);
@@ -468,7 +459,7 @@
     return false;
   }
 
-  RecordConsistencyBetweenDirectoryAndPrefs(open_result, directory(), args);
+  RecordConsistencyBetweenDirectoryAndPrefs(directory(), args);
 
   // Unapplied datatypes (those that do not have initial sync ended set) get
   // re-downloaded during any configuration. But, it's possible for a datatype
diff --git a/components/viz/common/surfaces/parent_local_surface_id_allocator.cc b/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
index 1f1e19bb..d5d1c1d 100644
--- a/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
+++ b/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
@@ -78,14 +78,6 @@
   return true;
 }
 
-void ParentLocalSurfaceIdAllocator::Reset(
-    const LocalSurfaceId& local_surface_id) {
-  is_invalid_ = false;
-  current_local_surface_id_allocation_.local_surface_id_ = local_surface_id;
-  current_local_surface_id_allocation_.allocation_time_ =
-      tick_clock_->NowTicks();
-}
-
 void ParentLocalSurfaceIdAllocator::Invalidate() {
   is_invalid_ = true;
 }
diff --git a/components/viz/common/surfaces/parent_local_surface_id_allocator.h b/components/viz/common/surfaces/parent_local_surface_id_allocator.h
index 8eb5584..fc0ae59 100644
--- a/components/viz/common/surfaces/parent_local_surface_id_allocator.h
+++ b/components/viz/common/surfaces/parent_local_surface_id_allocator.h
@@ -40,9 +40,6 @@
   bool UpdateFromChild(
       const LocalSurfaceIdAllocation& child_local_surface_id_allocation);
 
-  // Resets this allocator with the provided |local_surface_id| as a seed.
-  void Reset(const LocalSurfaceId& local_surface_id);
-
   // Marks the last known LocalSurfaceId as invalid until the next call to
   // GenerateId. This is used to defer commits until some LocalSurfaceId is
   // provided from an external source.
diff --git a/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc b/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
index 04a3c0a..13d44e2 100644
--- a/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
+++ b/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
@@ -18,16 +18,6 @@
 // - the accessors changed in the way we expected.
 
 namespace viz {
-namespace {
-
-::testing::AssertionResult ParentSequenceNumberIsSet(
-    const LocalSurfaceId& local_surface_id);
-::testing::AssertionResult ChildSequenceNumberIsSet(
-    const LocalSurfaceId& local_surface_id);
-::testing::AssertionResult EmbedTokenIsValid(
-    const LocalSurfaceId& local_surface_id);
-
-}  // namespace
 
 class ParentLocalSurfaceIdAllocatorTest : public testing::Test {
  public:
@@ -133,36 +123,6 @@
   EXPECT_FALSE(allocator().is_allocation_suppressed());
 }
 
-// This test verifies that calling reset with a LocalSurfaceId updates the
-// GetCurrentLocalSurfaceId and affects GenerateId.
-TEST_F(ParentLocalSurfaceIdAllocatorTest, ResetUpdatesComponents) {
-  allocator().GenerateId();
-  LocalSurfaceId default_local_surface_id =
-      allocator().GetCurrentLocalSurfaceIdAllocation().local_surface_id();
-  EXPECT_TRUE(default_local_surface_id.is_valid());
-  EXPECT_TRUE(ParentSequenceNumberIsSet(default_local_surface_id));
-  EXPECT_TRUE(ChildSequenceNumberIsSet(default_local_surface_id));
-  EXPECT_TRUE(EmbedTokenIsValid(default_local_surface_id));
-
-  LocalSurfaceId new_local_surface_id(
-      2u, 2u, base::UnguessableToken::Deserialize(0, 1u));
-
-  allocator().Reset(new_local_surface_id);
-  EXPECT_EQ(
-      new_local_surface_id,
-      allocator().GetCurrentLocalSurfaceIdAllocation().local_surface_id());
-
-  allocator().GenerateId();
-  LocalSurfaceId generated_id =
-      allocator().GetCurrentLocalSurfaceIdAllocation().local_surface_id();
-
-  EXPECT_EQ(generated_id.embed_token(), new_local_surface_id.embed_token());
-  EXPECT_EQ(generated_id.child_sequence_number(),
-            new_local_surface_id.child_sequence_number());
-  EXPECT_EQ(generated_id.parent_sequence_number(),
-            new_local_surface_id.child_sequence_number() + 1);
-}
-
 // This test verifies that if the child-allocated LocalSurfaceId has the most
 // recent parent sequence number at the time UpdateFromChild is called, then
 // its allocation time is used as the latest allocation time in
@@ -205,32 +165,4 @@
   }
 }
 
-namespace {
-
-::testing::AssertionResult ParentSequenceNumberIsSet(
-    const LocalSurfaceId& local_surface_id) {
-  if (local_surface_id.parent_sequence_number() != kInvalidParentSequenceNumber)
-    return ::testing::AssertionSuccess();
-
-  return ::testing::AssertionFailure()
-         << "parent_sequence_number() is not set.";
-}
-
-::testing::AssertionResult ChildSequenceNumberIsSet(
-    const LocalSurfaceId& local_surface_id) {
-  if (local_surface_id.child_sequence_number() != kInvalidChildSequenceNumber)
-    return ::testing::AssertionSuccess();
-
-  return ::testing::AssertionFailure() << "child_sequence_number() is not set.";
-}
-
-::testing::AssertionResult EmbedTokenIsValid(
-    const LocalSurfaceId& local_surface_id) {
-  if (!local_surface_id.embed_token().is_empty())
-    return ::testing::AssertionSuccess();
-
-  return ::testing::AssertionFailure() << "embed_token() is invalid.";
-}
-
-}  // namespace
 }  // namespace viz
diff --git a/components/viz/service/display/vulkan_renderer.cc b/components/viz/service/display/vulkan_renderer.cc
deleted file mode 100644
index 1ddd1d3..0000000
--- a/components/viz/service/display/vulkan_renderer.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display/vulkan_renderer.h"
-
-#include "components/viz/service/display/output_surface.h"
-#include "components/viz/service/display/output_surface_frame.h"
-
-namespace viz {
-
-VulkanRenderer::~VulkanRenderer() {}
-
-void VulkanRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
-  OutputSurfaceFrame output_frame;
-  output_frame.latency_info = std::move(latency_info);
-  output_surface_->SwapBuffers(std::move(output_frame));
-}
-
-VulkanRenderer::VulkanRenderer(const RendererSettings* settings,
-                               OutputSurface* output_surface,
-                               DisplayResourceProvider* resource_provider)
-    : DirectRenderer(settings, output_surface, resource_provider) {}
-
-void VulkanRenderer::DidChangeVisibility() {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::BindFramebufferToOutputSurface() {
-  NOTIMPLEMENTED();
-}
-
-ResourceFormat VulkanRenderer::BackbufferFormat() const {
-  NOTIMPLEMENTED();
-  return RGBA_8888;
-}
-
-void VulkanRenderer::BindFramebufferToTexture(
-    const RenderPassId render_pass_id) {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void VulkanRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::PrepareSurfaceForPass(
-    SurfaceInitializationMode initialization_mode,
-    const gfx::Rect& render_pass_scissor) {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::SetEnableDCLayers(bool enable) {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::DoDrawQuad(const DrawQuad* quad,
-                                const gfx::QuadF* clip_region) {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::BeginDrawingFrame() {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::FinishDrawingFrame() {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::FinishDrawingQuadList() {
-  NOTIMPLEMENTED();
-}
-
-bool VulkanRenderer::FlippedFramebuffer() const {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-void VulkanRenderer::EnsureScissorTestEnabled() {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::EnsureScissorTestDisabled() {
-  NOTIMPLEMENTED();
-}
-
-void VulkanRenderer::CopyDrawnRenderPass(
-    std::unique_ptr<CopyOutputRequest> request) {
-  NOTIMPLEMENTED();
-}
-
-bool VulkanRenderer::CanPartialSwap() {
-  NOTIMPLEMENTED();
-  return false;
-}
-
-}  // namespace viz
diff --git a/components/viz/service/display/vulkan_renderer.h b/components/viz/service/display/vulkan_renderer.h
deleted file mode 100644
index 4e7ff89a..0000000
--- a/components/viz/service/display/vulkan_renderer.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_VULKAN_RENDERER_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_VULKAN_RENDERER_H_
-
-#include "components/viz/service/display/direct_renderer.h"
-#include "components/viz/service/viz_service_export.h"
-#include "ui/latency/latency_info.h"
-
-namespace viz {
-
-class OutputSurface;
-
-class VIZ_SERVICE_EXPORT VulkanRenderer : public DirectRenderer {
- public:
-  VulkanRenderer(const RendererSettings* settings,
-                 OutputSurface* output_surface,
-                 DisplayResourceProvider* resource_provider);
-  ~VulkanRenderer() override;
-
-  // Implementation of public DirectRenderer functions.
-  void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
-
- protected:
-  // Implementations of protected Renderer functions.
-  void DidChangeVisibility() override;
-  ResourceFormat BackbufferFormat() const override;
-
-  // Implementations of protected DirectRenderer functions.
-  void BindFramebufferToOutputSurface() override;
-  void BindFramebufferToTexture(const RenderPassId render_pass_id) override;
-  void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
-  void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
-                             const gfx::Rect& render_pass_scissor) override;
-  void DoDrawQuad(const DrawQuad* quad, const gfx::QuadF* clip_region) override;
-  void BeginDrawingFrame() override;
-  void FinishDrawingFrame() override;
-  void FinishDrawingQuadList() override;
-  bool FlippedFramebuffer() const override;
-  void EnsureScissorTestEnabled() override;
-  void EnsureScissorTestDisabled() override;
-  void CopyDrawnRenderPass(std::unique_ptr<CopyOutputRequest> request) override;
-  bool CanPartialSwap() override;
-  void SetEnableDCLayers(bool enable) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(VulkanRenderer);
-};
-
-}  // namespace viz
-
-#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_VULKAN_RENDERER_H_
diff --git a/components/wifi/wifi_service_win.cc b/components/wifi/wifi_service_win.cc
index 48f5b99..3251ad7 100644
--- a/components/wifi/wifi_service_win.cc
+++ b/components/wifi/wifi_service_win.cc
@@ -28,6 +28,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "base/win/registry.h"
+#include "base/win/win_util.h"
 #include "components/onc/onc_constants.h"
 #include "components/wifi/network_properties.h"
 #include "third_party/libxml/chromium/libxml_utils.h"
@@ -1137,10 +1138,7 @@
 DWORD WiFiServiceImpl::FindAdapterIndexMapByGUID(
     const GUID& interface_guid,
     IP_ADAPTER_INDEX_MAP* adapter_index_map) {
-  base::string16 guid_string;
-  const int kGUIDSize = 39;
-  ::StringFromGUID2(interface_guid, base::WriteInto(&guid_string, kGUIDSize),
-                    kGUIDSize);
+  const auto guid_string = base::win::String16FromGUID(interface_guid);
 
   ULONG buffer_length = 0;
   DWORD error = ::GetInterfaceInfo(nullptr, &buffer_length);
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index 732dc46..3dda067 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -924,6 +924,8 @@
 
     BrowserTaskExecutor::PostFeatureListSetup();
 
+    delegate_->PostTaskSchedulerStart();
+
     if (!base::FeatureList::IsEnabled(
             features::kAllowStartingServiceManagerOnly)) {
       should_start_service_manager_only = false;
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 8fd4f5b..81d795d 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -27,6 +27,7 @@
 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index 4dbe013..fd4f77b 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -15,6 +15,7 @@
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/web_package/signed_exchange_envelope.h"
 #include "content/common/navigation_params.mojom.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -159,9 +160,18 @@
         result.push_back(std::move(throttle));
     }
   }
-  if (!frame_tree_node->parent())
-    return result;
-  agent_host = RenderFrameDevToolsAgentHost::GetFor(frame_tree_node->parent());
+  FrameTreeNode* parent = frame_tree_node->parent();
+  if (!parent) {
+    if (WebContentsImpl::FromFrameTreeNode(frame_tree_node)->IsPortal()) {
+      parent = WebContentsImpl::FromFrameTreeNode(frame_tree_node)
+                   ->GetOuterWebContents()
+                   ->GetFrameTree()
+                   ->root();
+    } else {
+      return result;
+    }
+  }
+  agent_host = RenderFrameDevToolsAgentHost::GetFor(parent);
   if (agent_host) {
     for (auto* target_handler :
          protocol::TargetHandler::ForAgentHost(agent_host)) {
@@ -358,6 +368,21 @@
   return !callback;
 }
 
+void PortalAttached(RenderFrameHostImpl* render_frame_host_impl) {
+  DispatchToAgents(render_frame_host_impl->frame_tree_node(),
+                   &protocol::TargetHandler::UpdatePortals);
+}
+
+void PortalDetached(RenderFrameHostImpl* render_frame_host_impl) {
+  DispatchToAgents(render_frame_host_impl->frame_tree_node(),
+                   &protocol::TargetHandler::UpdatePortals);
+}
+
+void PortalActivated(RenderFrameHostImpl* render_frame_host_impl) {
+  DispatchToAgents(render_frame_host_impl->frame_tree_node(),
+                   &protocol::TargetHandler::UpdatePortals);
+}
+
 }  // namespace devtools_instrumentation
 
 }  // namespace content
diff --git a/content/browser/devtools/devtools_instrumentation.h b/content/browser/devtools/devtools_instrumentation.h
index 1805184..0ef3544 100644
--- a/content/browser/devtools/devtools_instrumentation.h
+++ b/content/browser/devtools/devtools_instrumentation.h
@@ -116,6 +116,10 @@
                             const GURL& request_url,
                             CertErrorCallback callback);
 
+void PortalAttached(RenderFrameHostImpl* render_frame_host_impl);
+void PortalDetached(RenderFrameHostImpl* render_frame_host_impl);
+void PortalActivated(RenderFrameHostImpl* render_frame_host_impl);
+
 }  // namespace devtools_instrumentation
 
 }  // namespace content
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index d441a005..fdd1744 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -25,6 +25,7 @@
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
 #include "content/common/input/synthetic_tap_gesture_params.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/content_features.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/blink/web_input_event_traits.h"
 #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
diff --git a/content/browser/devtools/protocol/target_auto_attacher.cc b/content/browser/devtools/protocol/target_auto_attacher.cc
index 30a25805..053ea04e 100644
--- a/content/browser/devtools/protocol/target_auto_attacher.cc
+++ b/content/browser/devtools/protocol/target_auto_attacher.cc
@@ -13,6 +13,7 @@
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 
 namespace content {
 namespace protocol {
@@ -135,9 +136,34 @@
     RenderFrameHostImpl* render_frame_host) {
   render_frame_host_ = render_frame_host;
   UpdateFrames();
+  UpdatePortals();
   ReattachServiceWorkers(false);
 }
 
+void TargetAutoAttacher::UpdatePortals() {
+  if (!auto_attach_)
+    return;
+
+  Hosts new_hosts;
+  if (render_frame_host_ &&
+      render_frame_host_->frame_tree_node()->IsMainFrame()) {
+    WebContentsImpl* outer_web_contents = static_cast<WebContentsImpl*>(
+        WebContents::FromRenderFrameHost(render_frame_host_));
+    for (WebContents* web_contents :
+         outer_web_contents->GetInnerWebContents()) {
+      WebContentsImpl* web_contents_impl =
+          static_cast<WebContentsImpl*>(web_contents);
+      scoped_refptr<DevToolsAgentHost> new_host =
+          RenderFrameDevToolsAgentHost::GetOrCreateFor(
+              web_contents_impl->GetFrameTree()->root());
+      new_hosts.insert(new_host);
+    }
+  }
+
+  // TODO(dgozman): support wait_for_debugger_on_start_.
+  ReattachTargetsOfType(new_hosts, DevToolsAgentHost::kTypePage, false);
+}
+
 void TargetAutoAttacher::UpdateServiceWorkers() {
   ReattachServiceWorkers(false);
 }
@@ -189,7 +215,12 @@
       RenderFrameDevToolsAgentHost::FindForDangling(frame_tree_node);
 
   bool old_cross_process = !!agent_host;
-  bool new_cross_process = new_host && new_host->IsCrossProcessSubframe();
+  bool is_portal_main_frame =
+      frame_tree_node->IsMainFrame() && new_host &&
+      static_cast<WebContentsImpl*>(WebContents::FromRenderFrameHost(new_host))
+          ->IsPortal();
+  bool new_cross_process =
+      (new_host && new_host->IsCrossProcessSubframe()) || is_portal_main_frame;
 
   if (old_cross_process == new_cross_process)
     return nullptr;
@@ -262,10 +293,12 @@
       ReattachServiceWorkers(false);
     }
     UpdateFrames();
+    UpdatePortals();
   } else if (!auto_attach && auto_attach_) {
     auto_attach_ = false;
     Hosts empty;
     ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeFrame, false);
+    ReattachTargetsOfType(empty, DevToolsAgentHost::kTypePage, false);
     if (auto_attaching_service_workers_) {
       ServiceWorkerDevToolsManager::GetInstance()->RemoveObserver(this);
       ReattachTargetsOfType(empty, DevToolsAgentHost::kTypeServiceWorker,
diff --git a/content/browser/devtools/protocol/target_auto_attacher.h b/content/browser/devtools/protocol/target_auto_attacher.h
index 4e49d3d..e958bc0 100644
--- a/content/browser/devtools/protocol/target_auto_attacher.h
+++ b/content/browser/devtools/protocol/target_auto_attacher.h
@@ -35,6 +35,7 @@
                      bool wait_for_debugger_on_start,
                      base::OnceClosure callback);
 
+  void UpdatePortals();
   void UpdateServiceWorkers();
   void AgentHostClosed(DevToolsAgentHost* host);
 
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 4eaf0fa..475b7d50 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -492,6 +492,10 @@
                                     navigation_handle);
 }
 
+void TargetHandler::UpdatePortals() {
+  auto_attacher_.UpdatePortals();
+}
+
 void TargetHandler::ClearThrottles() {
   base::flat_set<Throttle*> copy(throttles_);
   for (Throttle* throttle : copy)
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index 514a59f6..adc66bdf 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -56,6 +56,7 @@
   void DidFinishNavigation();
   std::unique_ptr<NavigationThrottle> CreateThrottleForNavigation(
       NavigationHandle* navigation_handle);
+  void UpdatePortals();
 
   // Domain implementation.
   Response SetDiscoverTargets(bool discover) override;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index a81d80e..2108aa8e 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -631,6 +631,10 @@
 
 std::string RenderFrameDevToolsAgentHost::GetType() {
   if (web_contents() &&
+      static_cast<WebContentsImpl*>(web_contents())->IsPortal()) {
+    return kTypePage;
+  }
+  if (web_contents() &&
       static_cast<WebContentsImpl*>(web_contents())->GetOuterWebContents()) {
     return kTypeGuest;
   }
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 07cb107..3f78049 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -62,7 +62,6 @@
   static void SignalSynchronousSwapCompositorFrame(
       RenderFrameHost* frame_host,
       const DevToolsFrameMetadata& frame_metadata);
-
   FrameTreeNode* frame_tree_node() { return frame_tree_node_; }
 
   // DevToolsAgentHost overrides.
diff --git a/content/browser/frame_host/frame_tree_browsertest.cc b/content/browser/frame_host/frame_tree_browsertest.cc
index 90583cfe..c7fcb2d 100644
--- a/content/browser/frame_host/frame_tree_browsertest.cc
+++ b/content/browser/frame_host/frame_tree_browsertest.cc
@@ -13,6 +13,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_types.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/origin_util.h"
 #include "content/public/common/url_constants.h"
diff --git a/content/browser/frame_host/navigation_handle_impl_unittest.cc b/content/browser/frame_host/navigation_handle_impl_unittest.cc
index 2ad6c98..f9d0d4ba 100644
--- a/content/browser/frame_host/navigation_handle_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_handle_impl_unittest.cc
@@ -444,7 +444,7 @@
   const GURL kUrl = GURL("https://chromium.org");
   auto navigation =
       NavigationSimulatorImpl::CreateRendererInitiated(kUrl, main_rfh());
-  navigation->set_ssl_info(ssl_info);
+  navigation->SetSSLInfo(ssl_info);
   navigation->Fail(net::ERR_CERT_DATE_INVALID);
 
   EXPECT_EQ(net::CERT_STATUS_AUTHORITY_INVALID,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 6a42afb6..5eb0746 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -3832,7 +3832,8 @@
   }
   Portal* portal = Portal::Create(this, std::move(request));
   RenderFrameProxyHost* proxy_host = portal->CreateProxyAndAttachPortal();
-  std::move(callback).Run(proxy_host->GetRoutingID(), portal->portal_token());
+  std::move(callback).Run(proxy_host->GetRoutingID(), portal->portal_token(),
+                          portal->GetDevToolsFrameToken());
 }
 
 void RenderFrameHostImpl::AdoptPortal(
@@ -3848,7 +3849,8 @@
     return;
   }
   RenderFrameProxyHost* proxy_host = portal->CreateProxyAndAttachPortal();
-  std::move(callback).Run(proxy_host->GetRoutingID());
+  std::move(callback).Run(proxy_host->GetRoutingID(),
+                          portal->GetDevToolsFrameToken());
 }
 
 void RenderFrameHostImpl::IssueKeepAliveHandle(
diff --git a/content/browser/frame_host/render_frame_host_impl_browsertest.cc b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
index 9b99fd0..5effe5c 100644
--- a/content/browser/frame_host/render_frame_host_impl_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_impl_browsertest.cc
@@ -8,6 +8,8 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
@@ -2353,4 +2355,33 @@
             EvalJs(shell()->web_contents(), "window.origin"));
 }
 
+// Regression test for crbug.com/953934. It shouldn't crash if we quickly remove
+// an object element in the middle of its failing navigation.
+IN_PROC_BROWSER_TEST_F(RenderFrameHostImplBrowserTest,
+                       NoCrashOnRemoveObjectElementWithInvalidData) {
+  base::FilePath test_data_dir;
+  CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+  base::FilePath file_repro_path =
+      test_data_dir.Append(GetTestDataFilePath())
+          .Append(FILE_PATH_LITERAL(
+              "remove_object_element_with_invalid_data.html"));
+  GURL url(file_repro_path.value());
+
+  RenderProcessHostWatcher crash_observer(
+      shell()->web_contents(),
+      RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+
+  // This navigates to a page with an object element that will fail to load.
+  // When document load event hits, it'll attempt to remove that object element.
+  // This might happen while the object element's failed commit is underway.
+  // To make sure we hit these conditions and that we don't exit the test too
+  // soon, let's wait until the document.readyState finalizes. We don't really
+  // care if that succeeds since, in the failing case, the renderer is crashing.
+  NavigateToURL(shell(), url);
+  ignore_result(
+      WaitForRenderFrameReady(shell()->web_contents()->GetMainFrame()));
+
+  EXPECT_TRUE(crash_observer.did_exit_normally());
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index f93a9b77..62436cd 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -28,6 +28,7 @@
 #include "content/common/frame_messages.h"
 #include "content/common/frame_owner_properties.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
 #include "ipc/ipc_message.h"
 
 namespace content {
diff --git a/content/browser/isolated_origin_browsertest.cc b/content/browser/isolated_origin_browsertest.cc
index 84d81f9d..24b3a4c 100644
--- a/content/browser/isolated_origin_browsertest.cc
+++ b/content/browser/isolated_origin_browsertest.cc
@@ -979,9 +979,8 @@
   // A SiteInstance created for an isolated origin ServiceWorker should
   // not reuse the unsuitable first process.
   scoped_refptr<SiteInstanceImpl> sw_site_instance =
-      SiteInstanceImpl::CreateForURL(web_contents()->GetBrowserContext(),
-                                     hung_isolated_url);
-  sw_site_instance->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(
+          web_contents()->GetBrowserContext(), hung_isolated_url);
   sw_site_instance->set_process_reuse_policy(
       SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE);
   RenderProcessHost* sw_host = sw_site_instance->GetProcess();
diff --git a/content/browser/portal/portal.cc b/content/browser/portal/portal.cc
index d7faeb9..77468a35 100644
--- a/content/browser/portal/portal.cc
+++ b/content/browser/portal/portal.cc
@@ -10,6 +10,7 @@
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
 #include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/devtools/devtools_instrumentation.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_host_manager.h"
 #include "content/browser/frame_host/render_frame_proxy_host.h"
@@ -40,6 +41,10 @@
 }
 
 Portal::~Portal() {
+  WebContentsImpl* outer_contents_impl = static_cast<WebContentsImpl*>(
+      WebContents::FromRenderFrameHost(owner_render_frame_host_));
+  devtools_instrumentation::PortalDetached(outer_contents_impl->GetMainFrame());
+
   g_portal_token_map.Get().erase(portal_token_);
 }
 
@@ -122,6 +127,8 @@
   if (web_contents_created)
     PortalWebContentsCreated(portal_contents_impl_);
 
+  devtools_instrumentation::PortalAttached(outer_contents_impl->GetMainFrame());
+
   return proxy_host;
 }
 
@@ -165,6 +172,8 @@
   portal_contents_impl_->GetMainFrame()->OnPortalActivated(
       portal->portal_token_, portal_ptr.PassInterface(), std::move(data),
       std::move(callback));
+
+  devtools_instrumentation::PortalActivated(outer_contents->GetMainFrame());
 }
 
 void Portal::PostMessage(blink::TransferableMessage message,
@@ -190,6 +199,10 @@
   outer_contents->GetDelegate()->PortalWebContentsCreated(portal_web_contents);
 }
 
+base::UnguessableToken Portal::GetDevToolsFrameToken() const {
+  return portal_contents_impl_->GetMainFrame()->GetDevToolsFrameToken();
+}
+
 WebContentsImpl* Portal::GetPortalContents() {
   return portal_contents_impl_;
 }
diff --git a/content/browser/portal/portal.h b/content/browser/portal/portal.h
index 98b94182..5b2a671a 100644
--- a/content/browser/portal/portal.h
+++ b/content/browser/portal/portal.h
@@ -70,6 +70,9 @@
   // Returns the token which uniquely identifies this Portal.
   const base::UnguessableToken& portal_token() const { return portal_token_; }
 
+  // Returns the devtools frame token for the portal's main frame.
+  base::UnguessableToken GetDevToolsFrameToken() const;
+
   // Returns the Portal's WebContents.
   WebContentsImpl* GetPortalContents();
 
diff --git a/content/browser/portal/portal_browsertest.cc b/content/browser/portal/portal_browsertest.cc
index 870787b..7231cc8 100644
--- a/content/browser/portal/portal_browsertest.cc
+++ b/content/browser/portal/portal_browsertest.cc
@@ -132,8 +132,8 @@
                                             std::move(request));
     portal_ = portal_interceptor->GetPortal();
     RenderFrameProxyHost* proxy_host = portal_->CreateProxyAndAttachPortal();
-    std::move(callback).Run(proxy_host->GetRoutingID(),
-                            portal_->portal_token());
+    std::move(callback).Run(proxy_host->GetRoutingID(), portal_->portal_token(),
+                            portal_->GetDevToolsFrameToken());
 
     if (run_loop_)
       run_loop_->Quit();
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 4420a91a..73ffaa0 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -72,6 +72,7 @@
 #include "content/public/browser/android/compositor_client.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/gpu_stream_constants.h"
 #include "gpu/command_buffer/client/context_support.h"
diff --git a/content/browser/renderer_host/input/passthrough_touch_event_queue.h b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
index 8fd4679..35330cb 100644
--- a/content/browser/renderer_host/input/passthrough_touch_event_queue.h
+++ b/content/browser/renderer_host/input/passthrough_touch_event_queue.h
@@ -15,9 +15,9 @@
 #include "base/time/time.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
 #include "content/common/content_export.h"
-#include "content/public/common/content_features.h"
 #include "content/public/common/input_event_ack_source.h"
 #include "content/public/common/input_event_ack_state.h"
+#include "ui/events/blink/blink_features.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/render_process_host_unittest.cc b/content/browser/renderer_host/render_process_host_unittest.cc
index cc190205..8c014b1 100644
--- a/content/browser/renderer_host/render_process_host_unittest.cc
+++ b/content/browser/renderer_host/render_process_host_unittest.cc
@@ -185,16 +185,14 @@
 
   // Gets a RenderProcessHost for an unmatched service worker.
   scoped_refptr<SiteInstanceImpl> sw_site_instance1 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance1->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_host1 = sw_site_instance1->GetProcess();
 
   // Getting a RenderProcessHost for a service worker with DEFAULT reuse policy
   // should not reuse the existing service worker's process. We create this
   // second service worker to test the "find the newest process" logic later.
   scoped_refptr<SiteInstanceImpl> sw_site_instance2 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance2->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_host2 = sw_site_instance2->GetProcess();
   EXPECT_NE(sw_host1, sw_host2);
 
@@ -240,8 +238,7 @@
 
   // Gets a RenderProcessHost for an unmatched service worker.
   scoped_refptr<SiteInstanceImpl> sw_site_instance =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_host = sw_site_instance->GetProcess();
 
   // Simulate a situation where |sw_host| won't be considered suitable for
@@ -272,8 +269,7 @@
 
   // Gets a RenderProcessHost for a service worker.
   scoped_refptr<SiteInstanceImpl> sw_site_instance1 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance1->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   sw_site_instance1->set_process_reuse_policy(
       SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE);
   RenderProcessHost* sw_host1 = sw_site_instance1->GetProcess();
@@ -284,8 +280,7 @@
   // start the service worker and want to use a new process. We create this
   // second service worker to test the "find the newest process" logic later.
   scoped_refptr<SiteInstanceImpl> sw_site_instance2 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance2->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_host2 = sw_site_instance2->GetProcess();
   EXPECT_NE(sw_host1, sw_host2);
 
@@ -293,8 +288,7 @@
   // REUSE_PENDING_OR_COMMITTED_SITE reuse policy should reuse the newest
   // unmatched service worker's process (i.e., sw_host2).
   scoped_refptr<SiteInstanceImpl> sw_site_instance3 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance3->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   sw_site_instance3->set_process_reuse_policy(
       SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE);
   RenderProcessHost* sw_host3 = sw_site_instance3->GetProcess();
@@ -306,8 +300,7 @@
   // sw_host2 to be considered matched, so we can keep putting more service
   // workers in that process.
   scoped_refptr<SiteInstanceImpl> sw_site_instance4 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance4->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   sw_site_instance4->set_process_reuse_policy(
       SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE);
   RenderProcessHost* sw_host4 = sw_site_instance4->GetProcess();
@@ -336,15 +329,13 @@
 
   // Gets a RenderProcessHost for a service worker with process-per-site flag.
   scoped_refptr<SiteInstanceImpl> sw_site_instance1 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance1->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_host1 = sw_site_instance1->GetProcess();
 
   // Getting a RenderProcessHost for a service worker of the same site with
   // process-per-site flag should reuse the unmatched service worker's process.
   scoped_refptr<SiteInstanceImpl> sw_site_instance2 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance2->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_host2 = sw_site_instance2->GetProcess();
   EXPECT_EQ(sw_host1, sw_host2);
 
@@ -369,8 +360,7 @@
 
   // Gets a RenderProcessHost for a service worker.
   scoped_refptr<SiteInstanceImpl> sw_site_instance1 =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl1);
-  sw_site_instance1->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl1);
   RenderProcessHost* sw_host1 = sw_site_instance1->GetProcess();
 
   // Getting a RenderProcessHost for a service worker of a different site should
@@ -866,8 +856,7 @@
 
   // Create a RenderProcessHost for a service worker.
   scoped_refptr<SiteInstanceImpl> sw_site_instance =
-      SiteInstanceImpl::CreateForURL(browser_context(), kUrl);
-  sw_site_instance->set_is_for_service_worker();
+      SiteInstanceImpl::CreateForServiceWorker(browser_context(), kUrl);
   RenderProcessHost* sw_process = sw_site_instance->GetProcess();
 
   // Change foo.com SiteInstances to use a different StoragePartition.
diff --git a/content/browser/renderer_host/render_widget_host_input_event_router.cc b/content/browser/renderer_host/render_widget_host_input_event_router.cc
index 5ebb41f..53c7c53 100644
--- a/content/browser/renderer_host/render_widget_host_input_event_router.cc
+++ b/content/browser/renderer_host/render_widget_host_input_event_router.cc
@@ -1439,7 +1439,11 @@
   }
   // This function is called on GesturePinchBegin, by which time there should
   // be an active touch action assessed for the target.
-  DCHECK(target_active_touch_action.has_value());
+  // DCHECK(target_active_touch_action.has_value());
+  // TODO(wjmaclean): Find out why we can be in the middle of a gesture
+  // sequence and not have a valid touch action assigned.
+  if (!target_active_touch_action)
+    target_active_touch_action = cc::kTouchActionNone;
   return (target_active_touch_action.value() &
           cc::TouchAction::kTouchActionPinchZoom);
 }
diff --git a/content/browser/service_worker/service_worker_process_manager.cc b/content/browser/service_worker/service_worker_process_manager.cc
index 68718d4..064b70a 100644
--- a/content/browser/service_worker/service_worker_process_manager.cc
+++ b/content/browser/service_worker/service_worker_process_manager.cc
@@ -114,11 +114,10 @@
       storage_partition_ &&
       !storage_partition_->site_for_service_worker().is_empty();
   scoped_refptr<SiteInstanceImpl> site_instance =
-      SiteInstanceImpl::CreateForURL(
+      SiteInstanceImpl::CreateForServiceWorker(
           browser_context_, use_url_from_storage_partition
                                 ? storage_partition_->site_for_service_worker()
                                 : script_url);
-  site_instance->set_is_for_service_worker();
 
   // Attempt to reuse a renderer process if possible. Note that in the
   // <webview> case, process reuse isn't currently supported and a new
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index 6abfb486..703409b 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -83,6 +83,22 @@
 }
 
 // static
+scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForServiceWorker(
+    BrowserContext* browser_context,
+    const GURL& url) {
+  // This will create a new SiteInstance and BrowsingInstance.
+  scoped_refptr<BrowsingInstance> instance(
+      new BrowsingInstance(browser_context));
+
+  // We do NOT want to allow the default site instance here because workers
+  // need to be kept separate from other sites.
+  scoped_refptr<SiteInstanceImpl> site_instance =
+      instance->GetSiteInstanceForURL(url, /* allow_default_instance */ false);
+  site_instance->is_for_service_worker_ = true;
+  return site_instance;
+}
+
+// static
 bool SiteInstanceImpl::ShouldAssignSiteForURL(const GURL& url) {
   // about:blank should not "use up" a new SiteInstance.  The SiteInstance can
   // still be used for a normal web site.
diff --git a/content/browser/site_instance_impl.h b/content/browser/site_instance_impl.h
index 758e232..3881b2d 100644
--- a/content/browser/site_instance_impl.h
+++ b/content/browser/site_instance_impl.h
@@ -40,6 +40,9 @@
   static scoped_refptr<SiteInstanceImpl> CreateForURL(
       BrowserContext* browser_context,
       const GURL& url);
+  static scoped_refptr<SiteInstanceImpl> CreateForServiceWorker(
+      BrowserContext* browser_context,
+      const GURL& url);
   static bool ShouldAssignSiteForURL(const GURL& url);
 
   // Returns whether |lock_url| is at least at the granularity of a site (i.e.,
@@ -114,7 +117,6 @@
   // chosen existing process is reused because of the process limit, the process
   // will be tracked as having an unmatched service worker until reused by
   // another SiteInstance from the same site.
-  void set_is_for_service_worker() { is_for_service_worker_ = true; }
   bool is_for_service_worker() const { return is_for_service_worker_; }
 
   // Returns the URL which was used to set the |site_| for this SiteInstance.
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 88471bc4..68cb13c4 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -345,13 +345,15 @@
   // |portal_token|, which is the unique identifier for the portal.
   [Sync] CreatePortal(associated blink.mojom.Portal& portal)
       => (int32 proxy_routing_id,
-          mojo_base.mojom.UnguessableToken portal_token);
+          mojo_base.mojom.UnguessableToken portal_token,
+          mojo_base.mojom.UnguessableToken devtools_frame_token);
 
   // Requests that this frame adopts the portal identified by |portal_token|.
   // Returns |proxy_routing_id|, which is the routing id of the portal's
   // RenderFrameProxy.
   [Sync] AdoptPortal(mojo_base.mojom.UnguessableToken portal_token)
-      => (int32 proxy_routing_id);
+      => (int32 proxy_routing_id,
+          mojo_base.mojom.UnguessableToken devtools_frame_token);
 
   // Creates and returns a KeepAliveHandle.
   IssueKeepAliveHandle(KeepAliveHandle& keep_alive_handle);
diff --git a/content/common/user_agent.cc b/content/common/user_agent.cc
index abff1622..f37818e 100644
--- a/content/common/user_agent.cc
+++ b/content/common/user_agent.cc
@@ -134,6 +134,14 @@
   return os_cpu;
 }
 
+base::StringPiece GetFrozenUserAgent(bool mobile) {
+#if defined(OS_ANDROID)
+  return mobile ? frozen_user_agent_strings::kAndroidMobile
+                : frozen_user_agent_strings::kAndroid;
+#endif
+  return frozen_user_agent_strings::kDesktop;
+}
+
 std::string BuildUserAgentFromProduct(const std::string& product) {
   std::string os_info;
   base::StringAppendF(&os_info, "%s%s", GetUserAgentPlatform().c_str(),
diff --git a/content/public/app/content_main_delegate.h b/content/public/app/content_main_delegate.h
index f498906..01f81ee 100644
--- a/content/public/app/content_main_delegate.h
+++ b/content/public/app/content_main_delegate.h
@@ -134,6 +134,10 @@
   // list initialization is complete.
   virtual void PostFieldTrialInitialization() {}
 
+  // Allows the embedder to perform its own initialization after the
+  // TaskScheduler is started.
+  virtual void PostTaskSchedulerStart() {}
+
  protected:
   friend class ContentClientInitializer;
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 8fb7e308..06f440d7 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -484,18 +484,6 @@
 const base::Feature kTouchpadAsyncPinchEvents{"TouchpadAsyncPinchEvents",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Skips the browser touch event filter, ensuring that events that reach the
-// queue and would otherwise be filtered out will instead be passed onto the
-// renderer compositor process as long as the page hasn't timed out. Which event
-// types will be always forwarded is controlled by the "type" FeatureParam,
-// which can be either "discrete" (default) or "all".
-const base::Feature kSkipBrowserTouchFilter{"SkipBrowserTouchFilter",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
-
-const char kSkipBrowserTouchFilterTypeParamName[] = "type";
-const char kSkipBrowserTouchFilterTypeParamValueDiscrete[] = "discrete";
-const char kSkipBrowserTouchFilterTypeParamValueAll[] = "all";
-
 // Allows developers transfer user activation state to any target window in the
 // frame tree.
 const base::Feature kUserActivationPostMessageTransfer{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index 159c86fa..a54704c 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -107,11 +107,6 @@
 CONTENT_EXPORT extern const base::Feature kSignedExchangeSubresourcePrefetch;
 CONTENT_EXPORT extern const base::Feature kSignedHTTPExchange;
 CONTENT_EXPORT extern const base::Feature kSignedHTTPExchangePingValidity;
-CONTENT_EXPORT extern const base::Feature kSkipBrowserTouchFilter;
-CONTENT_EXPORT extern const char kSkipBrowserTouchFilterTypeParamName[];
-CONTENT_EXPORT extern const char
-    kSkipBrowserTouchFilterTypeParamValueDiscrete[];
-CONTENT_EXPORT extern const char kSkipBrowserTouchFilterTypeParamValueAll[];
 CONTENT_EXPORT extern const base::Feature kSpareRendererForSitePerProcess;
 CONTENT_EXPORT extern const base::Feature kSyntheticPointerActions;
 CONTENT_EXPORT extern const base::Feature kTimerThrottlingForHiddenFrames;
diff --git a/content/public/common/user_agent.h b/content/public/common/user_agent.h
index 651fcbd0..930fb5f 100644
--- a/content/public/common/user_agent.h
+++ b/content/public/common/user_agent.h
@@ -7,11 +7,29 @@
 
 #include <string>
 
+#include "base/strings/string_piece.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
+#include "third_party/blink/public/mojom/user_agent/user_agent_metadata.mojom.h"
 
 namespace content {
 
+namespace frozen_user_agent_strings {
+
+const char kDesktop[] =
+    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, "
+    "like Gecko) Chrome/75.0.3764.0 Safari/537.36";
+const char kAndroid[] =
+    "Mozilla/5.0 (Linux; Android 9; Unspecified Device) "
+    "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3764.0 "
+    "Safari/537.36";
+const char kAndroidMobile[] =
+    "Mozilla/5.0 (Linux; Android 9; Unspecified Device) "
+    "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3764.0 Mobile "
+    "Safari/537.36";
+
+}  // namespace frozen_user_agent_strings
+
 // Returns the WebKit version, in the form "major.minor (branch@revision)".
 CONTENT_EXPORT std::string GetWebKitVersion();
 
@@ -22,6 +40,10 @@
 // as an argument.
 CONTENT_EXPORT std::string BuildOSCpuInfo(bool include_android_build_number);
 
+// Returns the frozen User-agent string for
+// https://github.com/WICG/ua-client-hints.
+CONTENT_EXPORT base::StringPiece GetFrozenUserAgent(bool mobile);
+
 // Helper function to generate a full user agent string from a short
 // product name.
 CONTENT_EXPORT std::string BuildUserAgentFromProduct(
diff --git a/content/public/test/navigation_simulator.h b/content/public/test/navigation_simulator.h
index 1cc8c2b..27ee934 100644
--- a/content/public/test/navigation_simulator.h
+++ b/content/public/test/navigation_simulator.h
@@ -19,6 +19,7 @@
 namespace net {
 class IPEndPoint;
 class HttpResponseHeaders;
+class SSLInfo;
 }  // namespace net
 
 namespace content {
@@ -284,6 +285,10 @@
   // in throttles deferring the navigation with a call to Wait().
   virtual void SetAutoAdvance(bool auto_advance) = 0;
 
+  // Sets the SSLInfo to be set on the response. This should be called before
+  // Commit().
+  virtual void SetSSLInfo(const net::SSLInfo& ssl_info) = 0;
+
   // --------------------------------------------------------------------------
 
   // Gets the last throttle check result computed by the navigation throttles.
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 07120d3..97e7f0b 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -144,8 +144,6 @@
     "input/widget_input_handler_impl.h",
     "input/widget_input_handler_manager.cc",
     "input/widget_input_handler_manager.h",
-    "installedapp/related_apps_fetcher.cc",
-    "installedapp/related_apps_fetcher.h",
     "internal_document_state_data.cc",
     "internal_document_state_data.h",
     "java/gin_java_bridge_dispatcher.cc",
diff --git a/content/renderer/installedapp/related_apps_fetcher.cc b/content/renderer/installedapp/related_apps_fetcher.cc
deleted file mode 100644
index 54230fb..0000000
--- a/content/renderer/installedapp/related_apps_fetcher.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/installedapp/related_apps_fetcher.h"
-
-#include "base/bind.h"
-#include "content/public/renderer/render_frame.h"
-#include "third_party/blink/public/common/manifest/manifest.h"
-#include "third_party/blink/public/mojom/manifest/manifest.mojom.h"
-#include "third_party/blink/public/platform/modules/installedapp/web_related_application.h"
-#include "third_party/blink/public/platform/web_string.h"
-#include "third_party/blink/public/web/web_manifest_manager.h"
-
-namespace content {
-
-RelatedAppsFetcher::RelatedAppsFetcher(RenderFrame* render_frame)
-    : render_frame_(render_frame) {}
-
-RelatedAppsFetcher::~RelatedAppsFetcher() {}
-
-void RelatedAppsFetcher::GetManifestRelatedApplications(
-    blink::GetManifestRelatedApplicationsCallback completion_callback) {
-  blink::WebManifestManager* manifest_manager =
-      blink::WebManifestManager::FromFrame(render_frame_->GetWebFrame());
-  manifest_manager->RequestManifest(
-      base::BindOnce(&RelatedAppsFetcher::OnGetManifestForRelatedApplications,
-                     base::Unretained(this), std::move(completion_callback)));
-}
-
-void RelatedAppsFetcher::OnGetManifestForRelatedApplications(
-    blink::GetManifestRelatedApplicationsCallback completion_callback,
-    const blink::WebURL& /*url*/,
-    const blink::Manifest& manifest) {
-  std::vector<blink::WebRelatedApplication> related_apps;
-  for (const auto& relatedApplication : manifest.related_applications) {
-    blink::WebRelatedApplication webRelatedApplication;
-    webRelatedApplication.platform =
-        blink::WebString::FromUTF16(relatedApplication.platform);
-    webRelatedApplication.id =
-        blink::WebString::FromUTF16(relatedApplication.id);
-    if (!relatedApplication.url.is_empty()) {
-      webRelatedApplication.url =
-          blink::WebString::FromUTF8(relatedApplication.url.spec());
-    }
-    related_apps.push_back(std::move(webRelatedApplication));
-  }
-  std::move(completion_callback).Run(std::move(related_apps));
-}
-
-}  // namespace content
diff --git a/content/renderer/installedapp/related_apps_fetcher.h b/content/renderer/installedapp/related_apps_fetcher.h
deleted file mode 100644
index 594004e..0000000
--- a/content/renderer/installedapp/related_apps_fetcher.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_INSTALLEDAPP_RELATED_APPS_FETCHER_H
-#define CONTENT_RENDERER_INSTALLEDAPP_RELATED_APPS_FETCHER_H
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "content/common/content_export.h"
-#include "third_party/blink/public/platform/modules/installedapp/web_related_apps_fetcher.h"
-
-namespace blink {
-struct Manifest;
-}  // namespace blink
-
-namespace content {
-
-class RenderFrame;
-
-class CONTENT_EXPORT RelatedAppsFetcher : public blink::WebRelatedAppsFetcher {
- public:
-  explicit RelatedAppsFetcher(RenderFrame* render_frame);
-  ~RelatedAppsFetcher() override;
-
-  // blink::WebRelatedAppsFetcher overrides:
-  void GetManifestRelatedApplications(
-      blink::GetManifestRelatedApplicationsCallback completion_callback)
-      override;
-
- private:
-  // Callback for when the manifest has been fetched, triggered by a call to
-  // getManifestRelatedApplications.
-  void OnGetManifestForRelatedApplications(
-      blink::GetManifestRelatedApplicationsCallback completion_callback,
-      const blink::WebURL& url,
-      const blink::Manifest& manifest);
-
-  RenderFrame* const render_frame_;
-
-  DISALLOW_COPY_AND_ASSIGN(RelatedAppsFetcher);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_INSTALLEDAPP_RELATED_APPS_FETCHER_H
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 89954a077..5f63149 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -109,7 +109,6 @@
 #include "content/renderer/input/frame_input_handler_impl.h"
 #include "content/renderer/input/input_target_client_impl.h"
 #include "content/renderer/input/widget_input_handler_manager.h"
-#include "content/renderer/installedapp/related_apps_fetcher.h"
 #include "content/renderer/internal_document_state_data.h"
 #include "content/renderer/loader/navigation_body_loader.h"
 #include "content/renderer/loader/request_extra_data.h"
@@ -3627,9 +3626,17 @@
 
   // On load failure, a frame can ask its owner to render fallback content.
   // When that happens, don't load an error page.
+  base::WeakPtr<RenderFrameImpl> weak_this = weak_factory_.GetWeakPtr();
   blink::WebNavigationControl::FallbackContentResult fallback_result =
       frame_->MaybeRenderFallbackContent(error);
 
+  // The rendering fallback content can result in this frame being removed.
+  // Use a WeakPtr as an easy way to detect whether this has occurred. If so,
+  // this method should return immediately and not touch any part of the object,
+  // otherwise it will result in a use-after-free bug.
+  if (!weak_this)
+    return;
+
   if (commit_params.nav_entry_id == 0) {
     // For renderer initiated navigations, we send out a
     // DidFailProvisionalLoad() notification.
@@ -3720,10 +3727,9 @@
       false /* was_initiated_in_this_frame */);
 
   // The load of the error page can result in this frame being removed.
-  // Use a WeakPtr as an easy way to detect whether this has occured. If so,
+  // Use a WeakPtr as an easy way to detect whether this has occurred. If so,
   // this method should return immediately and not touch any part of the object,
   // otherwise it will result in a use-after-free bug.
-  base::WeakPtr<RenderFrameImpl> weak_this = weak_factory_.GetWeakPtr();
   frame_->CommitNavigation(std::move(navigation_params),
                            std::move(document_state));
   if (!weak_this)
@@ -4258,20 +4264,23 @@
 RenderFrameImpl::CreatePortal(mojo::ScopedInterfaceEndpointHandle pipe) {
   int proxy_routing_id = MSG_ROUTING_NONE;
   base::UnguessableToken portal_token;
+  base::UnguessableToken devtools_frame_token;
   GetFrameHost()->CreatePortal(
       blink::mojom::PortalAssociatedRequest(std::move(pipe)), &proxy_routing_id,
-      &portal_token);
-  RenderFrameProxy* proxy =
-      RenderFrameProxy::CreateProxyForPortal(this, proxy_routing_id);
+      &portal_token, &devtools_frame_token);
+  RenderFrameProxy* proxy = RenderFrameProxy::CreateProxyForPortal(
+      this, proxy_routing_id, devtools_frame_token);
   return std::make_pair(proxy->web_frame(), portal_token);
 }
 
 blink::WebRemoteFrame* RenderFrameImpl::AdoptPortal(
     const base::UnguessableToken& portal_token) {
   int proxy_routing_id = MSG_ROUTING_NONE;
-  GetFrameHost()->AdoptPortal(portal_token, &proxy_routing_id);
-  RenderFrameProxy* proxy =
-      RenderFrameProxy::CreateProxyForPortal(this, proxy_routing_id);
+  base::UnguessableToken devtools_frame_token;
+  GetFrameHost()->AdoptPortal(portal_token, &proxy_routing_id,
+                              &devtools_frame_token);
+  RenderFrameProxy* proxy = RenderFrameProxy::CreateProxyForPortal(
+      this, proxy_routing_id, devtools_frame_token);
   return proxy->web_frame();
 }
 
@@ -5512,13 +5521,6 @@
   return push_messaging_client_;
 }
 
-blink::WebRelatedAppsFetcher* RenderFrameImpl::GetRelatedAppsFetcher() {
-  if (!related_apps_fetcher_)
-    related_apps_fetcher_.reset(new RelatedAppsFetcher(this));
-
-  return related_apps_fetcher_.get();
-}
-
 void RenderFrameImpl::WillStartUsingPeerConnectionHandler(
     blink::WebRTCPeerConnectionHandler* handler) {
   static_cast<RTCPeerConnectionHandler*>(handler)->associateWithFrame(frame_);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 31dc055a..58e5b9e 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -119,7 +119,6 @@
 class WebLayerTreeView;
 class WebLocalFrame;
 class WebPushClient;
-class WebRelatedAppsFetcher;
 class WebSecurityOrigin;
 class WebString;
 class WebURL;
@@ -164,7 +163,6 @@
 class NavigationClient;
 class PepperPluginInstanceImpl;
 class PushMessagingClient;
-class RelatedAppsFetcher;
 class RenderAccessibilityImpl;
 class RendererPpapiHost;
 class RenderFrameObserver;
@@ -823,7 +821,6 @@
                                 int world_id) override;
   void DidChangeScrollOffset() override;
   blink::WebPushClient* PushClient() override;
-  blink::WebRelatedAppsFetcher* GetRelatedAppsFetcher() override;
   void WillStartUsingPeerConnectionHandler(
       blink::WebRTCPeerConnectionHandler* handler) override;
   blink::WebUserMediaClient* UserMediaClient() override;
@@ -1604,8 +1601,6 @@
   // flag set.
   RenderAccessibilityImpl* render_accessibility_;
 
-  std::unique_ptr<RelatedAppsFetcher> related_apps_fetcher_;
-
   // The PreviewsState of this RenderFrame that indicates which Previews can
   // be used. The PreviewsState is a bitmask of potentially several Previews
   // optimizations.
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index cdba17a..04b0734 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -177,9 +177,11 @@
 
 RenderFrameProxy* RenderFrameProxy::CreateProxyForPortal(
     RenderFrameImpl* parent,
-    int proxy_routing_id) {
+    int proxy_routing_id,
+    const base::UnguessableToken& devtools_frame_token) {
   std::unique_ptr<RenderFrameProxy> proxy(
       new RenderFrameProxy(proxy_routing_id));
+  proxy->devtools_frame_token_ = devtools_frame_token;
   blink::WebRemoteFrame* web_frame = blink::WebRemoteFrame::Create(
       blink::WebTreeScopeType::kDocument, proxy.get());
   proxy->Init(web_frame, parent->render_view(),
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 385a553..0cb2499 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -114,8 +114,10 @@
 
   // Creates a RenderFrameProxy to be used with a portal owned by |parent|.
   // |routing_id| is the routing id of this new RenderFrameProxy.
-  static RenderFrameProxy* CreateProxyForPortal(RenderFrameImpl* parent,
-                                                int proxy_routing_id);
+  static RenderFrameProxy* CreateProxyForPortal(
+      RenderFrameImpl* parent,
+      int proxy_routing_id,
+      const base::UnguessableToken& devtools_frame_token);
 
   // Returns the RenderFrameProxy for the given routing ID.
   static RenderFrameProxy* FromRoutingID(int routing_id);
diff --git a/content/renderer/render_process_impl.cc b/content/renderer/render_process_impl.cc
index 5620f8b..b56885c7 100644
--- a/content/renderer/render_process_impl.cc
+++ b/content/renderer/render_process_impl.cc
@@ -165,11 +165,17 @@
                         "--no-wasm-trap-handler");
 #if defined(OS_LINUX) && defined(ARCH_CPU_X86_64)
   if (base::FeatureList::IsEnabled(features::kWebAssemblyTrapHandler)) {
-    bool use_v8_signal_handler = false;
     base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
     if (!command_line->HasSwitch(
             service_manager::switches::kDisableInProcessStackTraces)) {
-      base::debug::SetStackDumpFirstChanceCallback(v8::V8::TryHandleSignal);
+      // Only enable WebAssembly trap handler if we can set the callback.
+      if (base::debug::SetStackDumpFirstChanceCallback(
+              v8::V8::TryHandleSignal)) {
+        // We registered the WebAssembly trap handler callback with the stack
+        // dump signal handler successfully. We can tell V8 that it can enable
+        // WebAssembly trap handler without using the V8 signal handler.
+        v8::V8::EnableWebAssemblyTrapHandler(/*use_v8_signal_handler=*/false);
+      }
     } else if (!command_line->HasSwitch(switches::kEnableCrashReporter) &&
                !command_line->HasSwitch(
                    switches::kEnableCrashReporterForTesting)) {
@@ -177,10 +183,8 @@
       // in-process stack traces are disabled then there will be no signal
       // handler. In this case, we fall back on V8's default handler
       // (https://crbug.com/798150).
-      use_v8_signal_handler = true;
+      v8::V8::EnableWebAssemblyTrapHandler(/*use_v8_signal_handler=*/true);
     }
-    // TODO(eholk): report UMA stat for how often this succeeds
-    v8::V8::EnableWebAssemblyTrapHandler(use_v8_signal_handler);
   }
 #endif
 #if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 4893de5..efc1902 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -10,6 +10,7 @@
 #include "base/base_switches.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/files/file.h"
 #include "base/files/file_util.h"
 #include "base/no_destructor.h"
@@ -26,6 +27,7 @@
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
@@ -60,6 +62,7 @@
 #include "services/test/echo/public/cpp/manifest.h"
 #include "services/test/echo/public/mojom/echo.mojom.h"
 #include "storage/browser/quota/quota_settings.h"
+#include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/common/user_agent/user_agent_metadata.h"
 #include "ui/base/ui_base_features.h"
 #include "url/gurl.h"
@@ -230,6 +233,11 @@
 std::string GetShellUserAgent() {
   std::string product = "Chrome/" CONTENT_SHELL_VERSION;
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (base::FeatureList::IsEnabled(blink::features::kFreezeUserAgent)) {
+    return content::GetFrozenUserAgent(
+               command_line->HasSwitch(switches::kUseMobileUserAgent))
+        .as_string();
+  }
   if (command_line->HasSwitch(switches::kUseMobileUserAgent))
     product += " Mobile";
   return BuildUserAgentFromProduct(product);
diff --git a/content/shell/browser/web_test/blink_test_controller.cc b/content/shell/browser/web_test/blink_test_controller.cc
index c78259db..e5a8c67 100644
--- a/content/shell/browser/web_test/blink_test_controller.cc
+++ b/content/shell/browser/web_test/blink_test_controller.cc
@@ -560,7 +560,10 @@
 
 void BlinkTestController::RendererUnresponsive() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  LOG(WARNING) << "renderer unresponsive";
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableHangMonitor)) {
+    LOG(WARNING) << "renderer unresponsive";
+  }
 }
 
 void BlinkTestController::OverrideWebkitPrefs(WebPreferences* prefs) {
diff --git a/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc b/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
index 47cb964b..60a15872 100644
--- a/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
@@ -1009,14 +1009,14 @@
   ON_CALL(*measurement_interval, StartNotifySession_(_, _))
       .WillByDefault(Invoke(
           [adapter_ptr, device_ptr, measurement_ptr, disconnect, succeeds](
-              const BluetoothRemoteGattCharacteristic::NotifySessionCallback&
+              BluetoothRemoteGattCharacteristic::NotifySessionCallback&
                   callback,
               BluetoothRemoteGattCharacteristic::ErrorCallback&
                   error_callback) {
             base::OnceClosure pending;
             if (succeeds) {
-              pending =
-                  base::Bind(callback, base::Passed(GetBaseGATTNotifySession(
+              pending = base::BindOnce(std::move(callback),
+                                       base::Passed(GetBaseGATTNotifySession(
                                            measurement_ptr->GetWeakPtr())));
             } else {
               pending =
@@ -1136,10 +1136,10 @@
                 std::make_unique<NiceMockBluetoothGattNotifySession>(
                     measurement_ptr->GetWeakPtr());
 
-            ON_CALL(*notify_session, Stop(_))
+            ON_CALL(*notify_session, Stop_(_))
                 .WillByDefault(Invoke([adapter_ptr, device_ptr, disconnect](
-                                          const base::Closure& callback) {
-                  device_ptr->PushPendingCallback(callback);
+                                          base::OnceClosure& callback) {
+                  device_ptr->PushPendingCallback(std::move(callback));
 
                   if (disconnect) {
                     device_ptr->SetConnected(false);
@@ -1663,7 +1663,7 @@
   auto session =
       std::make_unique<NiceMockBluetoothGattNotifySession>(characteristic);
 
-  ON_CALL(*session, Stop(_))
+  ON_CALL(*session, Stop_(_))
       .WillByDefault(testing::DoAll(
           InvokeWithoutArgs(
               session.get(),
diff --git a/content/test/data/remove_object_element_with_invalid_data.html b/content/test/data/remove_object_element_with_invalid_data.html
new file mode 100644
index 0000000..8f5f0411f
--- /dev/null
+++ b/content/test/data/remove_object_element_with_invalid_data.html
@@ -0,0 +1,17 @@
+<html>
+<head>
+<script>
+
+function DoLoad() {
+  let test_div = document.getElementById("test_div");
+  document.body.removeChild(test_div);
+}
+
+</script>
+</head>
+<body onload="DoLoad();">
+<div id="test_div">
+  <object data="INVALID"></object>
+</div>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
index 1c1d50c..fb2844e6 100644
--- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -170,3 +170,6 @@
 
 # Mark all webview tests as RetryOnFailure due to Nexus 5x driver bug.
 crbug.com/950932 [ android-webview-instrumentation qualcomm-adreno-(tm)-418 ] * [ RetryOnFailure ]
+
+# Failing on Nexus 5
+crbug.com/957714 [ android qualcomm-adreno-(tm)-330 ] Pixel_Canvas2DRedBox [ Failure ]
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index bd0847a6..8896e44 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -923,6 +923,28 @@
         ['android', 'opengles'], bug=906724)
     self.Skip('conformance/textures/video/*',
         ['android', 'opengles'], bug=906724)
+    # Failures with accelerated canvases on nexus5x
+    self.Fail('conformance/extensions/oes-texture-float-with-image.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/extensions/oes-texture-half-float-with-image.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/textures/image/' +
+        'tex-2d-luminance-luminance-unsigned_byte.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/textures/image/' +
+        'tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/textures/image/' +
+        'tex-2d-rgb-rgb-unsigned_short_5_6_5.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/textures/image/tex-2d-rgba-rgba-unsigned_byte.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/textures/image/' +
+        'tex-2d-rgba-rgba-unsigned_short_4_4_4_4.html',
+        ['android', 'opengles'], bug=957199)
+    self.Fail('conformance/textures/image/' +
+        'tex-2d-rgba-rgba-unsigned_short_5_5_5_1.html',
+        ['android', 'opengles'], bug=957199)
 
     # Canvas tests fail with missing fonts
     self.Fail('conformance/extensions/oes-texture-float-with-canvas.html',
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index 5c8f007..e23eabb 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -884,6 +884,10 @@
   auto_advance_ = auto_advance;
 }
 
+void NavigationSimulatorImpl::SetSSLInfo(const net::SSLInfo& ssl_info) {
+  ssl_info_ = ssl_info;
+}
+
 NavigationThrottle::ThrottleCheckResult
 NavigationSimulatorImpl::GetLastThrottleCheckResult() {
   return last_throttle_check_result_.value();
diff --git a/content/test/navigation_simulator_impl.h b/content/test/navigation_simulator_impl.h
index 598558c..3369c82 100644
--- a/content/test/navigation_simulator_impl.h
+++ b/content/test/navigation_simulator_impl.h
@@ -88,6 +88,7 @@
       service_manager::mojom::InterfaceProviderRequest request) override;
   void SetContentsMimeType(const std::string& contents_mime_type) override;
   void SetAutoAdvance(bool auto_advance) override;
+  void SetSSLInfo(const net::SSLInfo& ssl_info) override;
 
   NavigationThrottle::ThrottleCheckResult GetLastThrottleCheckResult() override;
   NavigationHandleImpl* GetNavigationHandle() const override;
@@ -131,8 +132,6 @@
     http_connection_info_ = info;
   }
 
-  void set_ssl_info(net::SSLInfo ssl_info) { ssl_info_ = ssl_info; }
-
   // Whether to drop the swap out ack of the previous RenderFrameHost during
   // cross-process navigations. By default this is false, set to true if you
   // want the old RenderFrameHost to be left in a pending swap out state.
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index bdedd20f..9d5af63e 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -107,12 +107,13 @@
 
   void CreatePortal(blink::mojom::PortalAssociatedRequest request,
                     CreatePortalCallback callback) override {
-    std::move(callback).Run(MSG_ROUTING_NONE, base::UnguessableToken());
+    std::move(callback).Run(MSG_ROUTING_NONE, base::UnguessableToken(),
+                            base::UnguessableToken());
   }
 
   void AdoptPortal(const base::UnguessableToken&,
                    AdoptPortalCallback callback) override {
-    std::move(callback).Run(MSG_ROUTING_NONE);
+    std::move(callback).Run(MSG_ROUTING_NONE, base::UnguessableToken());
   }
 
   void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override {}
diff --git a/device/bluetooth/bluetooth_adapter_winrt.cc b/device/bluetooth/bluetooth_adapter_winrt.cc
index ba6a6bc8..42cd63c7d 100644
--- a/device/bluetooth/bluetooth_adapter_winrt.cc
+++ b/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -27,6 +27,8 @@
 #include "base/strings/string_piece.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/win/core_winrt_util.h"
 #include "base/win/post_async_results.h"
@@ -45,6 +47,9 @@
 namespace uwp {
 using ABI::Windows::Devices::Bluetooth::BluetoothAdapter;
 }  // namespace uwp
+using ABI::Windows::Devices::Bluetooth::IBluetoothAdapter;
+using ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics;
+using ABI::Windows::Devices::Bluetooth::IID_IBluetoothAdapterStatics;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     BluetoothLEAdvertisementDataSection;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
@@ -70,13 +75,13 @@
     IBluetoothLEAdvertisementWatcher;
 using ABI::Windows::Devices::Bluetooth::Advertisement::
     IBluetoothLEManufacturerData;
-using ABI::Windows::Devices::Bluetooth::IBluetoothAdapter;
-using ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics;
 using ABI::Windows::Devices::Enumeration::DeviceInformation;
 using ABI::Windows::Devices::Enumeration::IDeviceInformation;
 using ABI::Windows::Devices::Enumeration::IDeviceInformationStatics;
 using ABI::Windows::Devices::Enumeration::IDeviceInformationUpdate;
 using ABI::Windows::Devices::Enumeration::IDeviceWatcher;
+using ABI::Windows::Devices::Enumeration::IID_IDeviceInformationStatics;
+using ABI::Windows::Devices::Radios::IID_IRadioStatics;
 using ABI::Windows::Devices::Radios::IRadio;
 using ABI::Windows::Devices::Radios::IRadioStatics;
 using ABI::Windows::Devices::Radios::Radio;
@@ -88,10 +93,10 @@
 using ABI::Windows::Devices::Radios::RadioState;
 using ABI::Windows::Devices::Radios::RadioState_Off;
 using ABI::Windows::Devices::Radios::RadioState_On;
-using ABI::Windows::Foundation::Collections::IVector;
-using ABI::Windows::Foundation::Collections::IVectorView;
 using ABI::Windows::Foundation::IAsyncOperation;
 using ABI::Windows::Foundation::IReference;
+using ABI::Windows::Foundation::Collections::IVector;
+using ABI::Windows::Foundation::Collections::IVectorView;
 using ABI::Windows::Storage::Streams::IBuffer;
 using ABI::Windows::Storage::Streams::IDataReader;
 using ABI::Windows::Storage::Streams::IDataReaderStatics;
@@ -462,6 +467,13 @@
                                   ExtractManufacturerData(advertisement.Get()));
 }
 
+decltype(&::RoGetAgileReference) LoadGetAgileReference() {
+  auto funcptr = reinterpret_cast<decltype(&::RoGetAgileReference)>(
+      ::GetProcAddress(::GetModuleHandle(L"Ole32.dll"), "RoGetAgileReference"));
+  CHECK(funcptr);
+  return funcptr;
+}
+
 }  // namespace
 
 std::string BluetoothAdapterWinrt::GetAddress() const {
@@ -622,12 +634,151 @@
   }
 }
 
+BluetoothAdapterWinrt::StaticsInterfaces::StaticsInterfaces(
+    ComPtr<IAgileReference> adapter_statics_in,
+    ComPtr<IAgileReference> device_information_statics_in,
+    ComPtr<IAgileReference> radio_statics_in)
+    : adapter_statics(adapter_statics_in),
+      device_information_statics(device_information_statics_in),
+      radio_statics(radio_statics_in) {}
+
+BluetoothAdapterWinrt::StaticsInterfaces::StaticsInterfaces(
+    const StaticsInterfaces& copy_from) = default;
+
+BluetoothAdapterWinrt::StaticsInterfaces::StaticsInterfaces() = default;
+
+BluetoothAdapterWinrt::StaticsInterfaces::~StaticsInterfaces() {}
+
 void BluetoothAdapterWinrt::Init(InitCallback init_cb) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  // We are wrapping |init_cb| in a ScopedClosureRunner to ensure it gets run no
-  // matter how the function exits. Furthermore, we set |is_initialized_| to
-  // true if adapter is still active when the callback gets run.
+  // Some of the initialization work requires loading libraries and should not
+  // be run on the browser main thread.
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&BluetoothAdapterWinrt::PerformSlowInitTasks),
+      base::BindOnce(&BluetoothAdapterWinrt::CompleteInit,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(init_cb)));
+}
+
+void BluetoothAdapterWinrt::InitForTests(
+    InitCallback init_cb,
+    ComPtr<IBluetoothAdapterStatics> bluetooth_adapter_statics,
+    ComPtr<IDeviceInformationStatics> device_information_statics,
+    ComPtr<IRadioStatics> radio_statics) {
+  if (!ResolveCoreWinRT()) {
+    CompleteInit(std::move(init_cb), StaticsInterfaces());
+  }
+
+  auto statics = PerformSlowInitTasks();
+  if (!bluetooth_adapter_statics) {
+    statics.adapter_statics->Resolve(IID_IBluetoothAdapterStatics,
+                                     &bluetooth_adapter_statics);
+  }
+  if (!device_information_statics) {
+    statics.device_information_statics->Resolve(IID_IDeviceInformationStatics,
+                                                &device_information_statics);
+  }
+  if (!radio_statics) {
+    statics.radio_statics->Resolve(IID_IRadioStatics, &radio_statics);
+  }
+
+  auto getAgileReferenceFunc = LoadGetAgileReference();
+
+  ComPtr<IAgileReference> radio_statics_agileref;
+  HRESULT hr =
+      getAgileReferenceFunc(AGILEREFERENCE_DEFAULT, IID_IRadioStatics,
+                            radio_statics.Get(), &radio_statics_agileref);
+  DCHECK(SUCCEEDED(hr));
+  ComPtr<IAgileReference> device_information_statics_agileref;
+  hr = getAgileReferenceFunc(
+      AGILEREFERENCE_DEFAULT, IID_IDeviceInformationStatics,
+      device_information_statics.Get(), &device_information_statics_agileref);
+  DCHECK(SUCCEEDED(hr));
+  ComPtr<IAgileReference> adapter_statics_agileref;
+  hr = getAgileReferenceFunc(
+      AGILEREFERENCE_DEFAULT, IID_IBluetoothAdapterStatics,
+      bluetooth_adapter_statics.Get(), &adapter_statics_agileref);
+  DCHECK(SUCCEEDED(hr));
+  CompleteInit(std::move(init_cb),
+               StaticsInterfaces(adapter_statics_agileref,
+                                 device_information_statics_agileref,
+                                 radio_statics_agileref));
+}
+
+// static
+BluetoothAdapterWinrt::StaticsInterfaces
+BluetoothAdapterWinrt::PerformSlowInitTasks() {
+  if (!ResolveCoreWinRT())
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+
+  ComPtr<IBluetoothAdapterStatics> adapter_statics;
+  HRESULT hr = base::win::GetActivationFactory<
+      IBluetoothAdapterStatics,
+      RuntimeClass_Windows_Devices_Bluetooth_BluetoothAdapter>(
+      &adapter_statics);
+  if (FAILED(hr)) {
+    VLOG(2) << "GetBluetoothAdapterStaticsActivationFactory failed: "
+            << logging::SystemErrorCodeToString(hr);
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+  }
+
+  ComPtr<IDeviceInformationStatics> device_information_statics;
+  hr = base::win::GetActivationFactory<
+      IDeviceInformationStatics,
+      RuntimeClass_Windows_Devices_Enumeration_DeviceInformation>(
+      &device_information_statics);
+  if (FAILED(hr)) {
+    VLOG(2) << "GetDeviceInformationStaticsActivationFactory failed: "
+            << logging::SystemErrorCodeToString(hr);
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+  }
+
+  ComPtr<IRadioStatics> radio_statics;
+  hr = base::win::GetActivationFactory<
+      IRadioStatics, RuntimeClass_Windows_Devices_Radios_Radio>(&radio_statics);
+  if (FAILED(hr)) {
+    VLOG(2) << "GetRadioStaticsActivationFactory failed: "
+            << logging::SystemErrorCodeToString(hr);
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+  }
+
+  auto getAgileReferenceFunc = LoadGetAgileReference();
+
+  ComPtr<IAgileReference> radio_statics_agileref;
+  hr = getAgileReferenceFunc(AGILEREFERENCE_DEFAULT,
+                             ABI::Windows::Devices::Radios::IID_IRadioStatics,
+                             radio_statics.Get(), &radio_statics_agileref);
+  if (FAILED(hr))
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+
+  ComPtr<IAgileReference> device_information_statics_agileref;
+  hr = getAgileReferenceFunc(
+      AGILEREFERENCE_DEFAULT,
+      ABI::Windows::Devices::Enumeration::IID_IDeviceInformationStatics,
+      device_information_statics.Get(), &device_information_statics_agileref);
+  if (FAILED(hr))
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+
+  ComPtr<IAgileReference> adapter_statics_agileref;
+  hr = getAgileReferenceFunc(
+      AGILEREFERENCE_DEFAULT,
+      ABI::Windows::Devices::Bluetooth::IID_IBluetoothAdapterStatics,
+      adapter_statics.Get(), &adapter_statics_agileref);
+  if (FAILED(hr))
+    return BluetoothAdapterWinrt::StaticsInterfaces();
+
+  return BluetoothAdapterWinrt::StaticsInterfaces(
+      adapter_statics_agileref, device_information_statics_agileref,
+      radio_statics_agileref);
+}
+
+void BluetoothAdapterWinrt::CompleteInit(InitCallback init_cb,
+                                         StaticsInterfaces statics) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  // We are wrapping |init_cb| in a ScopedClosureRunner to ensure it gets run
+  // no matter how the function exits. Furthermore, we set |is_initialized_|
+  // to true if adapter is still active when the callback gets run.
   base::ScopedClosureRunner on_init(base::BindOnce(
       [](base::WeakPtr<BluetoothAdapterWinrt> adapter, InitCallback init_cb) {
         if (adapter)
@@ -636,19 +787,22 @@
       },
       weak_ptr_factory_.GetWeakPtr(), std::move(init_cb)));
 
-  if (!ResolveCoreWinRT())
-    return;
-
-  ComPtr<IBluetoothAdapterStatics> adapter_statics;
-  HRESULT hr = GetBluetoothAdapterStaticsActivationFactory(&adapter_statics);
-  if (FAILED(hr)) {
-    VLOG(2) << "GetBluetoothAdapterStaticsActivationFactory failed: "
-            << logging::SystemErrorCodeToString(hr);
+  if (!statics.adapter_statics || !statics.device_information_statics ||
+      !statics.radio_statics) {
     return;
   }
 
+  HRESULT hr = statics.adapter_statics->Resolve(IID_IBluetoothAdapterStatics,
+                                                &bluetooth_adapter_statics_);
+  DCHECK(SUCCEEDED(hr));
+  hr = statics.device_information_statics->Resolve(
+      IID_IDeviceInformationStatics, &device_information_statics_);
+  DCHECK(SUCCEEDED(hr));
+  hr = statics.radio_statics->Resolve(IID_IRadioStatics, &radio_statics_);
+  DCHECK(SUCCEEDED(hr));
+
   ComPtr<IAsyncOperation<uwp::BluetoothAdapter*>> get_default_adapter_op;
-  hr = adapter_statics->GetDefaultAsync(&get_default_adapter_op);
+  hr = bluetooth_adapter_statics_->GetDefaultAsync(&get_default_adapter_op);
   if (FAILED(hr)) {
     VLOG(2) << "BluetoothAdapter::GetDefaultAsync failed: "
             << logging::SystemErrorCodeToString(hr);
@@ -667,8 +821,8 @@
 }
 
 bool BluetoothAdapterWinrt::SetPoweredImpl(bool powered) {
-  // Due to an issue on WoW64 we might fail to obtain the radio in OnGetRadio().
-  // This is why it can be null here.
+  // Due to an issue on WoW64 we might fail to obtain the radio in
+  // OnGetRadio(). This is why it can be null here.
   if (!radio_)
     return false;
 
@@ -761,8 +915,8 @@
     VLOG(2) << "Getting the Watcher Status failed: "
             << logging::SystemErrorCodeToString(hr);
   } else if (watcher_status == BluetoothLEAdvertisementWatcherStatus_Aborted) {
-    VLOG(2)
-        << "Starting Advertisement Watcher failed, it is in the Aborted state.";
+    VLOG(2) << "Starting Advertisement Watcher failed, it is in the Aborted "
+               "state.";
     RemoveAdvertisementReceivedHandler();
     ui_task_runner_->PostTask(
         FROM_HERE,
@@ -824,26 +978,6 @@
   NOTIMPLEMENTED();
 }
 
-HRESULT BluetoothAdapterWinrt::GetBluetoothAdapterStaticsActivationFactory(
-    IBluetoothAdapterStatics** statics) const {
-  return base::win::GetActivationFactory<
-      IBluetoothAdapterStatics,
-      RuntimeClass_Windows_Devices_Bluetooth_BluetoothAdapter>(statics);
-}
-
-HRESULT BluetoothAdapterWinrt::GetDeviceInformationStaticsActivationFactory(
-    IDeviceInformationStatics** statics) const {
-  return base::win::GetActivationFactory<
-      IDeviceInformationStatics,
-      RuntimeClass_Windows_Devices_Enumeration_DeviceInformation>(statics);
-}
-
-HRESULT BluetoothAdapterWinrt::GetRadioStaticsActivationFactory(
-    IRadioStatics** statics) const {
-  return base::win::GetActivationFactory<
-      IRadioStatics, RuntimeClass_Windows_Devices_Radios_Radio>(statics);
-}
-
 HRESULT
 BluetoothAdapterWinrt::ActivateBluetoothAdvertisementLEWatcherInstance(
     IBluetoothLEAdvertisementWatcher** instance) const {
@@ -912,18 +1046,9 @@
     return;
   }
 
-  ComPtr<IDeviceInformationStatics> device_information_statics;
-  hr =
-      GetDeviceInformationStaticsActivationFactory(&device_information_statics);
-  if (FAILED(hr)) {
-    VLOG(2) << "GetDeviceInformationStaticsActivationFactory failed: "
-            << logging::SystemErrorCodeToString(hr);
-    return;
-  }
-
   ComPtr<IAsyncOperation<DeviceInformation*>> create_from_id_op;
-  hr = device_information_statics->CreateFromIdAsync(device_id,
-                                                     &create_from_id_op);
+  hr = device_information_statics_->CreateFromIdAsync(device_id,
+                                                      &create_from_id_op);
   if (FAILED(hr)) {
     VLOG(2) << "CreateFromIdAsync failed: "
             << logging::SystemErrorCodeToString(hr);
@@ -958,16 +1083,8 @@
 
   name_ = base::win::ScopedHString(name).GetAsUTF8();
 
-  ComPtr<IRadioStatics> radio_statics;
-  hr = GetRadioStaticsActivationFactory(&radio_statics);
-  if (FAILED(hr)) {
-    VLOG(2) << "GetRadioStaticsActivationFactory failed: "
-            << logging::SystemErrorCodeToString(hr);
-    return;
-  }
-
   ComPtr<IAsyncOperation<RadioAccessStatus>> request_access_op;
-  hr = radio_statics->RequestAccessAsync(&request_access_op);
+  hr = radio_statics_->RequestAccessAsync(&request_access_op);
   if (FAILED(hr)) {
     VLOG(2) << "RequestAccessAsync failed: "
             << logging::SystemErrorCodeToString(hr);
@@ -1034,17 +1151,8 @@
 
   // Attempt to create a DeviceWatcher for powered radios, so that querying
   // the power state is still possible.
-  ComPtr<IDeviceInformationStatics> device_information_statics;
-  HRESULT hr =
-      GetDeviceInformationStaticsActivationFactory(&device_information_statics);
-  if (FAILED(hr)) {
-    VLOG(2) << "GetDeviceInformationStaticsActivationFactory failed: "
-            << logging::SystemErrorCodeToString(hr);
-    return;
-  }
-
   auto aqs_filter = base::win::ScopedHString::Create(kPoweredRadiosAqsFilter);
-  hr = device_information_statics->CreateWatcherAqsFilter(
+  HRESULT hr = device_information_statics_->CreateWatcherAqsFilter(
       aqs_filter.get(), &powered_radio_watcher_);
   if (FAILED(hr)) {
     VLOG(2) << "Creating Powered Radios Watcher failed: "
diff --git a/device/bluetooth/bluetooth_adapter_winrt.h b/device/bluetooth/bluetooth_adapter_winrt.h
index 3daa169..22985a9 100644
--- a/device/bluetooth/bluetooth_adapter_winrt.h
+++ b/device/bluetooth/bluetooth_adapter_winrt.h
@@ -79,6 +79,17 @@
   ~BluetoothAdapterWinrt() override;
 
   void Init(InitCallback init_cb);
+  // Allow tests to provide their own implementations of statics.
+  void InitForTests(
+      InitCallback init_cb,
+      Microsoft::WRL::ComPtr<
+          ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics>
+          bluetooth_adapter_statics,
+      Microsoft::WRL::ComPtr<
+          ABI::Windows::Devices::Enumeration::IDeviceInformationStatics>
+          device_information_statics,
+      Microsoft::WRL::ComPtr<ABI::Windows::Devices::Radios::IRadioStatics>
+          radio_statics);
 
   // BluetoothAdapter:
   bool SetPoweredImpl(bool powered) override;
@@ -97,18 +108,7 @@
   void RemovePairingDelegateInternal(
       BluetoothDevice::PairingDelegate* pairing_delegate) override;
 
-  // These are declared virtual so that they can be overridden by tests.
-  virtual HRESULT GetBluetoothAdapterStaticsActivationFactory(
-      ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics** statics)
-      const;
-
-  virtual HRESULT GetDeviceInformationStaticsActivationFactory(
-      ABI::Windows::Devices::Enumeration::IDeviceInformationStatics** statics)
-      const;
-
-  virtual HRESULT GetRadioStaticsActivationFactory(
-      ABI::Windows::Devices::Radios::IRadioStatics** statics) const;
-
+  // Declared virtual so that it can be overridden by tests.
   virtual HRESULT ActivateBluetoothAdvertisementLEWatcherInstance(
       ABI::Windows::Devices::Bluetooth::Advertisement::
           IBluetoothLEAdvertisementWatcher** instance) const;
@@ -120,6 +120,24 @@
       uint64_t raw_address);
 
  private:
+  struct StaticsInterfaces {
+    StaticsInterfaces(
+        Microsoft::WRL::ComPtr<IAgileReference>,   // IBluetoothStatics
+        Microsoft::WRL::ComPtr<IAgileReference>,   // IDeviceInformationStatics
+        Microsoft::WRL::ComPtr<IAgileReference>);  // IRadioStatics
+    StaticsInterfaces();
+    StaticsInterfaces(const StaticsInterfaces&);
+    ~StaticsInterfaces();
+
+    Microsoft::WRL::ComPtr<IAgileReference> adapter_statics;
+    Microsoft::WRL::ComPtr<IAgileReference> device_information_statics;
+    Microsoft::WRL::ComPtr<IAgileReference> radio_statics;
+  };
+
+  static StaticsInterfaces PerformSlowInitTasks();
+
+  void CompleteInit(InitCallback init_cb, StaticsInterfaces statics);
+
   void OnGetDefaultAdapter(
       base::ScopedClosureRunner on_init,
       Microsoft::WRL::ComPtr<
@@ -203,6 +221,15 @@
                              IBluetoothLEAdvertisementWatcher>
       ble_advertisement_watcher_;
 
+  Microsoft::WRL::ComPtr<
+      ABI::Windows::Devices::Bluetooth::IBluetoothAdapterStatics>
+      bluetooth_adapter_statics_;
+  Microsoft::WRL::ComPtr<
+      ABI::Windows::Devices::Enumeration::IDeviceInformationStatics>
+      device_information_statics_;
+  Microsoft::WRL::ComPtr<ABI::Windows::Devices::Radios::IRadioStatics>
+      radio_statics_;
+
   THREAD_CHECKER(thread_checker_);
 
   // Note: This should remain the last member so it'll be destroyed and
diff --git a/device/bluetooth/bluetooth_gatt_notify_session.cc b/device/bluetooth/bluetooth_gatt_notify_session.cc
index c0056b9..5d09e395f 100644
--- a/device/bluetooth/bluetooth_gatt_notify_session.cc
+++ b/device/bluetooth/bluetooth_gatt_notify_session.cc
@@ -39,12 +39,13 @@
          characteristic_->IsNotifying();
 }
 
-void BluetoothGattNotifySession::Stop(const base::Closure& callback) {
+void BluetoothGattNotifySession::Stop(base::OnceClosure callback) {
   active_ = false;
   if (characteristic_ != nullptr) {
-    characteristic_->StopNotifySession(this, callback);
+    characteristic_->StopNotifySession(this, std::move(callback));
   } else {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  std::move(callback));
   }
 }
 
diff --git a/device/bluetooth/bluetooth_gatt_notify_session.h b/device/bluetooth/bluetooth_gatt_notify_session.h
index 14999995..45119f9 100644
--- a/device/bluetooth/bluetooth_gatt_notify_session.h
+++ b/device/bluetooth/bluetooth_gatt_notify_session.h
@@ -44,7 +44,7 @@
   // necessarily stop value updates from the characteristic -- since updates
   // are shared among BluetoothGattNotifySession instances -- but it will
   // terminate this session.
-  virtual void Stop(const base::Closure& callback);
+  virtual void Stop(base::OnceClosure callback);
 
  private:
   // The associated characteristic.
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
index 87a115a..21a6ec2 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -61,43 +61,46 @@
 }
 
 BluetoothRemoteGattCharacteristic::NotifySessionCommand::NotifySessionCommand(
-    const ExecuteCallback& execute_callback,
-    const base::Closure& cancel_callback)
-    : execute_callback_(execute_callback), cancel_callback_(cancel_callback) {}
+    ExecuteCallback execute_callback,
+    base::OnceClosure cancel_callback)
+    : execute_callback_(std::move(execute_callback)),
+      cancel_callback_(std::move(cancel_callback)) {}
 
 BluetoothRemoteGattCharacteristic::NotifySessionCommand::
     ~NotifySessionCommand() = default;
 
 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute() {
-  execute_callback_.Run(COMMAND_NONE, RESULT_SUCCESS,
-                        BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
+  std::move(execute_callback_)
+      .Run(COMMAND_NONE, RESULT_SUCCESS,
+           BluetoothRemoteGattService::GATT_ERROR_UNKNOWN);
 }
 
 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Execute(
     Type previous_command_type,
     Result previous_command_result,
     BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
-  execute_callback_.Run(previous_command_type, previous_command_result,
-                        previous_command_error_code);
+  std::move(execute_callback_)
+      .Run(previous_command_type, previous_command_result,
+           previous_command_error_code);
 }
 
 void BluetoothRemoteGattCharacteristic::NotifySessionCommand::Cancel() {
-  cancel_callback_.Run();
+  std::move(cancel_callback_).Run();
 }
 
 void BluetoothRemoteGattCharacteristic::StartNotifySession(
-    const NotifySessionCallback& callback,
+    NotifySessionCallback callback,
     ErrorCallback error_callback) {
-  StartNotifySessionInternal(base::nullopt, callback,
+  StartNotifySessionInternal(base::nullopt, std::move(callback),
                              std::move(error_callback));
 }
 
 #if defined(OS_CHROMEOS)
 void BluetoothRemoteGattCharacteristic::StartNotifySession(
     NotificationType notification_type,
-    const NotifySessionCallback& callback,
+    NotifySessionCallback callback,
     ErrorCallback error_callback) {
-  StartNotifySessionInternal(notification_type, callback,
+  StartNotifySessionInternal(notification_type, std::move(callback),
                              std::move(error_callback));
 }
 #endif
@@ -121,20 +124,22 @@
 
 void BluetoothRemoteGattCharacteristic::StartNotifySessionInternal(
     const base::Optional<NotificationType>& notification_type,
-    const NotifySessionCallback& callback,
+    NotifySessionCallback callback,
     ErrorCallback error_callback) {
   auto repeating_error_callback =
       base::AdaptCallbackForRepeating(std::move(error_callback));
   NotifySessionCommand* command = new NotifySessionCommand(
-      base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
-                 GetWeakPtr(), notification_type, callback,
-                 repeating_error_callback),
-      base::Bind(&BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
-                 GetWeakPtr(),
-                 base::Bind(repeating_error_callback,
-                            BluetoothRemoteGattService::GATT_ERROR_FAILED)));
+      base::BindOnce(
+          &BluetoothRemoteGattCharacteristic::ExecuteStartNotifySession,
+          GetWeakPtr(), notification_type, std::move(callback),
+          repeating_error_callback),
+      base::BindOnce(
+          &BluetoothRemoteGattCharacteristic::CancelStartNotifySession,
+          GetWeakPtr(),
+          base::BindOnce(repeating_error_callback,
+                         BluetoothRemoteGattService::GATT_ERROR_FAILED)));
 
-  pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
+  pending_notify_commands_.push(base::WrapUnique(command));
   if (pending_notify_commands_.size() == 1) {
     command->Execute();
   }
@@ -155,7 +160,7 @@
           FROM_HERE,
           base::BindOnce(
               &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
-              GetWeakPtr(), callback));
+              GetWeakPtr(), std::move(callback)));
       return;
     } else {
       base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -191,7 +196,7 @@
         FROM_HERE,
         base::BindOnce(
             &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
-            GetWeakPtr(), callback));
+            GetWeakPtr(), std::move(callback)));
     return;
   }
 
@@ -224,20 +229,20 @@
                                      ? NotificationType::kNotification
                                      : NotificationType::kIndication),
 #endif
-      base::Bind(
+      base::BindOnce(
           &BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess,
-          GetWeakPtr(), callback),
+          GetWeakPtr(), std::move(callback)),
       base::BindOnce(
           &BluetoothRemoteGattCharacteristic::OnStartNotifySessionError,
           GetWeakPtr(), std::move(error_callback)));
 }
 
 void BluetoothRemoteGattCharacteristic::CancelStartNotifySession(
-    base::Closure callback) {
+    base::OnceClosure callback) {
   std::unique_ptr<NotifySessionCommand> command =
       std::move(pending_notify_commands_.front());
   pending_notify_commands_.pop();
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void BluetoothRemoteGattCharacteristic::OnStartNotifySessionSuccess(
@@ -248,7 +253,7 @@
   std::unique_ptr<device::BluetoothGattNotifySession> notify_session(
       new BluetoothGattNotifySession(weak_ptr_factory_.GetWeakPtr()));
   notify_sessions_.insert(notify_session.get());
-  callback.Run(std::move(notify_session));
+  std::move(callback).Run(std::move(notify_session));
 
   pending_notify_commands_.pop();
   if (!pending_notify_commands_.empty()) {
@@ -277,12 +282,14 @@
 
 void BluetoothRemoteGattCharacteristic::StopNotifySession(
     BluetoothGattNotifySession* session,
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
+  auto repeating_callback =
+      base::AdaptCallbackForRepeating(std::move(callback));
   NotifySessionCommand* command = new NotifySessionCommand(
       base::Bind(&BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession,
-                 GetWeakPtr(), session, callback),
+                 GetWeakPtr(), session, repeating_callback),
       base::Bind(&BluetoothRemoteGattCharacteristic::CancelStopNotifySession,
-                 GetWeakPtr(), callback));
+                 GetWeakPtr(), repeating_callback));
 
   pending_notify_commands_.push(std::unique_ptr<NotifySessionCommand>(command));
   if (pending_notify_commands_.size() == 1) {
@@ -292,7 +299,7 @@
 
 void BluetoothRemoteGattCharacteristic::ExecuteStopNotifySession(
     BluetoothGattNotifySession* session,
-    base::Closure callback,
+    base::OnceClosure callback,
     NotifySessionCommand::Type previous_command_type,
     NotifySessionCommand::Result previous_command_result,
     BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
@@ -305,7 +312,7 @@
         FROM_HERE,
         base::BindOnce(
             &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
-            GetWeakPtr(), session, callback,
+            GetWeakPtr(), session, std::move(callback),
             BluetoothRemoteGattService::GATT_ERROR_FAILED));
     return;
   }
@@ -316,7 +323,7 @@
         FROM_HERE,
         base::BindOnce(
             &BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
-            GetWeakPtr(), session, callback));
+            GetWeakPtr(), session, std::move(callback)));
     return;
   }
 
@@ -332,36 +339,40 @@
         FROM_HERE,
         base::BindOnce(
             &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
-            GetWeakPtr(), session, callback,
+            GetWeakPtr(), session, std::move(callback),
             BluetoothRemoteGattService::GATT_ERROR_FAILED));
     return;
   }
 
+  auto repeating_callback =
+      base::AdaptCallbackForRepeating(std::move(callback));
   UnsubscribeFromNotifications(
       ccc_descriptor[0],
-      base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
-                 GetWeakPtr(), session, callback),
-      base::Bind(&BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
-                 GetWeakPtr(), session, callback));
+      base::BindOnce(
+          &BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess,
+          GetWeakPtr(), session, repeating_callback),
+      base::BindOnce(
+          &BluetoothRemoteGattCharacteristic::OnStopNotifySessionError,
+          GetWeakPtr(), session, repeating_callback));
 }
 
 void BluetoothRemoteGattCharacteristic::CancelStopNotifySession(
-    base::Closure callback) {
+    base::OnceClosure callback) {
   std::unique_ptr<NotifySessionCommand> command =
       std::move(pending_notify_commands_.front());
   pending_notify_commands_.pop();
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void BluetoothRemoteGattCharacteristic::OnStopNotifySessionSuccess(
     BluetoothGattNotifySession* session,
-    base::Closure callback) {
+    base::OnceClosure callback) {
   std::unique_ptr<NotifySessionCommand> command =
       std::move(pending_notify_commands_.front());
 
   notify_sessions_.erase(session);
 
-  callback.Run();
+  std::move(callback).Run();
 
   pending_notify_commands_.pop();
   if (!pending_notify_commands_.empty()) {
@@ -374,14 +385,14 @@
 
 void BluetoothRemoteGattCharacteristic::OnStopNotifySessionError(
     BluetoothGattNotifySession* session,
-    base::Closure callback,
+    base::OnceClosure callback,
     BluetoothRemoteGattService::GattErrorCode error) {
   std::unique_ptr<NotifySessionCommand> command =
       std::move(pending_notify_commands_.front());
 
   notify_sessions_.erase(session);
 
-  callback.Run();
+  std::move(callback).Run();
 
   pending_notify_commands_.pop();
   if (!pending_notify_commands_.empty()) {
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.h b/device/bluetooth/bluetooth_remote_gatt_characteristic.h
index b907c1ad..6e26850 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.h
@@ -48,8 +48,8 @@
 
   // The NotifySessionCallback is used to return sessions after they have
   // been successfully started.
-  typedef base::Callback<void(std::unique_ptr<BluetoothGattNotifySession>)>
-      NotifySessionCallback;
+  using NotifySessionCallback =
+      base::OnceCallback<void(std::unique_ptr<BluetoothGattNotifySession>)>;
 
   ~BluetoothRemoteGattCharacteristic() override;
 
@@ -116,7 +116,7 @@
   //
   // To stop the flow of notifications, simply call the Stop method on the
   // BluetoothGattNotifySession object that you received in |callback|.
-  virtual void StartNotifySession(const NotifySessionCallback& callback,
+  virtual void StartNotifySession(NotifySessionCallback callback,
                                   ErrorCallback error_callback);
 #if defined(OS_CHROMEOS)
   // TODO(https://crbug.com/849359): This method should also be implemented on
@@ -126,7 +126,7 @@
   // notifications will be enabled.
   // https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518949-setnotifyvalue?language=objc#discussion
   virtual void StartNotifySession(NotificationType notification_type,
-                                  const NotifySessionCallback& callback,
+                                  NotifySessionCallback callback,
                                   ErrorCallback error_callback);
 #endif
 
@@ -185,12 +185,12 @@
   virtual void SubscribeToNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
       NotificationType notification_type,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) = 0;
 #else
   virtual void SubscribeToNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) = 0;
 #endif
 
@@ -200,7 +200,7 @@
   // listening to characteristic notifications on a particular platform.
   virtual void UnsubscribeFromNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) = 0;
 
   // Utility function to add a |descriptor| to the map of |descriptors_|.
@@ -227,22 +227,21 @@
   // Section 3.3.1.1. Characteristic Properties] requires this descriptor to be
   // present when notifications/indications are supported.
   virtual void StopNotifySession(BluetoothGattNotifySession* session,
-                                 const base::Closure& callback);
+                                 base::OnceClosure callback);
 
   class NotifySessionCommand {
    public:
     enum Type { COMMAND_NONE, COMMAND_START, COMMAND_STOP };
     enum Result { RESULT_SUCCESS, RESULT_ERROR };
 
-    typedef base::Callback<
-        void(Type, Result, BluetoothRemoteGattService::GattErrorCode)>
-        ExecuteCallback;
+    using ExecuteCallback = base::OnceCallback<
+        void(Type, Result, BluetoothRemoteGattService::GattErrorCode)>;
 
     ExecuteCallback execute_callback_;
-    base::Closure cancel_callback_;
+    base::OnceClosure cancel_callback_;
 
-    NotifySessionCommand(const ExecuteCallback& execute_callback,
-                         const base::Closure& cancel_callback);
+    NotifySessionCommand(ExecuteCallback execute_callback,
+                         base::OnceClosure cancel_callback);
     ~NotifySessionCommand();
 
     void Execute();
@@ -255,7 +254,7 @@
 
   void StartNotifySessionInternal(
       const base::Optional<NotificationType>& notification_type,
-      const NotifySessionCallback& callback,
+      NotifySessionCallback callback,
       ErrorCallback error_callback);
   void ExecuteStartNotifySession(
       const base::Optional<NotificationType>& notification_type,
@@ -264,7 +263,7 @@
       NotifySessionCommand::Type previous_command_type,
       NotifySessionCommand::Result previous_command_result,
       BluetoothRemoteGattService::GattErrorCode previous_command_error_code);
-  void CancelStartNotifySession(base::Closure callback);
+  void CancelStartNotifySession(base::OnceClosure callback);
   void OnStartNotifySessionSuccess(NotifySessionCallback callback);
   void OnStartNotifySessionError(
       ErrorCallback error_callback,
@@ -272,16 +271,16 @@
 
   void ExecuteStopNotifySession(
       BluetoothGattNotifySession* session,
-      base::Closure callback,
+      base::OnceClosure callback,
       NotifySessionCommand::Type previous_command_type,
       NotifySessionCommand::Result previous_command_result,
       BluetoothRemoteGattService::GattErrorCode previous_command_error_code);
-  void CancelStopNotifySession(base::Closure callback);
+  void CancelStopNotifySession(base::OnceClosure callback);
   void OnStopNotifySessionSuccess(BluetoothGattNotifySession* session,
-                                  base::Closure callback);
+                                  base::OnceClosure callback);
   void OnStopNotifySessionError(
       BluetoothGattNotifySession* session,
-      base::Closure callback,
+      base::OnceClosure callback,
       BluetoothRemoteGattService::GattErrorCode error);
   bool IsNotificationTypeSupported(
       const base::Optional<NotificationType>& notification_type);
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
index c488469b..0e76e676 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.cc
@@ -244,7 +244,7 @@
 
 void BluetoothRemoteGattCharacteristicAndroid::SubscribeToNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   if (!Java_ChromeBluetoothRemoteGattCharacteristic_setCharacteristicNotification(
           AttachCurrentThread(), j_characteristic_, true)) {
@@ -260,13 +260,13 @@
   std::vector<uint8_t> value(2);
   value[0] = hasNotify ? 1 : 2;
 
-  ccc_descriptor->WriteRemoteDescriptor(value, callback,
+  ccc_descriptor->WriteRemoteDescriptor(value, std::move(callback),
                                         std::move(error_callback));
 }
 
 void BluetoothRemoteGattCharacteristicAndroid::UnsubscribeFromNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   if (!Java_ChromeBluetoothRemoteGattCharacteristic_setCharacteristicNotification(
           AttachCurrentThread(), j_characteristic_, false)) {
@@ -281,7 +281,7 @@
   std::vector<uint8_t> value(2);
   value[0] = 0;
 
-  ccc_descriptor->WriteRemoteDescriptor(value, callback,
+  ccc_descriptor->WriteRemoteDescriptor(value, std::move(callback),
                                         std::move(error_callback));
 }
 
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h
index 0b13590f..6381134 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_android.h
@@ -100,11 +100,11 @@
 
  protected:
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* ccc_descriptor,
-                                const base::Closure& callback,
+                                base::OnceClosure callback,
                                 ErrorCallback error_callback) override;
   void UnsubscribeFromNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
  private:
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
index 975b62e..34e4a46 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.h
@@ -50,11 +50,11 @@
 
  protected:
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* ccc_descriptor,
-                                const base::Closure& callback,
+                                base::OnceClosure callback,
                                 ErrorCallback error_callback) override;
   void UnsubscribeFromNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
  private:
@@ -128,7 +128,7 @@
       write_characteristic_value_callbacks_;
   // Stores callbacks for SubscribeToNotifications and
   // UnsubscribeFromNotifications requests.
-  typedef std::pair<base::Closure, ErrorCallback> PendingNotifyCallbacks;
+  typedef std::pair<base::OnceClosure, ErrorCallback> PendingNotifyCallbacks;
   // Stores SubscribeToNotifications request callbacks.
   PendingNotifyCallbacks subscribe_to_notification_callbacks_;
   // Stores UnsubscribeFromNotifications request callbacks.
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
index dd4c77c..559a441 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_mac.mm
@@ -211,7 +211,7 @@
 
 void BluetoothRemoteGattCharacteristicMac::SubscribeToNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   VLOG(1) << *this << ": Subscribe to characteristic.";
   DCHECK(subscribe_to_notification_callbacks_.first.is_null());
@@ -219,13 +219,13 @@
   DCHECK(unsubscribe_from_notification_callbacks_.first.is_null());
   DCHECK(unsubscribe_from_notification_callbacks_.second.is_null());
   subscribe_to_notification_callbacks_ =
-      std::make_pair(callback, std::move(error_callback));
+      std::make_pair(std::move(callback), std::move(error_callback));
   [GetCBPeripheral() setNotifyValue:YES forCharacteristic:cb_characteristic_];
 }
 
 void BluetoothRemoteGattCharacteristicMac::UnsubscribeFromNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   VLOG(1) << *this << ": Unsubscribe from characteristic.";
   DCHECK(subscribe_to_notification_callbacks_.first.is_null());
@@ -233,7 +233,7 @@
   DCHECK(unsubscribe_from_notification_callbacks_.first.is_null());
   DCHECK(unsubscribe_from_notification_callbacks_.second.is_null());
   unsubscribe_from_notification_callbacks_ =
-      std::make_pair(callback, std::move(error_callback));
+      std::make_pair(std::move(callback), std::move(error_callback));
   [GetCBPeripheral() setNotifyValue:NO forCharacteristic:cb_characteristic_];
 }
 
@@ -351,7 +351,7 @@
     std::move(reentrant_safe_callbacks.second).Run(error_code);
     return;
   }
-  reentrant_safe_callbacks.first.Run();
+  std::move(reentrant_safe_callbacks.first).Run();
 }
 
 void BluetoothRemoteGattCharacteristicMac::DidDiscoverDescriptors() {
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
index 24e8641b..1acef67b 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_unittest.cc
@@ -2851,14 +2851,14 @@
 
   // Start notify session
   characteristic1_->StartNotifySession(
-      base::Bind(
+      base::BindOnce(
           [](BluetoothRemoteGattCharacteristic::NotifySessionCallback
-                 notifyCallback,
-             base::Closure stopNotifyCallback,
+                 notify_callback,
+             base::OnceClosure stop_notify_callback,
              std::unique_ptr<BluetoothGattNotifySession> session) {
             BluetoothGattNotifySession* s = session.get();
-            notifyCallback.Run(std::move(session));
-            s->Stop(stopNotifyCallback);
+            std::move(notify_callback).Run(std::move(session));
+            s->Stop(std::move(stop_notify_callback));
           },
           GetNotifyCallback(Call::EXPECTED),
           GetStopNotifyCallback(Call::EXPECTED)),
@@ -2905,12 +2905,12 @@
   EXPECT_EQ(characteristic1_, notify_sessions_[0]->GetCharacteristic());
   EXPECT_TRUE(characteristic1_->IsNotifying());
 
-  notify_sessions_[0]->Stop(base::Bind(
+  notify_sessions_[0]->Stop(base::BindOnce(
       [](BluetoothRemoteGattCharacteristic* characteristic,
          BluetoothRemoteGattCharacteristic::NotifySessionCallback
              notify_callback,
          BluetoothRemoteGattCharacteristic::ErrorCallback error_callback) {
-        characteristic->StartNotifySession(notify_callback,
+        characteristic->StartNotifySession(std::move(notify_callback),
                                            std::move(error_callback));
       },
       characteristic1_, GetNotifyCallback(Call::EXPECTED),
@@ -2961,12 +2961,12 @@
   EXPECT_EQ(characteristic1_, notify_sessions_[0]->GetCharacteristic());
   EXPECT_TRUE(characteristic1_->IsNotifying());
 
-  notify_sessions_[0]->Stop(base::Bind(
+  notify_sessions_[0]->Stop(base::BindOnce(
       [](BluetoothRemoteGattCharacteristic* characteristic,
          BluetoothRemoteGattCharacteristic::NotifySessionCallback
              notify_callback,
          BluetoothRemoteGattCharacteristic::ErrorCallback error_callback) {
-        characteristic->StartNotifySession(notify_callback,
+        characteristic->StartNotifySession(std::move(notify_callback),
                                            std::move(error_callback));
       },
       characteristic1_, GetNotifyCallback(Call::NOT_EXPECTED),
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc
index 4b2e41c..c495b889 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.cc
@@ -204,7 +204,7 @@
 
 void BluetoothRemoteGattCharacteristicWin::SubscribeToNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   task_manager_->PostRegisterGattCharacteristicValueChangedEvent(
       parent_service_->GetServicePath(), characteristic_info_.get(),
@@ -212,7 +212,8 @@
           ->GetWinDescriptorInfo(),
       base::BindOnce(
           &BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback,
-          weak_ptr_factory_.GetWeakPtr(), callback, std::move(error_callback)),
+          weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+          std::move(error_callback)),
       base::Bind(&BluetoothRemoteGattCharacteristicWin::
                      OnGattCharacteristicValueChanged,
                  weak_ptr_factory_.GetWeakPtr()));
@@ -220,10 +221,10 @@
 
 void BluetoothRemoteGattCharacteristicWin::UnsubscribeFromNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   // TODO(crbug.com/735828): Implement this method.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, std::move(callback));
 }
 
 void BluetoothRemoteGattCharacteristicWin::OnGetIncludedDescriptorsCallback(
@@ -380,14 +381,14 @@
 }
 
 void BluetoothRemoteGattCharacteristicWin::GattEventRegistrationCallback(
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback,
     BLUETOOTH_GATT_EVENT_HANDLE event_handle,
     HRESULT hr) {
   DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
   if (SUCCEEDED(hr)) {
     gatt_event_handle_ = event_handle;
-    callback.Run();
+    std::move(callback).Run();
   } else {
     std::move(error_callback).Run(HRESULTToGattErrorCode(hr));
   }
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h
index 07d50cef..714009f3 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_win.h
@@ -55,11 +55,11 @@
 
  protected:
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* ccc_descriptor,
-                                const base::Closure& callback,
+                                base::OnceClosure callback,
                                 ErrorCallback error_callback) override;
   void UnsubscribeFromNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
  private:
@@ -88,7 +88,7 @@
   BluetoothRemoteGattService::GattErrorCode HRESULTToGattErrorCode(HRESULT hr);
   void OnGattCharacteristicValueChanged(
       std::unique_ptr<std::vector<uint8_t>> new_value);
-  void GattEventRegistrationCallback(const base::Closure& callback,
+  void GattEventRegistrationCallback(base::OnceClosure callback,
                                      ErrorCallback error_callback,
                                      PVOID event_handle,
                                      HRESULT hr);
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
index 210a222..f471cc3 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.cc
@@ -363,7 +363,7 @@
 
 void BluetoothRemoteGattCharacteristicWinrt::SubscribeToNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   value_changed_token_ = AddTypedEventHandler(
       characteristic_.Get(), &IGattCharacteristic::add_ValueChanged,
@@ -384,12 +384,12 @@
       (GetProperties() & PROPERTY_NOTIFY)
           ? GattClientCharacteristicConfigurationDescriptorValue_Notify
           : GattClientCharacteristicConfigurationDescriptorValue_Indicate,
-      callback, std::move(error_callback));
+      std::move(callback), std::move(error_callback));
 }
 
 void BluetoothRemoteGattCharacteristicWinrt::UnsubscribeFromNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   auto repeating_error_callback =
       base::AdaptCallbackForRepeating(std::move(error_callback));
@@ -404,7 +404,8 @@
 
         std::move(callback).Run();
       },
-      weak_ptr_factory_.GetWeakPtr(), callback, repeating_error_callback);
+      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+      repeating_error_callback);
   WriteCccDescriptor(
       GattClientCharacteristicConfigurationDescriptorValue_None,
       // Wrap the success and error callbacks in a lambda, so that we can
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h
index 294fe05..b84862b1 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic_winrt.h
@@ -61,11 +61,11 @@
  protected:
   // BluetoothRemoteGattCharacteristic:
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* ccc_descriptor,
-                                const base::Closure& callback,
+                                base::OnceClosure callback,
                                 ErrorCallback error_callback) override;
   void UnsubscribeFromNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
  private:
diff --git a/device/bluetooth/bluetooth_uuid.cc b/device/bluetooth/bluetooth_uuid.cc
index 88e27363..0fbf22d4 100644
--- a/device/bluetooth/bluetooth_uuid.cc
+++ b/device/bluetooth/bluetooth_uuid.cc
@@ -15,6 +15,7 @@
 #include <objbase.h>
 
 #include "base/strings/string16.h"
+#include "base/win/win_util.h"
 #endif  // defined(OS_WIN)
 
 namespace device {
@@ -79,16 +80,12 @@
 
 #if defined(OS_WIN)
 BluetoothUUID::BluetoothUUID(GUID uuid) {
-  // 36 chars for UUID + 2 chars for braces + 1 char for null-terminator.
-  constexpr int kBufferSize = 39;
-  wchar_t buffer[kBufferSize];
-  int result = ::StringFromGUID2(uuid, buffer, kBufferSize);
-  DCHECK_EQ(kBufferSize, result);
+  auto buffer = base::win::String16FromGUID(uuid);
   DCHECK_EQ('{', buffer[0]);
   DCHECK_EQ('}', buffer[37]);
 
-  GetCanonicalUuid(base::WideToUTF8(base::WStringPiece(buffer).substr(1, 36)),
-                   &value_, &canonical_value_, &format_);
+  GetCanonicalUuid(base::WideToUTF8(buffer.substr(1, 36)), &value_,
+                   &canonical_value_, &format_);
   DCHECK_EQ(kFormat128Bit, format_);
 }
 #endif  // defined(OS_WIN)
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
index dc305125..c3f4568 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/callback_helpers.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
@@ -213,7 +214,7 @@
 #if defined(OS_CHROMEOS)
     NotificationType notification_type,
 #endif
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   bluez::BluezDBusManager::Get()
       ->GetBluetoothGattCharacteristicClient()
@@ -222,9 +223,9 @@
 #if defined(OS_CHROMEOS)
           notification_type,
 #endif
-          base::Bind(
+          base::BindOnce(
               &BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifySuccess,
-              weak_ptr_factory_.GetWeakPtr(), callback),
+              weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
           base::BindOnce(
               &BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifyError,
               weak_ptr_factory_.GetWeakPtr(), std::move(error_callback)));
@@ -232,17 +233,20 @@
 
 void BluetoothRemoteGattCharacteristicBlueZ::UnsubscribeFromNotifications(
     device::BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
+  auto repeating_callback =
+      base::AdaptCallbackForRepeating(std::move(callback));
   bluez::BluezDBusManager::Get()
       ->GetBluetoothGattCharacteristicClient()
       ->StopNotify(
           object_path(),
-          base::Bind(
+          base::BindOnce(
               &BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifySuccess,
-              weak_ptr_factory_.GetWeakPtr(), callback),
-          base::Bind(&BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError,
-                     weak_ptr_factory_.GetWeakPtr(), callback));
+              weak_ptr_factory_.GetWeakPtr(), repeating_callback),
+          base::BindOnce(
+              &BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError,
+              weak_ptr_factory_.GetWeakPtr(), repeating_callback));
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::GattDescriptorAdded(
@@ -329,11 +333,11 @@
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifySuccess(
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   VLOG(1) << "Started notifications from characteristic: "
           << object_path().value();
   has_notify_session_ = true;
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::OnStartNotifyError(
@@ -349,13 +353,13 @@
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifySuccess(
-    const base::Closure& callback) {
+    base::OnceClosure callback) {
   has_notify_session_ = false;
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::OnStopNotifyError(
-    const base::Closure& callback,
+    base::OnceClosure callback,
     const std::string& error_name,
     const std::string& error_message) {
   VLOG(1) << "Call to stop notifications failed for characteristic: "
@@ -363,7 +367,7 @@
           << error_message;
 
   // Since this is a best effort operation, treat this as success.
-  OnStopNotifySuccess(callback);
+  OnStopNotifySuccess(std::move(callback));
 }
 
 void BluetoothRemoteGattCharacteristicBlueZ::OnReadError(
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
index 96ce7bd2..2e4d7f8 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.h
@@ -70,17 +70,17 @@
   void SubscribeToNotifications(
       device::BluetoothRemoteGattDescriptor* ccc_descriptor,
       NotificationType notification_type,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 #else
   void SubscribeToNotifications(
       device::BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 #endif
   void UnsubscribeFromNotifications(
       device::BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
  private:
@@ -98,7 +98,7 @@
 
   // Called by dbus:: on successful completion of a request to start
   // notifications.
-  void OnStartNotifySuccess(const base::Closure& callback);
+  void OnStartNotifySuccess(base::OnceClosure callback);
 
   // Called by dbus:: on unsuccessful completion of a request to start
   // notifications.
@@ -108,11 +108,11 @@
 
   // Called by dbus:: on successful completion of a request to stop
   // notifications.
-  void OnStopNotifySuccess(const base::Closure& callback);
+  void OnStopNotifySuccess(base::OnceClosure callback);
 
   // Called by dbus:: on unsuccessful completion of a request to stop
   // notifications.
-  void OnStopNotifyError(const base::Closure& callback,
+  void OnStopNotifyError(base::OnceClosure callback,
                          const std::string& error_name,
                          const std::string& error_message);
 
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
index b8f5d19..8f8e25f 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.cc
@@ -76,11 +76,11 @@
 // Called back when subscribing or unsubscribing to a remote characteristic.
 // If |success| is true, run |callback|. Otherwise run |error_callback|.
 void OnSubscribeOrUnsubscribe(
-    const base::Closure& callback,
+    base::OnceClosure callback,
     BluetoothGattCharacteristic::ErrorCallback error_callback,
     bool success) {
   if (success)
-    callback.Run();
+    std::move(callback).Run();
   else
     std::move(error_callback).Run(BluetoothGattService::GATT_ERROR_FAILED);
 }
@@ -155,7 +155,7 @@
 
 void BluetoothRemoteGattCharacteristicCast::SubscribeToNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   DVLOG(2) << __func__ << " " << GetIdentifier();
 
@@ -165,13 +165,13 @@
   (void)ccc_descriptor;
 
   remote_characteristic_->SetRegisterNotification(
-      true, base::BindOnce(&OnSubscribeOrUnsubscribe, callback,
+      true, base::BindOnce(&OnSubscribeOrUnsubscribe, std::move(callback),
                            std::move(error_callback)));
 }
 
 void BluetoothRemoteGattCharacteristicCast::UnsubscribeFromNotifications(
     BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   DVLOG(2) << __func__ << " " << GetIdentifier();
 
@@ -181,7 +181,7 @@
   (void)ccc_descriptor;
 
   remote_characteristic_->SetRegisterNotification(
-      false, base::BindOnce(&OnSubscribeOrUnsubscribe, callback,
+      false, base::BindOnce(&OnSubscribeOrUnsubscribe, std::move(callback),
                             std::move(error_callback)));
 }
 
diff --git a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h
index ff9d577..f42c545f 100644
--- a/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h
+++ b/device/bluetooth/cast/bluetooth_remote_gatt_characteristic_cast.h
@@ -58,11 +58,11 @@
  private:
   // BluetoothRemoteGattCharacteristic implementation:
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* ccc_descriptor,
-                                const base::Closure& callback,
+                                base::OnceClosure callback,
                                 ErrorCallback error_callback) override;
   void UnsubscribeFromNotifications(
       BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
   // Called when the remote characteristic has been read or the operation has
diff --git a/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc b/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc
index 55cea8a..5dbdc04 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc
+++ b/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.cc
@@ -177,7 +177,7 @@
 #if defined(OS_CHROMEOS)
       device::BluetoothGattCharacteristic::NotificationType notification_type,
 #endif
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override {
     dbus::ObjectProxy* object_proxy =
         object_manager_->GetObjectProxy(object_path);
@@ -197,7 +197,7 @@
     object_proxy->CallMethodWithErrorCallback(
         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
         base::BindOnce(&BluetoothGattCharacteristicClientImpl::OnSuccess,
-                       weak_ptr_factory_.GetWeakPtr(), callback),
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
         base::BindOnce(&BluetoothGattCharacteristicClientImpl::OnError,
                        weak_ptr_factory_.GetWeakPtr(),
                        std::move(error_callback)));
@@ -205,7 +205,7 @@
 
   // BluetoothGattCharacteristicClient override.
   void StopNotify(const dbus::ObjectPath& object_path,
-                  const base::Closure& callback,
+                  base::OnceClosure callback,
                   ErrorCallback error_callback) override {
     dbus::ObjectProxy* object_proxy =
         object_manager_->GetObjectProxy(object_path);
@@ -221,7 +221,7 @@
     object_proxy->CallMethodWithErrorCallback(
         &method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
         base::BindOnce(&BluetoothGattCharacteristicClientImpl::OnSuccess,
-                       weak_ptr_factory_.GetWeakPtr(), callback),
+                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
         base::BindOnce(&BluetoothGattCharacteristicClientImpl::OnError,
                        weak_ptr_factory_.GetWeakPtr(),
                        std::move(error_callback)));
diff --git a/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h b/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h
index 1f1a46c..b76a831 100644
--- a/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h
+++ b/device/bluetooth/dbus/bluetooth_gatt_characteristic_client.h
@@ -127,11 +127,11 @@
   virtual void StartNotify(
       const dbus::ObjectPath& object_path,
       device::BluetoothGattCharacteristic::NotificationType notification_type,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) = 0;
 #else
   virtual void StartNotify(const dbus::ObjectPath& object_path,
-                           const base::Closure& callback,
+                           base::OnceClosure callback,
                            ErrorCallback error_callback) = 0;
 #endif
 
@@ -139,7 +139,7 @@
   // object path |object_path|. Invokes |callback| on success and
   // |error_callback| on failure.
   virtual void StopNotify(const dbus::ObjectPath& object_path,
-                          const base::Closure& callback,
+                          base::OnceClosure callback,
                           ErrorCallback error_callback) = 0;
 
   // Creates the instance.
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc
index 0b99f643..f19914c 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.cc
@@ -328,7 +328,7 @@
 #if defined(OS_CHROMEOS)
     device::BluetoothGattCharacteristic::NotificationType notification_type,
 #endif
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   if (!IsHeartRateVisible()) {
     std::move(error_callback).Run(kUnknownCharacteristicError, "");
@@ -354,13 +354,13 @@
 
   // Respond asynchronously.
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, callback,
+      FROM_HERE, std::move(callback),
       base::TimeDelta::FromMilliseconds(kStartNotifyResponseIntervalMs));
 }
 
 void FakeBluetoothGattCharacteristicClient::StopNotify(
     const dbus::ObjectPath& object_path,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   if (!IsHeartRateVisible()) {
     std::move(error_callback).Run(kUnknownCharacteristicError, "");
@@ -382,7 +382,7 @@
 
   heart_rate_measurement_properties_->notifying.ReplaceValue(false);
 
-  callback.Run();
+  std::move(callback).Run();
 }
 
 void FakeBluetoothGattCharacteristicClient::ExposeHeartRateCharacteristics(
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h
index a5c21c59..7810e27e 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h
@@ -67,16 +67,16 @@
   void StartNotify(
       const dbus::ObjectPath& object_path,
       device::BluetoothGattCharacteristic::NotificationType notification_type,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 #else
   void StartNotify(const dbus::ObjectPath& object_path,
-                   const base::Closure& callback,
+                   base::OnceClosure callback,
                    ErrorCallback error_callback) override;
 #endif
 
   void StopNotify(const dbus::ObjectPath& object_path,
-                  const base::Closure& callback,
+                  base::OnceClosure callback,
                   ErrorCallback error_callback) override;
 
   // Makes the group of characteristics belonging to a particular GATT based
diff --git a/device/bluetooth/test/bluetooth_test_win.cc b/device/bluetooth/test/bluetooth_test_win.cc
index 93caee5..5cf7bdf 100644
--- a/device/bluetooth/test/bluetooth_test_win.cc
+++ b/device/bluetooth/test/bluetooth_test_win.cc
@@ -149,7 +149,14 @@
         device_information_(std::move(device_information)),
         watcher_(Make<FakeBluetoothLEAdvertisementWatcherWinrt>()),
         bluetooth_test_winrt_(bluetooth_test_winrt) {
-    Init(std::move(init_cb));
+    ComPtr<IBluetoothAdapterStatics> bluetooth_adapter_statics;
+    Make<FakeBluetoothAdapterStaticsWinrt>(adapter_).CopyTo(
+        (IBluetoothAdapterStatics**)&bluetooth_adapter_statics);
+    ComPtr<IDeviceInformationStatics> device_information_statics;
+    Make<FakeDeviceInformationStaticsWinrt>(device_information_)
+        .CopyTo((IDeviceInformationStatics**)&device_information_statics);
+    InitForTests(std::move(init_cb), bluetooth_adapter_statics,
+                 device_information_statics, nullptr);
   }
 
   FakeBluetoothLEAdvertisementWatcherWinrt* watcher() { return watcher_.Get(); }
@@ -157,15 +164,15 @@
  protected:
   ~TestBluetoothAdapterWinrt() override = default;
 
-  HRESULT GetBluetoothAdapterStaticsActivationFactory(
-      IBluetoothAdapterStatics** statics) const override {
+  HRESULT GetTestBluetoothAdapterStaticsActivationFactory(
+      IBluetoothAdapterStatics** statics) const {
     auto adapter_statics = Make<FakeBluetoothAdapterStaticsWinrt>(adapter_);
     return adapter_statics.CopyTo(statics);
   }
 
   HRESULT
-  GetDeviceInformationStaticsActivationFactory(
-      IDeviceInformationStatics** statics) const override {
+  GetTestDeviceInformationStaticsActivationFactory(
+      IDeviceInformationStatics** statics) const {
     auto device_information_statics =
         Make<FakeDeviceInformationStaticsWinrt>(device_information_);
     return device_information_statics.CopyTo(statics);
diff --git a/device/bluetooth/test/fake_remote_gatt_characteristic.cc b/device/bluetooth/test/fake_remote_gatt_characteristic.cc
index 21945dd..3f4eb2a 100644
--- a/device/bluetooth/test/fake_remote_gatt_characteristic.cc
+++ b/device/bluetooth/test/fake_remote_gatt_characteristic.cc
@@ -184,24 +184,25 @@
 #if defined(OS_CHROMEOS)
     NotificationType notification_type,
 #endif
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&FakeRemoteGattCharacteristic::
-                                    DispatchSubscribeToNotificationsResponse,
-                                weak_ptr_factory_.GetWeakPtr(), callback,
-                                std::move(error_callback)));
+      FROM_HERE,
+      base::BindOnce(&FakeRemoteGattCharacteristic::
+                         DispatchSubscribeToNotificationsResponse,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+                     std::move(error_callback)));
 }
 
 void FakeRemoteGattCharacteristic::UnsubscribeFromNotifications(
     device::BluetoothRemoteGattDescriptor* ccc_descriptor,
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::BindOnce(&FakeRemoteGattCharacteristic::
                          DispatchUnsubscribeFromNotificationsResponse,
-                     weak_ptr_factory_.GetWeakPtr(), callback,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                      std::move(error_callback)));
 }
 
@@ -252,7 +253,7 @@
 }
 
 void FakeRemoteGattCharacteristic::DispatchSubscribeToNotificationsResponse(
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   DCHECK(next_subscribe_to_notifications_response_);
   uint16_t gatt_code = next_subscribe_to_notifications_response_.value();
@@ -260,7 +261,7 @@
 
   switch (gatt_code) {
     case mojom::kGATTSuccess:
-      callback.Run();
+      std::move(callback).Run();
       break;
     case mojom::kGATTInvalidHandle:
       std::move(error_callback)
@@ -272,7 +273,7 @@
 }
 
 void FakeRemoteGattCharacteristic::DispatchUnsubscribeFromNotificationsResponse(
-    const base::Closure& callback,
+    base::OnceClosure callback,
     ErrorCallback error_callback) {
   DCHECK(next_unsubscribe_from_notifications_response_);
   uint16_t gatt_code = next_unsubscribe_from_notifications_response_.value();
@@ -280,7 +281,7 @@
 
   switch (gatt_code) {
     case mojom::kGATTSuccess:
-      callback.Run();
+      std::move(callback).Run();
       break;
     case mojom::kGATTInvalidHandle:
       std::move(error_callback)
diff --git a/device/bluetooth/test/fake_remote_gatt_characteristic.h b/device/bluetooth/test/fake_remote_gatt_characteristic.h
index 7a36031..8dc91e0 100644
--- a/device/bluetooth/test/fake_remote_gatt_characteristic.h
+++ b/device/bluetooth/test/fake_remote_gatt_characteristic.h
@@ -101,18 +101,18 @@
   void SubscribeToNotifications(
       device::BluetoothRemoteGattDescriptor* ccc_descriptor,
       NotificationType notification_type,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 #else
   // device::BluetoothRemoteGattCharacteristic overrides:
   void SubscribeToNotifications(
       device::BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 #endif
   void UnsubscribeFromNotifications(
       device::BluetoothRemoteGattDescriptor* ccc_descriptor,
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback) override;
 
  private:
@@ -121,10 +121,10 @@
   void DispatchWriteResponse(base::OnceClosure callback,
                              ErrorCallback error_callback,
                              const std::vector<uint8_t>& value);
-  void DispatchSubscribeToNotificationsResponse(const base::Closure& callback,
+  void DispatchSubscribeToNotificationsResponse(base::OnceClosure callback,
                                                 ErrorCallback error_callback);
   void DispatchUnsubscribeFromNotificationsResponse(
-      const base::Closure& callback,
+      base::OnceClosure callback,
       ErrorCallback error_callback);
 
   const std::string characteristic_id_;
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h
index c88da93..a521b62 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h
+++ b/device/bluetooth/test/mock_bluetooth_gatt_characteristic.h
@@ -52,23 +52,24 @@
   MOCK_METHOD1(UpdateValue, bool(const std::vector<uint8_t>&));
 #if defined(OS_CHROMEOS)
   void StartNotifySession(NotificationType t,
-                          const NotifySessionCallback& c,
+                          NotifySessionCallback c,
                           ErrorCallback ec) override {
     StartNotifySession_(t, c, ec);
   }
   MOCK_METHOD3(StartNotifySession_,
-               void(NotificationType,
-                    const NotifySessionCallback&,
-                    ErrorCallback&));
+               void(NotificationType, NotifySessionCallback&, ErrorCallback&));
 #endif
-  void StartNotifySession(const NotifySessionCallback& c,
-                          ErrorCallback ec) override {
+  void StartNotifySession(NotifySessionCallback c, ErrorCallback ec) override {
     StartNotifySession_(c, ec);
   }
   MOCK_METHOD2(StartNotifySession_,
-               void(const NotifySessionCallback&, ErrorCallback&));
-  MOCK_METHOD2(StopNotifySession,
-               void(BluetoothGattNotifySession*, const base::Closure&));
+               void(NotifySessionCallback&, ErrorCallback&));
+  void StopNotifySession(BluetoothGattNotifySession* s,
+                         base::OnceClosure c) override {
+    StopNotifySession_(s, c);
+  }
+  MOCK_METHOD2(StopNotifySession_,
+               void(BluetoothGattNotifySession*, base::OnceClosure&));
   void ReadRemoteCharacteristic(ValueCallback c, ErrorCallback ec) override {
     ReadRemoteCharacteristic_(c, ec);
   }
@@ -102,34 +103,34 @@
 #if defined(OS_CHROMEOS)
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* d,
                                 NotificationType t,
-                                const base::Closure& c,
+                                base::OnceClosure c,
                                 ErrorCallback ec) override {
     SubscribeToNotifications_(d, t, c, ec);
   }
   MOCK_METHOD4(SubscribeToNotifications_,
                void(BluetoothRemoteGattDescriptor*,
                     NotificationType,
-                    const base::Closure&,
+                    base::OnceClosure&,
                     ErrorCallback&));
 #else
   void SubscribeToNotifications(BluetoothRemoteGattDescriptor* d,
-                                const base::Closure& c,
+                                base::OnceClosure c,
                                 ErrorCallback ec) override {
     SubscribeToNotifications_(d, c, ec);
   }
   MOCK_METHOD3(SubscribeToNotifications_,
                void(BluetoothRemoteGattDescriptor*,
-                    const base::Closure&,
+                    base::OnceClosure&,
                     ErrorCallback&));
 #endif
   void UnsubscribeFromNotifications(BluetoothRemoteGattDescriptor* d,
-                                    const base::Closure& c,
+                                    base::OnceClosure c,
                                     ErrorCallback ec) override {
     UnsubscribeFromNotifications_(d, c, ec);
   }
   MOCK_METHOD3(UnsubscribeFromNotifications_,
                void(BluetoothRemoteGattDescriptor*,
-                    const base::Closure&,
+                    base::OnceClosure&,
                     ErrorCallback&));
 
  private:
diff --git a/device/bluetooth/test/mock_bluetooth_gatt_notify_session.h b/device/bluetooth/test/mock_bluetooth_gatt_notify_session.h
index 90f0bf5..1139bd1 100644
--- a/device/bluetooth/test/mock_bluetooth_gatt_notify_session.h
+++ b/device/bluetooth/test/mock_bluetooth_gatt_notify_session.h
@@ -27,7 +27,8 @@
   ~MockBluetoothGattNotifySession() override;
 
   MOCK_METHOD0(IsActive, bool());
-  MOCK_METHOD1(Stop, void(const base::Closure&));
+  void Stop(base::OnceClosure c) override { Stop_(c); }
+  MOCK_METHOD1(Stop_, void(base::OnceClosure&));
 
   // Starts notifying the adapter's observers that the characteristic's value
   // changed.
diff --git a/device/fido/ble/fido_ble_connection_unittest.cc b/device/fido/ble/fido_ble_connection_unittest.cc
index 31bec45..0860a05a 100644
--- a/device/fido/ble/fido_ble_connection_unittest.cc
+++ b/device/fido/ble/fido_ble_connection_unittest.cc
@@ -181,13 +181,14 @@
             }));
 
     ON_CALL(*fido_status_, StartNotifySession_(_, _))
-        .WillByDefault(Invoke([this](
-                                  const auto& callback,
-                                  BluetoothGattCharacteristic::ErrorCallback&) {
-          notify_session_ = new NiceMockBluetoothGattNotifySession(
-              fido_status_->GetWeakPtr());
-          callback.Run(base::WrapUnique(notify_session_));
-        }));
+        .WillByDefault(Invoke(
+            [this](BluetoothRemoteGattCharacteristic::NotifySessionCallback&
+                       callback,
+                   BluetoothRemoteGattCharacteristic::ErrorCallback&) {
+              notify_session_ = new NiceMockBluetoothGattNotifySession(
+                  fido_status_->GetWeakPtr());
+              std::move(callback).Run(base::WrapUnique(notify_session_));
+            }));
   }
 
   void SimulateGattDiscoveryComplete(bool complete) {
diff --git a/device/fido/fido_device_authenticator.cc b/device/fido/fido_device_authenticator.cc
index 8fb7b29..920408f 100644
--- a/device/fido/fido_device_authenticator.cc
+++ b/device/fido/fido_device_authenticator.cc
@@ -89,18 +89,23 @@
   MakeCredential(
       MakeCredentialTask::GetTouchRequest(device()),
       base::BindOnce(
-          [](base::OnceCallback<void()> callback, CtapDeviceResponseCode status,
+          [](std::string authenticator_id, base::OnceCallback<void()> callback,
+             CtapDeviceResponseCode status,
              base::Optional<AuthenticatorMakeCredentialResponse>) {
             // If the device didn't understand/process the request it may
             // fail immediately. Rather than count that as a touch, ignore
             // those cases completely.
             if (status == CtapDeviceResponseCode::kSuccess ||
                 status == CtapDeviceResponseCode::kCtap2ErrPinNotSet ||
-                status == CtapDeviceResponseCode::kCtap2ErrPinInvalid) {
+                status == CtapDeviceResponseCode::kCtap2ErrPinInvalid ||
+                status == CtapDeviceResponseCode::kCtap2ErrPinAuthInvalid) {
               std::move(callback).Run();
+              return;
             }
+            FIDO_LOG(DEBUG) << "Ignoring status " << static_cast<int>(status)
+                            << " from " << authenticator_id;
           },
-          std::move(callback)));
+          GetId(), std::move(callback)));
 }
 
 void FidoDeviceAuthenticator::GetRetries(GetRetriesCallback callback) {
diff --git a/docs/infra/cq_builders.md b/docs/infra/cq_builders.md
index 3f33b6f..19259a98 100644
--- a/docs/infra/cq_builders.md
+++ b/docs/infra/cq_builders.md
@@ -70,10 +70,10 @@
 
 * [win10_chromium_x64_rel_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win10_chromium_x64_rel_ng) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win10_chromium_x64_rel_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win10_chromium_x64_rel_ng))
 
-* [win7-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win7-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win7-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win7-rel))
-
 * [win_chromium_compile_dbg_ng](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/win_chromium_compile_dbg_ng) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/win_chromium_compile_dbg_ng)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+win_chromium_compile_dbg_ng))
 
+  TODO(crbug.com/948145): Re-add win7-rel once the bot has recovered.
+
 
 ## Optional builders
 
@@ -142,6 +142,7 @@
 * [dawn-mac-x64-deps-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/dawn-mac-x64-deps-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/dawn-mac-x64-deps-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+dawn-mac-x64-deps-rel))
 
   Path regular expressions:
+    * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
     * [`//testing/buildbot/chromium.dawn.json`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:testing/buildbot/chromium.dawn.json)
     * [`//third_party/blink/renderer/modules/webgpu/.+`](https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/webgpu/)
     * [`//third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu)
@@ -151,6 +152,7 @@
 * [dawn-win10-x64-deps-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/dawn-win10-x64-deps-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/dawn-win10-x64-deps-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+dawn-win10-x64-deps-rel))
 
   Path regular expressions:
+    * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
     * [`//testing/buildbot/chromium.dawn.json`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:testing/buildbot/chromium.dawn.json)
     * [`//third_party/blink/renderer/modules/webgpu/.+`](https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/webgpu/)
     * [`//third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu)
@@ -160,6 +162,7 @@
 * [dawn-win10-x86-deps-rel](https://ci.chromium.org/p/chromium/builders/luci.chromium.try/dawn-win10-x86-deps-rel) ([`commit-queue.cfg` entry](https://cs.chromium.org/search/?q=package:%5Echromium$+file:commit-queue.cfg+chromium/try/dawn-win10-x86-deps-rel)) ([matching builders](https://cs.chromium.org/search/?q=file:trybots.py+dawn-win10-x86-deps-rel))
 
   Path regular expressions:
+    * [`//gpu/.+`](https://cs.chromium.org/chromium/src/gpu/)
     * [`//testing/buildbot/chromium.dawn.json`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:testing/buildbot/chromium.dawn.json)
     * [`//third_party/blink/renderer/modules/webgpu/.+`](https://cs.chromium.org/chromium/src/third_party/blink/renderer/modules/webgpu/)
     * [`//third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu`](https://cs.chromium.org/search/?q=package:%5Echromium$+file:third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu)
diff --git a/extensions/browser/api/BUILD.gn b/extensions/browser/api/BUILD.gn
index c7fc2d0..937b7b8 100644
--- a/extensions/browser/api/BUILD.gn
+++ b/extensions/browser/api/BUILD.gn
@@ -46,6 +46,7 @@
     "//extensions/browser/api/app_runtime",
     "//extensions/browser/api/app_window",
     "//extensions/browser/api/audio",
+    "//extensions/browser/api/automation_internal",
     "//extensions/browser/api/bluetooth",
     "//extensions/browser/api/bluetooth_low_energy",
     "//extensions/browser/api/bluetooth_socket",
diff --git a/extensions/browser/api/DEPS b/extensions/browser/api/DEPS
index 1659dd6..f5d55d7 100644
--- a/extensions/browser/api/DEPS
+++ b/extensions/browser/api/DEPS
@@ -4,4 +4,6 @@
   "+services/device/public",
   "+storage/browser/fileapi",
   "+storage/common/fileapi",
+  "+ui/accessibility",
+  "+ui/aura",
 ]
diff --git a/extensions/browser/api/automation_internal/BUILD.gn b/extensions/browser/api/automation_internal/BUILD.gn
new file mode 100644
index 0000000..0e1c50e
--- /dev/null
+++ b/extensions/browser/api/automation_internal/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//extensions/buildflags/buildflags.gni")
+
+assert(enable_extensions,
+       "Cannot depend on extensions because enable_extensions=false.")
+
+source_set("automation_internal") {
+  sources = [
+    "automation_event_router.cc",
+    "automation_event_router.h",
+    "automation_event_router_interface.h",
+    "automation_internal_api.cc",
+    "automation_internal_api.h",
+    "automation_internal_api_delegate.cc",
+    "automation_internal_api_delegate.h",
+  ]
+
+  public_deps = [
+    "//extensions/browser:browser_sources",
+  ]
+
+  deps = [
+    "//components/prefs",
+    "//extensions/common/api",
+  ]
+}
diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc b/extensions/browser/api/automation_internal/automation_event_router.cc
similarity index 84%
rename from chrome/browser/extensions/api/automation_internal/automation_event_router.cc
rename to extensions/browser/api/automation_internal/automation_event_router.cc
index 892cd3c..91b0894 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc
+++ b/extensions/browser/api/automation_internal/automation_event_router.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
 
 #include <algorithm>
 #include <memory>
@@ -12,24 +12,20 @@
 #include "base/stl_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/extensions/api/automation_internal.h"
-#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_process_host.h"
+#include "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
+#include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/event_router.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_messages.h"
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
 
-#if defined(USE_AURA)
-#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
-#endif
-
 namespace extensions {
 
 // static
@@ -40,28 +36,28 @@
 }
 
 AutomationEventRouter::AutomationEventRouter()
-    : active_profile_(ProfileManager::GetActiveUserProfile()) {
+    : active_context_(ExtensionsAPIClient::Get()
+                          ->GetAutomationInternalApiDelegate()
+                          ->GetActiveUserContext()) {
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
                  content::NotificationService::AllBrowserContextsAndSources());
   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
                  content::NotificationService::AllBrowserContextsAndSources());
 #if defined(USE_AURA)
   // Not reset because |this| is leaked.
-  AutomationManagerAura::GetInstance()->set_event_bundle_sink(this);
+  ExtensionsAPIClient::Get()
+      ->GetAutomationInternalApiDelegate()
+      ->SetEventBundleSink(this);
 #endif
 }
 
-AutomationEventRouter::~AutomationEventRouter() {
-}
+AutomationEventRouter::~AutomationEventRouter() {}
 
 void AutomationEventRouter::RegisterListenerForOneTree(
     const ExtensionId& extension_id,
     int listener_process_id,
     ui::AXTreeID source_ax_tree_id) {
-  Register(extension_id,
-           listener_process_id,
-           source_ax_tree_id,
-           false);
+  Register(extension_id, listener_process_id, source_ax_tree_id, false);
 }
 
 void AutomationEventRouter::RegisterListenerWithDesktopPermission(
@@ -72,8 +68,12 @@
 
 void AutomationEventRouter::DispatchAccessibilityEvents(
     const ExtensionMsg_AccessibilityEventBundleParams& event_bundle) {
-  if (active_profile_ != ProfileManager::GetActiveUserProfile()) {
-    active_profile_ = ProfileManager::GetActiveUserProfile();
+  content::BrowserContext* active_context =
+      ExtensionsAPIClient::Get()
+          ->GetAutomationInternalApiDelegate()
+          ->GetActiveUserContext();
+  if (active_context_ != active_context) {
+    active_context_ = active_context;
     UpdateActiveProfile();
   }
 
@@ -87,7 +87,7 @@
     content::RenderProcessHost* rph =
         content::RenderProcessHost::FromID(listener.process_id);
     rph->Send(new ExtensionMsg_AccessibilityEventBundle(
-        event_bundle, listener.is_active_profile));
+        event_bundle, listener.is_active_context));
   }
 }
 
@@ -112,7 +112,7 @@
   if (listeners_.empty())
     return;
 
-  browser_context = browser_context ? browser_context : active_profile_;
+  browser_context = browser_context ? browser_context : active_context_;
   std::unique_ptr<base::ListValue> args(
       api::automation_internal::OnAccessibilityTreeDestroyed::Create(
           tree_id.ToString()));
@@ -126,10 +126,13 @@
     tree_destroyed_callback_for_test_.Run(tree_id);
 }
 
-void AutomationEventRouter::DispatchActionResult(const ui::AXActionData& data,
-                                                 bool result) {
+void AutomationEventRouter::DispatchActionResult(
+    const ui::AXActionData& data,
+    bool result,
+    content::BrowserContext* browser_context) {
   CHECK(!data.source_extension_id.empty());
 
+  browser_context = browser_context ? browser_context : active_context_;
   if (listeners_.empty())
     return;
 
@@ -139,8 +142,8 @@
   auto event = std::make_unique<Event>(
       events::AUTOMATION_INTERNAL_ON_ACTION_RESULT,
       api::automation_internal::OnActionResult::kEventName, std::move(args),
-      active_profile_);
-  EventRouter::Get(active_profile_)
+      active_context_);
+  EventRouter::Get(active_context_)
       ->DispatchEventToExtension(data.source_extension_id, std::move(event));
 }
 
@@ -174,19 +177,17 @@
   auto event = std::make_unique<Event>(
       events::AUTOMATION_INTERNAL_ON_GET_TEXT_LOCATION_RESULT,
       api::automation_internal::OnGetTextLocationResult::kEventName,
-      std::move(args), active_profile_);
-  EventRouter::Get(active_profile_)
+      std::move(args), active_context_);
+  EventRouter::Get(active_context_)
       ->DispatchEventToExtension(data.source_extension_id, std::move(event));
 }
 
-AutomationEventRouter::AutomationListener::AutomationListener() {
-}
+AutomationEventRouter::AutomationListener::AutomationListener() {}
 
 AutomationEventRouter::AutomationListener::AutomationListener(
     const AutomationListener& other) = default;
 
-AutomationEventRouter::AutomationListener::~AutomationListener() {
-}
+AutomationEventRouter::AutomationListener::~AutomationListener() {}
 
 void AutomationEventRouter::Register(const ExtensionId& extension_id,
                                      int listener_process_id,
@@ -264,15 +265,15 @@
     content::RenderProcessHost* rph =
         content::RenderProcessHost::FromID(listener.process_id);
 
-    // The purpose of is_active_profile is to ensure different instances of
+    // The purpose of is_active_context is to ensure different instances of
     // the same extension running in different profiles don't interfere with
     // one another. If an automation extension is only running in one profile,
     // always mark it as active. If it's running in two or more profiles,
     // only mark one as active.
-    listener.is_active_profile = (extension_id_count == 1 ||
-                                  rph->GetBrowserContext() == active_profile_);
+    listener.is_active_context = (extension_id_count == 1 ||
+                                  rph->GetBrowserContext() == active_context_);
 #else
-    listener.is_active_profile = true;
+    listener.is_active_context = true;
 #endif
   }
 }
diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.h b/extensions/browser/api/automation_internal/automation_event_router.h
similarity index 84%
rename from chrome/browser/extensions/api/automation_internal/automation_event_router.h
rename to extensions/browser/api/automation_internal/automation_event_router.h
index cda183d..15cb451 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_event_router.h
+++ b/extensions/browser/api/automation_internal/automation_event_router.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
-#define CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
+#ifndef EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
+#define EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
 
 #include <set>
 #include <vector>
@@ -11,17 +11,16 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/singleton.h"
-#include "chrome/common/extensions/api/automation_internal.h"
 #include "content/public/browser/ax_event_notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/browser/api/automation_internal/automation_event_router_interface.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/extension_messages.h"
 #include "ui/accessibility/ax_event_bundle_sink.h"
 #include "ui/accessibility/ax_tree_id.h"
 
-class Profile;
-
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -37,7 +36,8 @@
 struct AutomationListener;
 
 class AutomationEventRouter : public ui::AXEventBundleSink,
-                              public content::NotificationObserver {
+                              public content::NotificationObserver,
+                              public AutomationEventRouterInterface {
  public:
   static AutomationEventRouter* GetInstance();
 
@@ -56,18 +56,22 @@
                                              int listener_process_id);
 
   void DispatchAccessibilityEvents(
-      const ExtensionMsg_AccessibilityEventBundleParams& events);
+      const ExtensionMsg_AccessibilityEventBundleParams& events) override;
 
   void DispatchAccessibilityLocationChange(
-      const ExtensionMsg_AccessibilityLocationChangeParams& params);
+      const ExtensionMsg_AccessibilityLocationChangeParams& params) override;
 
   // Notify all automation extensions that an accessibility tree was
   // destroyed. If |browser_context| is null,
-  void DispatchTreeDestroyedEvent(ui::AXTreeID tree_id,
-                                  content::BrowserContext* browser_context);
+  void DispatchTreeDestroyedEvent(
+      ui::AXTreeID tree_id,
+      content::BrowserContext* browser_context) override;
 
   // Notify the source extension of the action of an action result.
-  void DispatchActionResult(const ui::AXActionData& data, bool result);
+  void DispatchActionResult(
+      const ui::AXActionData& data,
+      bool result,
+      content::BrowserContext* browser_context = nullptr) override;
 
   void SetTreeDestroyedCallbackForTest(
       base::RepeatingCallback<void(ui::AXTreeID)> cb);
@@ -86,7 +90,7 @@
     int process_id;
     bool desktop;
     std::set<ui::AXTreeID> tree_ids;
-    bool is_active_profile;
+    bool is_active_context;
   };
 
   AutomationEventRouter();
@@ -123,7 +127,7 @@
   content::NotificationRegistrar registrar_;
   std::vector<AutomationListener> listeners_;
 
-  Profile* active_profile_;
+  content::BrowserContext* active_context_;
 
   base::RepeatingCallback<void(ui::AXTreeID)> tree_destroyed_callback_for_test_;
 
@@ -134,4 +138,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
+#endif  // EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_H_
diff --git a/chromecast/browser/extensions/api/automation_internal/automation_event_router_interface.h b/extensions/browser/api/automation_internal/automation_event_router_interface.h
similarity index 76%
rename from chromecast/browser/extensions/api/automation_internal/automation_event_router_interface.h
rename to extensions/browser/api/automation_internal/automation_event_router_interface.h
index 5a008dc..e22a737 100644
--- a/chromecast/browser/extensions/api/automation_internal/automation_event_router_interface.h
+++ b/extensions/browser/api/automation_internal/automation_event_router_interface.h
@@ -2,17 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_INTERFACE_H_
-#define CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_INTERFACE_H_
+#ifndef EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_INTERFACE_H_
+#define EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_INTERFACE_H_
 
 #include <set>
 #include <vector>
 
 #include "base/macros.h"
-#include "chromecast/common/extensions_api/automation_internal.h"
 #include "content/public/browser/ax_event_notification_details.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/common/extension_id.h"
 #include "extensions/common/extension_messages.h"
 
@@ -28,8 +28,9 @@
 struct ExtensionMsg_AccessibilityLocationChangeParams;
 
 namespace extensions {
-namespace cast {
 
+// NOTE: This interface is implemented in chromecast/internal by
+// ax_tree_source_flutter_unittest.cc
 class AutomationEventRouterInterface {
  public:
   virtual void DispatchAccessibilityEvents(
@@ -48,7 +49,7 @@
   virtual void DispatchActionResult(
       const ui::AXActionData& data,
       bool result,
-      content::BrowserContext* active_profile) = 0;
+      content::BrowserContext* browser_context = nullptr) = 0;
 
   AutomationEventRouterInterface() {}
   virtual ~AutomationEventRouterInterface() {}
@@ -56,7 +57,6 @@
   DISALLOW_COPY_AND_ASSIGN(AutomationEventRouterInterface);
 };
 
-}  // namespace cast
 }  // namespace extensions
 
-#endif  // CHROMECAST_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_INTERFACE_H_
+#endif  // EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_EVENT_ROUTER_INTERFACE_H_
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/extensions/browser/api/automation_internal/automation_internal_api.cc
similarity index 90%
rename from chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
rename to extensions/browser/api/automation_internal/automation_internal_api.cc
index e7970e2..f6de53d 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc
+++ b/extensions/browser/api/automation_internal/automation_internal_api.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/api/automation_internal/automation_internal_api.h"
+#include "extensions/browser/api/automation_internal/automation_internal_api.h"
 
 #include <stdint.h>
 
@@ -14,16 +14,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
-#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
-#include "chrome/browser/extensions/chrome_extension_function_details.h"
-#include "chrome/browser/extensions/extension_tab_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/extensions/api/automation.h"
-#include "chrome/common/extensions/api/automation_internal.h"
-#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "content/public/browser/ax_event_notification_details.h"
 #include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/browser_context.h"
@@ -37,6 +27,11 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
+#include "extensions/browser/api/automation_internal/automation_event_router.h"
+#include "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/common/api/automation.h"
+#include "extensions/common/api/automation_internal.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/common/manifest_handlers/automation.h"
 #include "extensions/common/permissions/permissions_data.h"
@@ -46,7 +41,6 @@
 #include "ui/accessibility/ax_tree_id_registry.h"
 
 #if defined(USE_AURA)
-#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
 #include "ui/aura/env.h"
 #endif
 
@@ -137,23 +131,6 @@
   const extensions::AutomationInternalQuerySelectorFunction::Callback callback_;
 };
 
-bool CanRequestAutomation(const Extension* extension,
-                          const AutomationInfo* automation_info,
-                          content::WebContents* contents) {
-  if (automation_info->desktop)
-    return true;
-
-  const GURL& url = contents->GetURL();
-  // TODO(aboxhall): check for webstore URL
-  if (automation_info->matches.MatchesURL(url))
-    return true;
-
-  int tab_id = ExtensionTabUtil::GetTabId(contents);
-  std::string unused_error;
-  return extension->permissions_data()->CanAccessPage(url, tab_id,
-                                                      &unused_error);
-}
-
 }  // namespace
 
 // Helper class that receives accessibility data from |WebContents|.
@@ -198,8 +175,7 @@
       return;
 
     AutomationEventRouter::GetInstance()->DispatchTreeDestroyedEvent(
-        tree_id,
-        browser_context_);
+        tree_id, browser_context_);
   }
 
   void RenderFrameHostChanged(content::RenderFrameHost* old_host,
@@ -266,8 +242,7 @@
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(AutomationWebContentsObserver)
 
-ExtensionFunction::ResponseAction
-AutomationInternalEnableTabFunction::Run() {
+ExtensionFunction::ResponseAction AutomationInternalEnableTabFunction::Run() {
   const AutomationInfo* automation_info = AutomationInfo::Get(extension());
   EXTENSION_FUNCTION_VALIDATE(automation_info);
 
@@ -275,33 +250,31 @@
   std::unique_ptr<Params> params(Params::Create(*args_));
   EXTENSION_FUNCTION_VALIDATE(params.get());
   content::WebContents* contents = NULL;
+  AutomationInternalApiDelegate* automation_api_delegate =
+      ExtensionsAPIClient::Get()->GetAutomationInternalApiDelegate();
   int tab_id = -1;
   if (params->args.tab_id.get()) {
     tab_id = *params->args.tab_id;
-    if (!ExtensionTabUtil::GetTabById(
-            tab_id, browser_context(), include_incognito_information(),
-            NULL, /* browser out param*/
-            NULL, /* tab_strip out param */
-            &contents, NULL /* tab_index out param */)) {
-      return RespondNow(Error(tabs_constants::kTabNotFoundError,
-                              base::NumberToString(tab_id)));
+    std::string error_string;
+    if (!automation_api_delegate->GetTabById(tab_id, browser_context(),
+                                             include_incognito_information(),
+                                             &contents, &error_string)) {
+      return RespondNow(Error(error_string, base::NumberToString(tab_id)));
     }
   } else {
-    contents = ChromeExtensionFunctionDetails(this)
-                   .GetCurrentBrowser()
-                   ->tab_strip_model()
-                   ->GetActiveWebContents();
+    contents = automation_api_delegate->GetActiveWebContents(this);
     if (!contents)
       return RespondNow(Error("No active tab"));
 
-    tab_id = ExtensionTabUtil::GetTabId(contents);
+    tab_id = automation_api_delegate->GetTabId(contents);
   }
 
   content::RenderFrameHost* rfh = contents->GetMainFrame();
   if (!rfh)
     return RespondNow(Error("Could not enable accessibility for active tab"));
 
-  if (!CanRequestAutomation(extension(), automation_info, contents)) {
+  if (!automation_api_delegate->CanRequestAutomation(
+          extension(), automation_info, contents)) {
     return RespondNow(Error(kCannotRequestAutomationOnPage));
   }
 
@@ -312,9 +285,7 @@
 
   // This gets removed when the extension process dies.
   AutomationEventRouter::GetInstance()->RegisterListenerForOneTree(
-      extension_id(),
-      source_process_id(),
-      ax_tree_id);
+      extension_id(), source_process_id(), ax_tree_id);
 
   return RespondNow(
       ArgumentList(api::automation_internal::EnableTab::Results::Create(
@@ -547,7 +518,9 @@
     if (rfh) {
       content::WebContents* contents =
           content::WebContents::FromRenderFrameHost(rfh);
-      if (!CanRequestAutomation(extension(), automation_info, contents)) {
+      if (!ExtensionsAPIClient::Get()
+               ->GetAutomationInternalApiDelegate()
+               ->CanRequestAutomation(extension(), automation_info, contents)) {
         return RespondNow(Error(kCannotRequestAutomationOnPage));
       }
 
@@ -595,8 +568,10 @@
   AutomationEventRouter::GetInstance()->RegisterListenerWithDesktopPermission(
       extension_id(), source_process_id());
 
-  AutomationManagerAura::GetInstance()->Enable();
-  ui::AXTreeID ax_tree_id = AutomationManagerAura::GetInstance()->ax_tree_id();
+  AutomationInternalApiDelegate* automation_api_delegate =
+      ExtensionsAPIClient::Get()->GetAutomationInternalApiDelegate();
+  automation_api_delegate->EnableDesktop();
+  ui::AXTreeID ax_tree_id = automation_api_delegate->GetAXTreeID();
   return RespondNow(
       ArgumentList(api::automation_internal::EnableDesktop::Results::Create(
           ax_tree_id.ToString())));
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.h b/extensions/browser/api/automation_internal/automation_internal_api.h
similarity index 87%
rename from chrome/browser/extensions/api/automation_internal/automation_internal_api.h
rename to extensions/browser/api/automation_internal/automation_internal_api.h
index 8450b31..45c6dda 100644
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.h
+++ b/extensions/browser/api/automation_internal/automation_internal_api.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
-#define CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
+#ifndef EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
+#define EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
 
 #include <string>
 
@@ -80,8 +80,8 @@
                              AUTOMATIONINTERNAL_QUERYSELECTOR)
 
  public:
-  typedef base::Callback<void(const std::string& error,
-                              int result_acc_obj_id)> Callback;
+  typedef base::Callback<void(const std::string& error, int result_acc_obj_id)>
+      Callback;
 
  protected:
   ~AutomationInternalQuerySelectorFunction() override {}
@@ -98,4 +98,4 @@
 
 }  // namespace extensions
 
-#endif  // CHROME_BROWSER_EXTENSIONS_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
+#endif  // EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_H_
diff --git a/extensions/browser/api/automation_internal/automation_internal_api_delegate.cc b/extensions/browser/api/automation_internal/automation_internal_api_delegate.cc
new file mode 100644
index 0000000..80bad851
--- /dev/null
+++ b/extensions/browser/api/automation_internal/automation_internal_api_delegate.cc
@@ -0,0 +1,12 @@
+// 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 "extensions/browser/api/automation_internal/automation_internal_api_delegate.h"
+
+namespace extensions {
+
+AutomationInternalApiDelegate::AutomationInternalApiDelegate() {}
+AutomationInternalApiDelegate::~AutomationInternalApiDelegate() = default;
+
+}  // namespace extensions
diff --git a/extensions/browser/api/automation_internal/automation_internal_api_delegate.h b/extensions/browser/api/automation_internal/automation_internal_api_delegate.h
new file mode 100644
index 0000000..485aaea
--- /dev/null
+++ b/extensions/browser/api/automation_internal/automation_internal_api_delegate.h
@@ -0,0 +1,69 @@
+// 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 EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_DELEGATE_H_
+#define EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_DELEGATE_H_
+
+#include <memory>
+
+#include "extensions/common/extension_id.h"
+#include "extensions/common/extension_messages.h"
+
+class UIThreadExtensionFunction;
+
+namespace extensions {
+class AutomationInternalApiDelegate;
+struct AutomationInfo;
+class Extension;
+}  // namespace extensions
+
+namespace content {
+class BrowserContext;
+class WebContents;
+}  // namespace content
+
+namespace ui {
+class AXTreeID;
+class AXEventBundleSink;
+}  // namespace ui
+
+namespace extensions {
+
+class AutomationInternalApiDelegate {
+ public:
+  AutomationInternalApiDelegate();
+  virtual ~AutomationInternalApiDelegate();
+
+  // Returns true if the extension is permitted to use the automation
+  // API for the given web contents.
+  virtual bool CanRequestAutomation(const Extension* extension,
+                                    const AutomationInfo* automation_info,
+                                    content::WebContents* contents) = 0;
+  // Sets |contents| to point to the web contents object associated with the
+  // given tab id.  Otherwise, sets |error_msg| with a reason why the
+  // tab could not be found. Returns true on success.
+  virtual bool GetTabById(int tab_id,
+                          content::BrowserContext* browser_context,
+                          bool include_incognito,
+                          content::WebContents** contents,
+                          std::string* error_msg) = 0;
+  // Finds the tab id associated with the given web contents object.
+  virtual int GetTabId(content::WebContents* contents) = 0;
+  // Retrieves the active web contents.
+  virtual content::WebContents* GetActiveWebContents(
+      UIThreadExtensionFunction* function) = 0;
+  // Starts managing automation nodes on the desktop.
+  virtual void EnableDesktop() = 0;
+  // Gets the ax tree id for the nodes being managed for the desktop.
+  virtual ui::AXTreeID GetAXTreeID() = 0;
+  // Gets the active user context, if multiple contexts are managed by
+  // the delegate. Otherwise, may return null.
+  virtual content::BrowserContext* GetActiveUserContext() = 0;
+  // Sets the event bundle sink that should be set on the automation manager.
+  virtual void SetEventBundleSink(ui::AXEventBundleSink* sink) = 0;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_AUTOMATION_INTERNAL_AUTOMATION_INTERNAL_API_DELEGATE_H_
diff --git a/extensions/browser/api/declarative_net_request/file_sequence_helper.cc b/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
index 0c9bca88..aa55d5e3 100644
--- a/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
+++ b/extensions/browser/api/declarative_net_request/file_sequence_helper.cc
@@ -246,7 +246,8 @@
   // ensure we don't leave the actual files in an inconsistent state.
   std::unique_ptr<RulesetSource> temporary_source =
       RulesetSource::CreateTemporarySource(source.id(), source.priority(),
-                                           source.rule_count_limit());
+                                           source.rule_count_limit(),
+                                           source.extension_id());
   if (!temporary_source) {
     *error = kInternalErrorUpdatingDynamicRules;
     *status = UpdateDynamicRulesStatus::kErrorCreateTemporarySource;
diff --git a/extensions/browser/api/declarative_net_request/indexed_rule.cc b/extensions/browser/api/declarative_net_request/indexed_rule.cc
index 9fb78e8..18fc192 100644
--- a/extensions/browser/api/declarative_net_request/indexed_rule.cc
+++ b/extensions/browser/api/declarative_net_request/indexed_rule.cc
@@ -255,6 +255,11 @@
   return true;
 }
 
+// Returns if the redirect URL will be used as a relative URL.
+bool IsRedirectUrlRelative(const std::string& redirect_url) {
+  return !redirect_url.empty() && redirect_url[0] == '/';
+}
+
 }  // namespace
 
 IndexedRule::IndexedRule() = default;
@@ -264,6 +269,7 @@
 
 // static
 ParseResult IndexedRule::CreateIndexedRule(dnr_api::Rule parsed_rule,
+                                           const GURL& base_url,
                                            IndexedRule* indexed_rule) {
   DCHECK(indexed_rule);
   DCHECK(IsAPIAvailable());
@@ -278,8 +284,11 @@
         parsed_rule.action.redirect_url->empty()) {
       return ParseResult::ERROR_EMPTY_REDIRECT_URL;
     }
-    if (!GURL(*parsed_rule.action.redirect_url).is_valid())
+
+    if (!IsRedirectUrlRelative(*parsed_rule.action.redirect_url) &&
+        !GURL(*parsed_rule.action.redirect_url).is_valid()) {
       return ParseResult::ERROR_INVALID_REDIRECT_URL;
+    }
     if (!parsed_rule.priority)
       return ParseResult::ERROR_EMPTY_REDIRECT_RULE_PRIORITY;
     if (*parsed_rule.priority < kMinValidPriority)
@@ -325,8 +334,16 @@
     return ParseResult::ERROR_NON_ASCII_EXCLUDED_DOMAIN;
   }
 
-  if (is_redirect_rule)
-    indexed_rule->redirect_url = std::move(*parsed_rule.action.redirect_url);
+  if (is_redirect_rule) {
+    if (IsRedirectUrlRelative(*parsed_rule.action.redirect_url)) {
+      GURL::Replacements relative_path;
+      relative_path.SetPathStr(parsed_rule.action.redirect_url->c_str());
+      indexed_rule->redirect_url =
+          base_url.ReplaceComponents(relative_path).spec();
+    } else {
+      indexed_rule->redirect_url = std::move(*parsed_rule.action.redirect_url);
+    }
+  }
 
   // Parse the |anchor_left|, |anchor_right|, |url_pattern_type| and
   // |url_pattern| fields.
diff --git a/extensions/browser/api/declarative_net_request/indexed_rule.h b/extensions/browser/api/declarative_net_request/indexed_rule.h
index 3231477..42790e64d 100644
--- a/extensions/browser/api/declarative_net_request/indexed_rule.h
+++ b/extensions/browser/api/declarative_net_request/indexed_rule.h
@@ -13,6 +13,8 @@
 #include "components/url_pattern_index/flat/url_pattern_index_generated.h"
 #include "extensions/common/api/declarative_net_request.h"
 
+class GURL;
+
 namespace extensions {
 namespace declarative_net_request {
 
@@ -29,6 +31,7 @@
 
   static ParseResult CreateIndexedRule(
       extensions::api::declarative_net_request::Rule parsed_rule,
+      const GURL& base_url,
       IndexedRule* indexed_rule);
 
   api::declarative_net_request::RuleActionType action_type =
diff --git a/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc b/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
index cd9b9ab..e792e814 100644
--- a/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
+++ b/extensions/browser/api/declarative_net_request/indexed_rule_unittest.cc
@@ -15,7 +15,9 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/version_info/version_info.h"
 #include "extensions/browser/api/declarative_net_request/constants.h"
+#include "extensions/browser/api/declarative_net_request/test_utils.h"
 #include "extensions/common/api/declarative_net_request.h"
+#include "extensions/common/extension.h"
 #include "extensions/common/features/feature_channel.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -26,6 +28,12 @@
 namespace flat_rule = url_pattern_index::flat;
 namespace dnr_api = extensions::api::declarative_net_request;
 
+constexpr const char* kTestExtensionId = "extensionid";
+
+GURL GetBaseURL() {
+  return Extension::GetBaseURLFromExtensionId(kTestExtensionId);
+}
+
 dnr_api::Rule CreateGenericParsedRule() {
   dnr_api::Rule rule;
   rule.id = kMinValidID;
@@ -59,8 +67,8 @@
     rule.id = cases[i].id;
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
 
     EXPECT_EQ(cases[i].expected_result, result);
     if (result == ParseResult::SUCCESS)
@@ -94,8 +102,8 @@
         std::make_unique<std::string>("http://google.com");
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
 
     EXPECT_EQ(cases[i].expected_result, result);
     if (result == ParseResult::SUCCESS)
@@ -107,8 +115,8 @@
     dnr_api::Rule rule = CreateGenericParsedRule();
     rule.priority = std::make_unique<int>(5);
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
     EXPECT_EQ(ParseResult::SUCCESS, result);
     EXPECT_EQ(static_cast<uint32_t>(kDefaultPriority), indexed_rule.priority);
   }
@@ -144,8 +152,8 @@
         std::move(cases[i].is_url_filter_case_sensitive);
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
 
     EXPECT_EQ(ParseResult::SUCCESS, result);
     EXPECT_EQ(cases[i].expected_options, indexed_rule.options);
@@ -207,8 +215,8 @@
         std::move(cases[i].excluded_resource_types);
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
 
     EXPECT_EQ(cases[i].expected_result, result);
     if (result == ParseResult::SUCCESS)
@@ -279,8 +287,8 @@
     rule.condition.url_filter = std::move(cases[i].input_url_filter);
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
     if (result != ParseResult::SUCCESS)
       continue;
 
@@ -313,7 +321,8 @@
         std::move(test_case.is_url_filter_case_sensitive);
     IndexedRule indexed_rule;
     ASSERT_EQ(ParseResult::SUCCESS,
-              IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule));
+              IndexedRule::CreateIndexedRule(std::move(rule), GetBaseURL(),
+                                             &indexed_rule));
     EXPECT_EQ(test_case.expected_pattern, indexed_rule.url_pattern);
   }
 }
@@ -372,8 +381,8 @@
     rule.condition.excluded_domains = std::move(cases[i].excluded_domains);
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
 
     EXPECT_EQ(cases[i].expected_result, result);
     if (result == ParseResult::SUCCESS) {
@@ -390,13 +399,16 @@
     const ParseResult expected_result;
     // Only valid if |expected_result| is SUCCESS.
     const std::string expected_redirect_url;
-  } cases[] = {{std::make_unique<std::string>(""),
-                ParseResult::ERROR_EMPTY_REDIRECT_URL, ""},
-               {nullptr, ParseResult::ERROR_EMPTY_REDIRECT_URL, ""},
-               {std::make_unique<std::string>("http://google.com"),
-                ParseResult::SUCCESS, "http://google.com"},
-               {std::make_unique<std::string>("abc"),
-                ParseResult::ERROR_INVALID_REDIRECT_URL, ""}};
+  } cases[] = {
+      {std::make_unique<std::string>(""), ParseResult::ERROR_EMPTY_REDIRECT_URL,
+       ""},
+      {nullptr, ParseResult::ERROR_EMPTY_REDIRECT_URL, ""},
+      {std::make_unique<std::string>("http://google.com"), ParseResult::SUCCESS,
+       "http://google.com"},
+      {std::make_unique<std::string>("/relative/url"), ParseResult::SUCCESS,
+       "chrome-extension://" + std::string(kTestExtensionId) + "/relative/url"},
+      {std::make_unique<std::string>("abc"),
+       ParseResult::ERROR_INVALID_REDIRECT_URL, ""}};
 
   for (size_t i = 0; i < base::size(cases); ++i) {
     SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
@@ -406,8 +418,8 @@
     rule.priority = std::make_unique<int>(kMinValidPriority);
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
 
     EXPECT_EQ(cases[i].expected_result, result);
     if (result == ParseResult::SUCCESS)
@@ -448,8 +460,8 @@
     rule.action.remove_headers_list = std::move(cases[i].types);
 
     IndexedRule indexed_rule;
-    ParseResult result =
-        IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+    ParseResult result = IndexedRule::CreateIndexedRule(
+        std::move(rule), GetBaseURL(), &indexed_rule);
     EXPECT_EQ(cases[i].expected_result, result);
     if (result != ParseResult::SUCCESS)
       continue;
diff --git a/extensions/browser/api/declarative_net_request/ruleset_source.cc b/extensions/browser/api/declarative_net_request/ruleset_source.cc
index 53ec680..1cdc81c6 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_source.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_source.cc
@@ -38,6 +38,7 @@
 #include "services/data_decoder/public/cpp/safe_json_parser.h"
 #include "services/service_manager/public/cpp/identity.h"
 #include "tools/json_schema_compiler/util.h"
+#include "url/gurl.h"
 
 namespace extensions {
 namespace declarative_net_request {
@@ -241,7 +242,7 @@
   return RulesetSource(
       declarative_net_request::DNRManifestData::GetRulesetPath(extension),
       file_util::GetIndexedRulesetPath(extension.path()), kStaticRulesetID,
-      kStaticRulesetPriority, dnr_api::MAX_NUMBER_OF_RULES);
+      kStaticRulesetPriority, dnr_api::MAX_NUMBER_OF_RULES, extension.id());
 }
 
 // static
@@ -256,14 +257,15 @@
       dynamic_ruleset_directory.AppendASCII(kDynamicRulesJSONFilename),
       dynamic_ruleset_directory.AppendASCII(kDynamicIndexedRulesFilename),
       kDynamicRulesetID, kDynamicRulesetPriority,
-      dnr_api::MAX_NUMBER_OF_DYNAMIC_RULES);
+      dnr_api::MAX_NUMBER_OF_DYNAMIC_RULES, extension.id());
 }
 
 // static
 std::unique_ptr<RulesetSource> RulesetSource::CreateTemporarySource(
     size_t id,
     size_t priority,
-    size_t rule_count_limit) {
+    size_t rule_count_limit,
+    ExtensionId extension_id) {
   base::FilePath temporary_file_indexed;
   base::FilePath temporary_file_json;
   if (!base::CreateTemporaryFile(&temporary_file_indexed) ||
@@ -271,21 +273,23 @@
     return nullptr;
   }
 
-  return std::make_unique<RulesetSource>(std::move(temporary_file_json),
-                                         std::move(temporary_file_indexed), id,
-                                         priority, rule_count_limit);
+  return std::make_unique<RulesetSource>(
+      std::move(temporary_file_json), std::move(temporary_file_indexed), id,
+      priority, rule_count_limit, std::move(extension_id));
 }
 
 RulesetSource::RulesetSource(base::FilePath json_path,
                              base::FilePath indexed_path,
                              size_t id,
                              size_t priority,
-                             size_t rule_count_limit)
+                             size_t rule_count_limit,
+                             ExtensionId extension_id)
     : json_path_(std::move(json_path)),
       indexed_path_(std::move(indexed_path)),
       id_(id),
       priority_(priority),
-      rule_count_limit_(rule_count_limit) {}
+      rule_count_limit_(rule_count_limit),
+      extension_id_(std::move(extension_id)) {}
 
 RulesetSource::~RulesetSource() = default;
 RulesetSource::RulesetSource(RulesetSource&&) = default;
@@ -293,7 +297,7 @@
 
 RulesetSource RulesetSource::Clone() const {
   return RulesetSource(json_path_, indexed_path_, id_, priority_,
-                       rule_count_limit_);
+                       rule_count_limit_, extension_id_);
 }
 
 IndexAndPersistJSONRulesetResult
@@ -370,7 +374,7 @@
 
   {
     std::set<int> id_set;  // Ensure all ids are distinct.
-
+    const GURL base_url = Extension::GetBaseURLFromExtensionId(extension_id_);
     for (auto& rule : rules) {
       int rule_id = rule.id;
       bool inserted = id_set.insert(rule_id).second;
@@ -378,8 +382,8 @@
         return ParseInfo(ParseResult::ERROR_DUPLICATE_IDS, rule_id);
 
       IndexedRule indexed_rule;
-      ParseResult parse_result =
-          IndexedRule::CreateIndexedRule(std::move(rule), &indexed_rule);
+      ParseResult parse_result = IndexedRule::CreateIndexedRule(
+          std::move(rule), base_url, &indexed_rule);
       if (parse_result != ParseResult::SUCCESS)
         return ParseInfo(parse_result, rule_id);
 
diff --git a/extensions/browser/api/declarative_net_request/ruleset_source.h b/extensions/browser/api/declarative_net_request/ruleset_source.h
index 8781ae8f..72eb583 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_source.h
+++ b/extensions/browser/api/declarative_net_request/ruleset_source.h
@@ -12,6 +12,7 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/time/time.h"
+#include "extensions/common/extension_id.h"
 
 namespace base {
 class Token;
@@ -133,14 +134,18 @@
 
   // Creates a temporary source i.e. a source corresponding to temporary files.
   // Returns null on failure.
-  static std::unique_ptr<RulesetSource>
-  CreateTemporarySource(size_t id, size_t priority, size_t rule_count_limit);
+  static std::unique_ptr<RulesetSource> CreateTemporarySource(
+      size_t id,
+      size_t priority,
+      size_t rule_count_limit,
+      ExtensionId extension_id);
 
   RulesetSource(base::FilePath json_path,
                 base::FilePath indexed_path,
                 size_t id,
                 size_t priority,
-                size_t rule_count_limit);
+                size_t rule_count_limit,
+                ExtensionId extension_id);
   ~RulesetSource();
   RulesetSource(RulesetSource&&);
   RulesetSource& operator=(RulesetSource&&);
@@ -160,6 +165,9 @@
   // The maximum number of rules that will be indexed from this source.
   size_t rule_count_limit() const { return rule_count_limit_; }
 
+  // The ID of the extension from which the ruleset originates from.
+  const ExtensionId& extension_id() const { return extension_id_; }
+
   // Indexes and persists the JSON ruleset. This is potentially unsafe since the
   // JSON rules file is parsed in-process. Note: This must be called on a
   // sequence where file IO is allowed.
@@ -200,6 +208,7 @@
   size_t id_;
   size_t priority_;
   size_t rule_count_limit_;
+  ExtensionId extension_id_;
 
   DISALLOW_COPY_AND_ASSIGN(RulesetSource);
 };
diff --git a/extensions/browser/api/declarative_net_request/test_utils.cc b/extensions/browser/api/declarative_net_request/test_utils.cc
index 859dc3f3..84e800c6 100644
--- a/extensions/browser/api/declarative_net_request/test_utils.cc
+++ b/extensions/browser/api/declarative_net_request/test_utils.cc
@@ -65,9 +65,10 @@
 
 RulesetSource CreateTemporarySource(size_t id,
                                     size_t priority,
-                                    size_t rule_count_limit) {
-  std::unique_ptr<RulesetSource> source =
-      RulesetSource::CreateTemporarySource(id, priority, rule_count_limit);
+                                    size_t rule_count_limit,
+                                    ExtensionId extension_id) {
+  std::unique_ptr<RulesetSource> source = RulesetSource::CreateTemporarySource(
+      id, priority, rule_count_limit, std::move(extension_id));
   CHECK(source);
   return source->Clone();
 }
diff --git a/extensions/browser/api/declarative_net_request/test_utils.h b/extensions/browser/api/declarative_net_request/test_utils.h
index d98f7a6..4657207e 100644
--- a/extensions/browser/api/declarative_net_request/test_utils.h
+++ b/extensions/browser/api/declarative_net_request/test_utils.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <vector>
 
+#include "extensions/common/extension_id.h"
+
 namespace content {
 class BrowserContext;
 }  // namespace content
@@ -17,6 +19,7 @@
 class Extension;
 
 namespace declarative_net_request {
+
 class RulesetSource;
 class RulesetMatcher;
 struct TestRule;
@@ -42,7 +45,8 @@
 // Helper to return a RulesetSource bound to temporary files.
 RulesetSource CreateTemporarySource(size_t id = 1,
                                     size_t priority = 1,
-                                    size_t rule_count_limit = 100);
+                                    size_t rule_count_limit = 100,
+                                    ExtensionId extension_id = "extensionid");
 
 }  // namespace declarative_net_request
 }  // namespace extensions
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index b8c2091..6f43548 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -149,4 +149,9 @@
     const base::Callback<void(const std::string&)>& error_callback) {}
 #endif
 
+AutomationInternalApiDelegate*
+ExtensionsAPIClient::GetAutomationInternalApiDelegate() {
+  return nullptr;
+}
+
 }  // namespace extensions
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index a818412a..c88cd401 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -35,6 +35,7 @@
 
 namespace extensions {
 
+class AutomationInternalApiDelegate;
 class AppViewGuestDelegate;
 class ContentRulesRegistry;
 class DevicePermissionsPrompt;
@@ -184,6 +185,8 @@
       const base::Callback<void(const std::string&)>& error_callback);
 #endif
 
+  virtual AutomationInternalApiDelegate* GetAutomationInternalApiDelegate();
+
   // NOTE: If this interface gains too many methods (perhaps more than 20) it
   // should be split into one interface per API.
 };
diff --git a/extensions/browser/api/web_request/web_request_api_helpers.cc b/extensions/browser/api/web_request/web_request_api_helpers.cc
index 9cb01a071..6a9a984 100644
--- a/extensions/browser/api/web_request/web_request_api_helpers.cc
+++ b/extensions/browser/api/web_request/web_request_api_helpers.cc
@@ -96,6 +96,10 @@
       "Extensions.WebRequest.SpecialRequestHeadersChanged", type);
 }
 
+bool IsStringLowerCaseASCII(const std::string& s) {
+  return std::none_of(s.begin(), s.end(), base::IsAsciiUpper<char>);
+}
+
 }  // namespace
 
 IgnoredAction::IgnoredAction(extensions::ExtensionId extension_id,
@@ -724,12 +728,11 @@
           delta.modified_request_headers);
       while (modification.GetNext() && !extension_conflicts) {
         // This modification sets |key| to |value|.
-        const std::string& key = modification.name();
+        const std::string key = base::ToLowerASCII(modification.name());
         const std::string& value = modification.value();
 
         // We must not modify anything that has been deleted before.
-        if (removed_headers->find(key) != removed_headers->end() &&
-            !extension_conflicts) {
+        if (base::ContainsKey(*removed_headers, key)) {
           extension_conflicts = true;
           break;
         }
@@ -748,12 +751,12 @@
 
         // We must not modify anything that has been set to a *different*
         // value before.
-        if (set_headers->find(key) != set_headers->end() &&
-            !extension_conflicts) {
+        if (base::ContainsKey(*set_headers, key)) {
           std::string current_value;
           if (!request_headers->GetHeader(key, &current_value) ||
               current_value != value) {
             extension_conflicts = true;
+            break;
           }
         }
       }
@@ -762,11 +765,11 @@
     // Check whether any deletion affects a request header that has been
     // modified before.
     {
-      for (auto key = delta.deleted_request_headers.begin();
-           key != delta.deleted_request_headers.end() && !extension_conflicts;
-           ++key) {
-        if (set_headers->find(*key) != set_headers->end())
+      for (const std::string& key : delta.deleted_request_headers) {
+        if (base::ContainsKey(*set_headers, base::ToLowerASCII(key))) {
           extension_conflicts = true;
+          break;
+        }
       }
     }
 
@@ -779,14 +782,14 @@
         net::HttpRequestHeaders::Iterator modification(
             delta.modified_request_headers);
         while (modification.GetNext())
-          set_headers->insert(modification.name());
+          set_headers->insert(base::ToLowerASCII(modification.name()));
       }
 
       // Perform all deletions and record which keys were deleted.
       {
         for (const auto& header : delta.deleted_request_headers) {
           request_headers->RemoveHeader(header);
-          removed_headers->insert(header);
+          removed_headers->insert(base::ToLowerASCII(header));
         }
       }
       request.logger->LogEvent(
@@ -802,6 +805,11 @@
     }
   }
 
+  DCHECK(std::all_of(removed_headers->begin(), removed_headers->end(),
+                     IsStringLowerCaseASCII));
+  DCHECK(std::all_of(set_headers->begin(), set_headers->end(),
+                     IsStringLowerCaseASCII));
+
   // TODO(https://crbug.com/827582): Remove once data is gathered.
   static const std::map<std::string, WebRequestSpecialRequestHeaderModification>
       kHeaderMap{
@@ -816,7 +824,7 @@
       };
   int special_headers_removed = 0;
   for (const auto& header : *removed_headers) {
-    auto it = kHeaderMap.find(base::ToLowerASCII(header));
+    auto it = kHeaderMap.find(header);
     if (it != kHeaderMap.end()) {
       special_headers_removed++;
       RecordSpecialRequestHeadersRemoved(it->second);
@@ -832,7 +840,7 @@
 
   int special_headers_changed = 0;
   for (const auto& header : *set_headers) {
-    auto it = kHeaderMap.find(base::ToLowerASCII(header));
+    auto it = kHeaderMap.find(header);
     if (it != kHeaderMap.end()) {
       special_headers_changed++;
       RecordSpecialRequestHeadersChanged(it->second);
diff --git a/extensions/common/api/PRESUBMIT.py b/extensions/common/api/PRESUBMIT.py
index e4fba25..97f4cd4 100644
--- a/extensions/common/api/PRESUBMIT.py
+++ b/extensions/common/api/PRESUBMIT.py
@@ -26,6 +26,7 @@
       'closure_compiler', 'externs')
 
   api_pairs = {
+    join(api_root, 'automation.idl'): join(externs_root, 'automation.js'),
     join(api_root, 'bluetooth.idl'): join(externs_root, 'bluetooth.js'),
     join(api_root, 'metrics_private.json'):
         join(externs_root, 'metrics_private.js'),
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 232b732a..e5baed9 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -77,6 +77,15 @@
     "dependencies": ["permission:audio"],
     "contexts": ["blessed_extension"]
   },
+  "automationInternal": {
+    "internal": true,
+    "dependencies": ["manifest:automation"],
+    "contexts": ["blessed_extension"]
+  },
+  "automation": {
+    "dependencies": ["manifest:automation"],
+    "contexts": ["blessed_extension"]
+  },
   "bluetooth": [{
     "dependencies": ["manifest:bluetooth"],
     "contexts": ["blessed_extension"]
diff --git a/chrome/common/extensions/api/automation.idl b/extensions/common/api/automation.idl
similarity index 100%
rename from chrome/common/extensions/api/automation.idl
rename to extensions/common/api/automation.idl
diff --git a/chrome/common/extensions/api/automation_internal.idl b/extensions/common/api/automation_internal.idl
similarity index 100%
rename from chrome/common/extensions/api/automation_internal.idl
rename to extensions/common/api/automation_internal.idl
diff --git a/extensions/common/api/declarative_net_request.idl b/extensions/common/api/declarative_net_request.idl
index 2c39f46..04e68d0 100644
--- a/extensions/common/api/declarative_net_request.idl
+++ b/extensions/common/api/declarative_net_request.idl
@@ -46,8 +46,8 @@
     block,
     // Redirect the network request.
     redirect,
-    // Allow the network request. The request won't be blocked even if there
-    // is a blocking rule which matches it.
+    // Allow the network request. The request won't be blocked or redirected
+    // even if there is a block or redirect rule which matches it.
     allow,
     // Remove request/response headers from the network request.
     removeHeaders
@@ -125,7 +125,9 @@
     // The type of action to perform.
     RuleActionType type;
 
-    // The redirect url. Only valid if RuleActionType is "redirect".
+    // The redirect url. Only valid if RuleActionType is "redirect". Can be
+    // specified as an absolute url or a relative url (starting with '/'), which
+    // is relative to the extension which specified the rule.
     DOMString? redirectUrl;
 
     // The headers to remove from the request. Only valid if RuleActionType is
@@ -154,34 +156,11 @@
 
   interface Functions {
 
-    // Adds <code>rules</code> to the current set of dynamic rules for the
-    // extension. These rules are persisted across browser sessions.
-    // Note: <a href="#property-MAX_NUMBER_OF_DYNAMIC_RULES">
-    // MAX_NUMBER_OF_DYNAMIC_RULES</a> is the maximum number of dynamic rules an
-    // extension can add.
-    // |rules|: The rules to add.
-    // |callback|: Called once the given <code>rules</code> are added. In case
-    // of an error, $(ref:runtime.lastError) will be set to denote the error
-    // message and no rules will be added. This can happen for multiple reasons,
-    // such as invalid rule format, duplicate rule ID, rule count limit
-    // exceeded, internal errors, and others.
-    static void addDynamicRules(Rule[] rules, optional EmptyCallback callback);
-
-    // Removes rules corresponding to <code>rule_ids</code> from the current set
-    // of dynamic rules for the extension. Any <code>rule_ids</code> not already
-    // present are ignored. Note that static rules specified as part of the
-    // extension package can not be removed using this function.
-    // |rule_ids|: The IDs of dynamic rules to remove.
-    // |callback|: Called once the rules are removed. In case of an error,
-    // $(ref:runtime.lastError) will be set to denote the error message and no
-    // rules will be removed. This may happen due to internal errors.
-    static void removeDynamicRules(long[] rule_ids,
-        optional EmptyCallback callback);
-
-    // Returns the current set of dynamic rules for the extension.
-    // |callback|: Called with the set of dynamic rules. An error might be
-    // raised in case of transient internal errors.
-    static void getDynamicRules(GetRulesCallback callback);
+    // TODO(crbug.com/930961): Enable documentation for these functions once
+    // they are implemented.
+    [nodoc] static void addDynamicRules(Rule[] rules, optional EmptyCallback callback);
+    [nodoc] static void removeDynamicRules(long[] rule_ids, optional EmptyCallback callback);
+    [nodoc] static void getDynamicRules(GetRulesCallback callback);
 
     // Adds <code>page_patterns</code> to the set of allowed pages. Requests
     // from these pages are not intercepted by the extension. These are
@@ -194,11 +173,11 @@
     // <a href="/extensions/match_patterns">match patterns</a> which are to be
     // allowed.
     // |callback|: Called after the <code>page_patterns</code> have been added.
-    // $(ref:runtime.lastError) will be set in case of an error, for example if
+    // chrome.runtime.lastError will be set in case of an error, for example if
     // an invalid page pattern is specified or the extension exceeded the
     // maximum page patterns limit.
-    static void addAllowedPages(DOMString[] page_patterns,
-        optional EmptyCallback callback);
+
+    static void addAllowedPages(DOMString[] page_patterns, optional EmptyCallback callback);
 
     // Removes <code>page_patterns</code> from the set of allowed pages.
     // Note: Removing page patterns is atomic. In case of an error, no page
@@ -207,9 +186,8 @@
     // <a href="/extensions/match_patterns">match patterns</a> which are to be
     // removed.
     // |callback|: Called after the <code>page_patterns</code> have been
-    // removed. $(ref:runtime.lastError) will be set in case of an error.
-    static void removeAllowedPages(DOMString[] page_patterns,
-        optional EmptyCallback callback);
+    // removed. chrome.runtime.lastError will be set in case of an error.
+    static void removeAllowedPages(DOMString[] page_patterns, optional EmptyCallback callback);
 
     // Returns the current set of allowed pages.
     // |callback|: Called with the set of currently allowed pages.
diff --git a/extensions/common/api/schema.gni b/extensions/common/api/schema.gni
index 084f7be2..7473c42 100644
--- a/extensions/common/api/schema.gni
+++ b/extensions/common/api/schema.gni
@@ -9,6 +9,8 @@
   "app_view_guest_internal.json",
   "app_window.idl",
   "audio.idl",
+  "automation.idl",
+  "automation_internal.idl",
   "bluetooth.idl",
   "bluetooth_low_energy.idl",
   "bluetooth_private.idl",
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h
index 85e3f4a..1d9e87e 100644
--- a/fuchsia/engine/browser/frame_impl.h
+++ b/fuchsia/engine/browser/frame_impl.h
@@ -22,6 +22,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "fuchsia/engine/browser/discarding_event_filter.h"
 #include "fuchsia/engine/on_load_script_injector.mojom.h"
+#include "fuchsia/engine/web_engine_export.h"
 #include "ui/aura/window_tree_host.h"
 #include "ui/wm/core/focus_controller.h"
 #include "url/gurl.h"
@@ -183,7 +184,8 @@
 // Computes the observable differences between |old_entry| and |new_entry|.
 // Returns true if they are different, |false| if their observable fields are
 // identical.
-bool DiffNavigationEntries(const fuchsia::web::NavigationState& old_entry,
-                           const fuchsia::web::NavigationState& new_entry,
-                           fuchsia::web::NavigationState* difference);
+WEB_ENGINE_EXPORT bool DiffNavigationEntries(
+    const fuchsia::web::NavigationState& old_entry,
+    const fuchsia::web::NavigationState& new_entry,
+    fuchsia::web::NavigationState* difference);
 #endif  // FUCHSIA_ENGINE_BROWSER_FRAME_IMPL_H_
diff --git a/google_apis/google_api_keys.cc b/google_apis/google_api_keys.cc
index 6d187b5..347358a 100644
--- a/google_apis/google_api_keys.cc
+++ b/google_apis/google_api_keys.cc
@@ -82,6 +82,10 @@
 #define GOOGLE_API_KEY_REMOTING_FTL DUMMY_API_TOKEN
 #endif
 
+#if !defined(GOOGLE_API_KEY_REMOTING_FTL_MOBILE)
+#define GOOGLE_API_KEY_REMOTING_FTL_MOBILE DUMMY_API_TOKEN
+#endif
+
 // These are used as shortcuts for developers and users providing
 // OAuth credentials via preprocessor defines or environment
 // variables.  If set, they will be used to replace any of the client
@@ -125,6 +129,11 @@
         STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING_FTL), nullptr,
         std::string(), environment.get(), command_line);
 
+    api_key_remoting_ftl_mobile_ = CalculateKeyValue(
+        GOOGLE_API_KEY_REMOTING_FTL_MOBILE,
+        STRINGIZE_NO_EXPANSION(GOOGLE_API_KEY_REMOTING_FTL_MOBILE), nullptr,
+        std::string(), environment.get(), command_line);
+
     metrics_key_ = CalculateKeyValue(
         GOOGLE_METRICS_SIGNING_KEY,
         STRINGIZE_NO_EXPANSION(GOOGLE_METRICS_SIGNING_KEY), nullptr,
@@ -194,6 +203,9 @@
 #endif
   std::string api_key_non_stable() const { return api_key_non_stable_; }
   std::string api_key_remoting_ftl() const { return api_key_remoting_ftl_; }
+  std::string api_key_remoting_ftl_mobile() const {
+    return api_key_remoting_ftl_mobile_;
+  }
 
   std::string metrics_key() const { return metrics_key_; }
 
@@ -292,6 +304,7 @@
   std::string api_key_;
   std::string api_key_non_stable_;
   std::string api_key_remoting_ftl_;
+  std::string api_key_remoting_ftl_mobile_;
   std::string metrics_key_;
   std::string client_ids_[CLIENT_NUM_ITEMS];
   std::string client_secrets_[CLIENT_NUM_ITEMS];
@@ -316,6 +329,10 @@
   return g_api_key_cache.Get().api_key_remoting_ftl();
 }
 
+std::string GetRemotingFtlMobileAPIKey() {
+  return g_api_key_cache.Get().api_key_remoting_ftl_mobile();
+}
+
 #if defined(OS_IOS)
 void SetAPIKey(const std::string& api_key) {
   g_api_key_cache.Get().set_api_key(api_key);
diff --git a/google_apis/google_api_keys.h b/google_apis/google_api_keys.h
index 01fc4e10..46d4b75 100644
--- a/google_apis/google_api_keys.h
+++ b/google_apis/google_api_keys.h
@@ -76,6 +76,7 @@
 // Retrieves the Chrome Remote Desktop FTL API key to be used during the
 // signaling process.
 std::string GetRemotingFtlAPIKey();
+std::string GetRemotingFtlMobileAPIKey();
 
 #if defined(OS_IOS)
 // Sets the API key. This should be called as early as possible before this
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 255f6eb5..b4869ed 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -301,12 +301,8 @@
       'GL_TRANSFORM_FEEDBACK_ACTIVE',
       'GL_TRANSFORM_FEEDBACK_BUFFER_BINDING',
       'GL_TRANSFORM_FEEDBACK_PAUSED',
-      'GL_TRANSFORM_FEEDBACK_BUFFER_SIZE',
-      'GL_TRANSFORM_FEEDBACK_BUFFER_START',
       'GL_UNIFORM_BUFFER_BINDING',
       'GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT',
-      'GL_UNIFORM_BUFFER_SIZE',
-      'GL_UNIFORM_BUFFER_START',
       'GL_UNPACK_IMAGE_HEIGHT',
       'GL_UNPACK_ROW_LENGTH',
       'GL_UNPACK_SKIP_IMAGES',
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index 4d57dcee..14070d3e 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -7046,14 +7046,9 @@
       {GL_TRANSFORM_FEEDBACK_BUFFER_BINDING,
        "GL_TRANSFORM_FEEDBACK_BUFFER_BINDING"},
       {GL_TRANSFORM_FEEDBACK_PAUSED, "GL_TRANSFORM_FEEDBACK_PAUSED"},
-      {GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE"},
-      {GL_TRANSFORM_FEEDBACK_BUFFER_START,
-       "GL_TRANSFORM_FEEDBACK_BUFFER_START"},
       {GL_UNIFORM_BUFFER_BINDING, "GL_UNIFORM_BUFFER_BINDING"},
       {GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
        "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT"},
-      {GL_UNIFORM_BUFFER_SIZE, "GL_UNIFORM_BUFFER_SIZE"},
-      {GL_UNIFORM_BUFFER_START, "GL_UNIFORM_BUFFER_START"},
       {GL_UNPACK_IMAGE_HEIGHT, "GL_UNPACK_IMAGE_HEIGHT"},
       {GL_UNPACK_ROW_LENGTH, "GL_UNPACK_ROW_LENGTH"},
       {GL_UNPACK_SKIP_IMAGES, "GL_UNPACK_SKIP_IMAGES"},
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 1b0ea92..430ac569 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -430,12 +430,8 @@
     GL_TRANSFORM_FEEDBACK_ACTIVE,
     GL_TRANSFORM_FEEDBACK_BUFFER_BINDING,
     GL_TRANSFORM_FEEDBACK_PAUSED,
-    GL_TRANSFORM_FEEDBACK_BUFFER_SIZE,
-    GL_TRANSFORM_FEEDBACK_BUFFER_START,
     GL_UNIFORM_BUFFER_BINDING,
     GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
-    GL_UNIFORM_BUFFER_SIZE,
-    GL_UNIFORM_BUFFER_START,
     GL_UNPACK_IMAGE_HEIGHT,
     GL_UNPACK_ROW_LENGTH,
     GL_UNPACK_SKIP_IMAGES,
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
index d5b6a11..1d3f1a7 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer.cc
@@ -373,7 +373,6 @@
 
   void EndAccess(bool readonly) {
     CheckContext();
-    DCHECK_EQ(RepresentationAccessMode::kWrite, mode_);
 
     // Insert a gl fence to signal the write completion.
     base::ScopedFD sync_fd = CreateEglFenceAndExportFd();
diff --git a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
index 0dfa416a..cbffb4f 100644
--- a/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
+++ b/gpu/command_buffer/service/shared_image_backing_factory_ahardwarebuffer_unittest.cc
@@ -319,11 +319,17 @@
   EXPECT_EQ(0u, begin_semaphores.size());
   EXPECT_EQ(0u, end_semaphores.size());
 
-  EXPECT_FALSE(skia_representation->BeginWriteAccess(
-      0, SkSurfaceProps(0, kUnknown_SkPixelGeometry), &begin_semaphores,
-      &end_semaphores));
-  EXPECT_EQ(0u, begin_semaphores.size());
-  EXPECT_EQ(0u, end_semaphores.size());
+  auto skia_representation2 = shared_image_representation_factory_->ProduceSkia(
+      gl_legacy_shared_image.mailbox(), context_state_.get());
+  std::vector<GrBackendSemaphore> begin_semaphores2;
+  std::vector<GrBackendSemaphore> end_semaphores2;
+
+  EXPECT_FALSE(skia_representation2->BeginWriteAccess(
+      0, SkSurfaceProps(0, kUnknown_SkPixelGeometry), &begin_semaphores2,
+      &end_semaphores2));
+  EXPECT_EQ(0u, begin_semaphores2.size());
+  EXPECT_EQ(0u, end_semaphores2.size());
+  skia_representation2.reset();
 
   skia_representation->EndWriteAccess(std::move(surface));
   skia_representation.reset();
@@ -362,40 +368,6 @@
   skia_representation.reset();
 }
 
-// Test to check that we cannot begin reading twice on the same representation
-TEST_F(SharedImageBackingFactoryAHBTest,
-       CannotReadMultipleTimesOnSameRepresentation) {
-  if (!base::AndroidHardwareBufferCompat::IsSupportAvailable())
-    return;
-
-  GlLegacySharedImage gl_legacy_shared_image{
-      backing_factory_.get(),     true /* is_thread_safe */,
-      &mailbox_manager_,          &shared_image_manager_,
-      memory_type_tracker_.get(), shared_image_representation_factory_.get()};
-
-  auto skia_representation = shared_image_representation_factory_->ProduceSkia(
-      gl_legacy_shared_image.mailbox(), context_state_.get());
-  {
-    std::vector<GrBackendSemaphore> begin_semaphores;
-    std::vector<GrBackendSemaphore> end_semaphores;
-    EXPECT_TRUE(skia_representation->BeginReadAccess(&begin_semaphores,
-                                                     &end_semaphores));
-    EXPECT_EQ(0u, begin_semaphores.size());
-    EXPECT_EQ(0u, end_semaphores.size());
-  }
-  {
-    std::vector<GrBackendSemaphore> begin_semaphores;
-    std::vector<GrBackendSemaphore> end_semaphores;
-    EXPECT_FALSE(skia_representation->BeginReadAccess(&begin_semaphores,
-                                                      &end_semaphores));
-    EXPECT_EQ(0u, begin_semaphores.size());
-    EXPECT_EQ(0u, end_semaphores.size());
-  }
-
-  skia_representation->EndReadAccess();
-  skia_representation.reset();
-}
-
 // Test to check that a context cannot write while another context is reading
 TEST_F(SharedImageBackingFactoryAHBTest, CannotWriteWhileReading) {
   if (!base::AndroidHardwareBufferCompat::IsSupportAvailable())
@@ -416,11 +388,17 @@
   EXPECT_EQ(0u, begin_semaphores.size());
   EXPECT_EQ(0u, end_semaphores.size());
 
-  EXPECT_FALSE(skia_representation->BeginWriteAccess(
-      0, SkSurfaceProps(0, kUnknown_SkPixelGeometry), &begin_semaphores,
-      &end_semaphores));
-  EXPECT_EQ(0u, begin_semaphores.size());
-  EXPECT_EQ(0u, end_semaphores.size());
+  auto skia_representation2 = shared_image_representation_factory_->ProduceSkia(
+      gl_legacy_shared_image.mailbox(), context_state_.get());
+
+  std::vector<GrBackendSemaphore> begin_semaphores2;
+  std::vector<GrBackendSemaphore> end_semaphores2;
+  EXPECT_FALSE(skia_representation2->BeginWriteAccess(
+      0, SkSurfaceProps(0, kUnknown_SkPixelGeometry), &begin_semaphores2,
+      &end_semaphores2));
+  EXPECT_EQ(0u, begin_semaphores2.size());
+  EXPECT_EQ(0u, end_semaphores2.size());
+  skia_representation2.reset();
 
   skia_representation->EndReadAccess();
   skia_representation.reset();
@@ -446,10 +424,16 @@
   EXPECT_EQ(0u, begin_semaphores.size());
   EXPECT_EQ(0u, end_semaphores.size());
 
-  EXPECT_FALSE(
-      skia_representation->BeginReadAccess(&begin_semaphores, &end_semaphores));
-  EXPECT_EQ(0u, begin_semaphores.size());
-  EXPECT_EQ(0u, end_semaphores.size());
+  auto skia_representation2 = shared_image_representation_factory_->ProduceSkia(
+      gl_legacy_shared_image.mailbox(), context_state_.get());
+  std::vector<GrBackendSemaphore> begin_semaphores2;
+  std::vector<GrBackendSemaphore> end_semaphores2;
+
+  EXPECT_FALSE(skia_representation2->BeginReadAccess(&begin_semaphores2,
+                                                     &end_semaphores2));
+  EXPECT_EQ(0u, begin_semaphores2.size());
+  EXPECT_EQ(0u, end_semaphores2.size());
+  skia_representation2.reset();
 
   skia_representation->EndWriteAccess(std::move(surface));
   skia_representation.reset();
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index 5c4466b..e53cf04 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -21,7 +21,8 @@
                          GLuint service_id,
                          viz::ResourceFormat resource_format,
                          GrBackendTexture* gr_texture) {
-  if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB) {
+  if (target != GL_TEXTURE_2D && target != GL_TEXTURE_RECTANGLE_ARB &&
+      target != GL_TEXTURE_EXTERNAL_OES) {
     LOG(ERROR) << "GetGrBackendTexture: invalid texture target.";
     return false;
   }
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap_unittest.cc b/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap_unittest.cc
index bf77a6d..e2070dc 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap_unittest.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap_unittest.cc
@@ -3,12 +3,22 @@
 // found in the LICENSE file.
 
 #include "gpu/ipc/common/gpu_memory_buffer_impl_native_pixmap.h"
+
+#include "build/build_config.h"
 #include "gpu/ipc/common/gpu_memory_buffer_impl_test_template.h"
 
 namespace gpu {
 namespace {
 
-INSTANTIATE_TYPED_TEST_SUITE_P(GpuMemoryBufferImplNativePixmap,
+// On Fuchsia NativePixmap depends on Vulkan, which is not initialized in tests.
+// See crbug.com/957700
+#if defined(OS_FUCHSIA)
+#define MAYBE_GpuMemoryBufferImplNativePixmap \
+  DISABLED_GpuMemoryBufferImplNativePixmap
+#else
+#define MAYBE_GpuMemoryBufferImplNativePixmap GpuMemoryBufferImplNativePixmap
+#endif
+INSTANTIATE_TYPED_TEST_SUITE_P(MAYBE_GpuMemoryBufferImplNativePixmap,
                                GpuMemoryBufferImplTest,
                                GpuMemoryBufferImplNativePixmap);
 
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc
index b1d1102..84f1792f 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap_unittest.cc
@@ -3,12 +3,23 @@
 // found in the LICENSE file.
 
 #include "gpu/ipc/service/gpu_memory_buffer_factory_native_pixmap.h"
+
+#include "build/build_config.h"
 #include "gpu/ipc/service/gpu_memory_buffer_factory_test_template.h"
 
 namespace gpu {
 namespace {
 
-INSTANTIATE_TYPED_TEST_SUITE_P(GpuMemoryBufferFactoryNativePixmap,
+// On Fuchsia NativePixmap depends on Vulkan, which is not initialized in tests.
+// See crbug.com/957700
+#if defined(OS_FUCHSIA)
+#define MAYBE_GpuMemoryBufferFactoryNativePixmap \
+  DISABLED_GpuMemoryBufferFactoryNativePixmap
+#else
+#define MAYBE_GpuMemoryBufferFactoryNativePixmap \
+  GpuMemoryBufferFactoryNativePixmap
+#endif
+INSTANTIATE_TYPED_TEST_SUITE_P(MAYBE_GpuMemoryBufferFactoryNativePixmap,
                                GpuMemoryBufferFactoryTest,
                                GpuMemoryBufferFactoryNativePixmap);
 
diff --git a/gpu/ipc/service/swap_chain_presenter.cc b/gpu/ipc/service/swap_chain_presenter.cc
index 148feeea..277c3f7 100644
--- a/gpu/ipc/service/swap_chain_presenter.cc
+++ b/gpu/ipc/service/swap_chain_presenter.cc
@@ -164,7 +164,12 @@
   }
 }
 
-bool SwapChainPresenter::PresentationHistory::valid() const {
+void SwapChainPresenter::PresentationHistory::Clear() {
+  presents_.clear();
+  composed_count_ = 0;
+}
+
+bool SwapChainPresenter::PresentationHistory::Valid() const {
   return presents_.size() >= kPresentsToStore;
 }
 
@@ -203,8 +208,9 @@
     return false;
 
   // Start out as YUV.
-  if (!presentation_history_.valid())
+  if (!presentation_history_.Valid())
     return true;
+
   int composition_count = presentation_history_.composed_count();
 
   // It's more efficient to use a BGRA backbuffer instead of YUV if overlays
@@ -724,6 +730,10 @@
   }
 
   bool swap_chain_resized = swap_chain_size_ != swap_chain_size;
+  // Give it another chance to try YUV again when the size changes.
+  if (swap_chain_resized) {
+    presentation_history_.Clear();
+  }
   bool use_yuv_swap_chain = ShouldUseYUVSwapChain(params.protected_video_type);
   bool toggle_yuv_swapchain = use_yuv_swap_chain != is_yuv_swapchain_;
   bool toggle_protected_video =
diff --git a/gpu/ipc/service/swap_chain_presenter.h b/gpu/ipc/service/swap_chain_presenter.h
index ddfa705..99ca2a0 100644
--- a/gpu/ipc/service/swap_chain_presenter.h
+++ b/gpu/ipc/service/swap_chain_presenter.h
@@ -78,7 +78,8 @@
 
     void AddSample(DXGI_FRAME_PRESENTATION_MODE mode);
 
-    bool valid() const;
+    void Clear();
+    bool Valid() const;
     int composed_count() const;
 
    private:
diff --git a/infra/config/commit-queue.cfg b/infra/config/commit-queue.cfg
index c49fe4413..f9dd4b1f 100644
--- a/infra/config/commit-queue.cfg
+++ b/infra/config/commit-queue.cfg
@@ -140,9 +140,7 @@
       builders {
         name: "chromium/try/win10_chromium_x64_rel_ng"
       }
-      builders {
-        name: "chromium/try/win7-rel"
-      }
+      # TODO(crbug.com/948145): Re-add win7-rel once the bot has recovered.
       builders {
         name: "chromium/try/win_chromium_compile_dbg_ng"
       }
@@ -203,6 +201,7 @@
       }
       builders {
         name: "chromium/try/dawn-mac-x64-deps-rel"
+        location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
         location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
         location_regexp: ".+/[+]/third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu"
@@ -211,6 +210,7 @@
       }
       builders {
         name: "chromium/try/dawn-win10-x64-deps-rel"
+        location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
         location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
         location_regexp: ".+/[+]/third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu"
@@ -219,6 +219,7 @@
       }
       builders {
         name: "chromium/try/dawn-win10-x86-deps-rel"
+        location_regexp: ".+/[+]/gpu/.+"
         location_regexp: ".+/[+]/testing/buildbot/chromium.dawn.json"
         location_regexp: ".+/[+]/third_party/blink/renderer/modules/webgpu/.+"
         location_regexp: ".+/[+]/third_party/blink/web_tests/FlagExpectations/enable-unsafe-webgpu"
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index 18f1600..ffda190 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -59,11 +59,13 @@
     "//components/autofill/ios/form_util",
     "//components/keyed_service/core",
     "//components/keyed_service/ios",
+    "//components/leveldb_proto",
     "//components/prefs",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/history",
+    "//ios/chrome/browser/leveldb_proto:factory",
     "//ios/chrome/browser/passwords:passwords_generation_utils",
     "//ios/chrome/browser/signin",
     "//ios/chrome/browser/ui/autofill/manual_fill:manual_fill_ui",
diff --git a/ios/chrome/browser/autofill/legacy_strike_database_factory.cc b/ios/chrome/browser/autofill/legacy_strike_database_factory.cc
index e6fea6e..d2fe4b6 100644
--- a/ios/chrome/browser/autofill/legacy_strike_database_factory.cc
+++ b/ios/chrome/browser/autofill/legacy_strike_database_factory.cc
@@ -11,6 +11,7 @@
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/leveldb_proto/proto_database_provider_factory.h"
 
 namespace autofill {
 
@@ -30,7 +31,9 @@
 LegacyStrikeDatabaseFactory::LegacyStrikeDatabaseFactory()
     : BrowserStateKeyedServiceFactory(
           "AutofillLegacyStrikeDatabase",
-          BrowserStateDependencyManager::GetInstance()) {}
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
+}
 
 LegacyStrikeDatabaseFactory::~LegacyStrikeDatabaseFactory() {}
 
@@ -39,9 +42,13 @@
     web::BrowserState* context) const {
   ios::ChromeBrowserState* chrome_browser_state =
       ios::ChromeBrowserState::FromBrowserState(context);
+
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::ProtoDatabaseProviderFactory::GetInstance()
+          ->GetForBrowserState(chrome_browser_state);
+
   return std::make_unique<autofill::LegacyStrikeDatabase>(
-      chrome_browser_state->GetStatePath().Append(
-          FILE_PATH_LITERAL("AutofillStrikeDatabase")));
+      db_provider, chrome_browser_state->GetStatePath());
 }
 
 }  // namespace autofill
diff --git a/ios/chrome/browser/autofill/strike_database_factory.cc b/ios/chrome/browser/autofill/strike_database_factory.cc
index a944172..f52a73f 100644
--- a/ios/chrome/browser/autofill/strike_database_factory.cc
+++ b/ios/chrome/browser/autofill/strike_database_factory.cc
@@ -11,6 +11,7 @@
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/leveldb_proto/proto_database_provider_factory.h"
 
 namespace autofill {
 
@@ -30,7 +31,9 @@
 StrikeDatabaseFactory::StrikeDatabaseFactory()
     : BrowserStateKeyedServiceFactory(
           "AutofillStrikeDatabase",
-          BrowserStateDependencyManager::GetInstance()) {}
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(leveldb_proto::ProtoDatabaseProviderFactory::GetInstance());
+}
 
 StrikeDatabaseFactory::~StrikeDatabaseFactory() {}
 
@@ -38,9 +41,13 @@
     web::BrowserState* context) const {
   ios::ChromeBrowserState* chrome_browser_state =
       ios::ChromeBrowserState::FromBrowserState(context);
+
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::ProtoDatabaseProviderFactory::GetInstance()
+          ->GetForBrowserState(chrome_browser_state);
+
   return std::make_unique<autofill::StrikeDatabase>(
-      chrome_browser_state->GetStatePath().Append(
-          FILE_PATH_LITERAL("AutofillStrikeDatabase")));
+      db_provider, chrome_browser_state->GetStatePath());
 }
 
 }  // namespace autofill
diff --git a/ios/chrome/browser/overlays/BUILD.gn b/ios/chrome/browser/overlays/BUILD.gn
index 4f4ecbf1..caab1345 100644
--- a/ios/chrome/browser/overlays/BUILD.gn
+++ b/ios/chrome/browser/overlays/BUILD.gn
@@ -16,6 +16,8 @@
   sources = [
     "overlay_manager_impl.h",
     "overlay_manager_impl.mm",
+    "overlay_presenter.h",
+    "overlay_presenter.mm",
     "overlay_request_impl.cc",
     "overlay_request_impl.h",
     "overlay_request_queue_impl.h",
diff --git a/ios/chrome/browser/overlays/overlay_manager_impl.h b/ios/chrome/browser/overlays/overlay_manager_impl.h
index 7589d71b9..26237558 100644
--- a/ios/chrome/browser/overlays/overlay_manager_impl.h
+++ b/ios/chrome/browser/overlays/overlay_manager_impl.h
@@ -9,13 +9,13 @@
 #include <memory>
 
 #include "base/observer_list.h"
+#import "ios/chrome/browser/main/browser_observer.h"
+#include "ios/chrome/browser/overlays/overlay_presenter.h"
 #include "ios/chrome/browser/overlays/public/overlay_manager.h"
 #include "ios/chrome/browser/overlays/public/overlay_user_data.h"
 
-class WebStateList;
-
 // Internal implementation of OverlayManager.
-class OverlayManagerImpl : public OverlayManager {
+class OverlayManagerImpl : public BrowserObserver, public OverlayManager {
  public:
   ~OverlayManagerImpl() override;
 
@@ -31,27 +31,25 @@
 
    private:
     OVERLAY_USER_DATA_SETUP(Container);
-    explicit Container(WebStateList* web_state_list);
+    explicit Container(Browser* browser);
 
-    WebStateList* web_state_list_ = nullptr;
+    Browser* browser_ = nullptr;
     std::map<OverlayModality, std::unique_ptr<OverlayManagerImpl>> managers_;
   };
 
+  // BrowserObserver:
+  void BrowserDestroyed(Browser* browser) override;
+
   // OverlayManager:
   void SetUIDelegate(OverlayUIDelegate* ui_delegate) override;
   void AddObserver(OverlayManagerObserver* observer) override;
   void RemoveObserver(OverlayManagerObserver* observer) override;
 
  private:
-  OverlayManagerImpl(WebStateList* web_state_list);
+  OverlayManagerImpl(Browser* browser, OverlayModality modality);
 
-  // The manager's observers.
   base::ObserverList<OverlayManagerObserver>::Unchecked observers_;
-  // The Browser's WebStateList.  Used to update overlay scheduling for when
-  // WebStates are removed from the Browser.
-  WebStateList* web_state_list_ = nullptr;
-  // The UI delegate provided to the manager.
-  OverlayUIDelegate* ui_delegate_ = nullptr;
+  OverlayPresenter presenter_;
 };
 
 #endif  // IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_MANAGER_IMPL_H_
diff --git a/ios/chrome/browser/overlays/overlay_manager_impl.mm b/ios/chrome/browser/overlays/overlay_manager_impl.mm
index 896390e..1d9aa43 100644
--- a/ios/chrome/browser/overlays/overlay_manager_impl.mm
+++ b/ios/chrome/browser/overlays/overlay_manager_impl.mm
@@ -20,8 +20,7 @@
 // static
 OverlayManager* OverlayManager::FromBrowser(Browser* browser,
                                             OverlayModality modality) {
-  OverlayManagerImpl::Container::CreateForUserData(browser,
-                                                   browser->GetWebStateList());
+  OverlayManagerImpl::Container::CreateForUserData(browser, browser);
   return OverlayManagerImpl::Container::FromUserData(browser)
       ->ManagerForModality(modality);
 }
@@ -30,8 +29,9 @@
 
 OVERLAY_USER_DATA_SETUP_IMPL(OverlayManagerImpl::Container);
 
-OverlayManagerImpl::Container::Container(WebStateList* web_state_list)
-    : web_state_list_(web_state_list) {}
+OverlayManagerImpl::Container::Container(Browser* browser) : browser_(browser) {
+  DCHECK(browser_);
+}
 
 OverlayManagerImpl::Container::~Container() = default;
 
@@ -39,24 +39,32 @@
     OverlayModality modality) {
   auto& manager = managers_[modality];
   if (!manager) {
-    manager = base::WrapUnique(new OverlayManagerImpl(web_state_list_));
+    manager = base::WrapUnique(new OverlayManagerImpl(browser_, modality));
   }
   return manager.get();
 }
 
 #pragma mark - OverlayManagerImpl
 
-OverlayManagerImpl::OverlayManagerImpl(WebStateList* web_state_list)
-    : web_state_list_(web_state_list) {
-  DCHECK(web_state_list_);
+OverlayManagerImpl::OverlayManagerImpl(Browser* browser,
+                                       OverlayModality modality)
+    : presenter_(modality, browser->GetWebStateList()) {
+  browser->AddObserver(this);
 }
 
 OverlayManagerImpl::~OverlayManagerImpl() = default;
 
+#pragma mark BrowserObserver
+
+void OverlayManagerImpl::BrowserDestroyed(Browser* browser) {
+  presenter_.Disconnect();
+  browser->RemoveObserver(this);
+}
+
+#pragma mark OverlayManager
+
 void OverlayManagerImpl::SetUIDelegate(OverlayUIDelegate* ui_delegate) {
-  ui_delegate_ = ui_delegate;
-  // TODO(crbug.com/941745): Trigger the scheduling of the overlay UI
-  // presentation.
+  presenter_.SetUIDelegate(ui_delegate);
 }
 
 void OverlayManagerImpl::AddObserver(OverlayManagerObserver* observer) {
diff --git a/ios/chrome/browser/overlays/overlay_manager_impl_unittest.mm b/ios/chrome/browser/overlays/overlay_manager_impl_unittest.mm
index 81fe3dd8..644b173 100644
--- a/ios/chrome/browser/overlays/overlay_manager_impl_unittest.mm
+++ b/ios/chrome/browser/overlays/overlay_manager_impl_unittest.mm
@@ -4,6 +4,8 @@
 
 #import "ios/chrome/browser/overlays/overlay_manager_impl.h"
 
+#import "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#import "ios/chrome/browser/main/test_browser.h"
 #include "ios/chrome/browser/overlays/public/overlay_request.h"
 #include "ios/chrome/browser/overlays/public/overlay_request_queue.h"
 #include "ios/chrome/browser/overlays/test/fake_overlay_user_data.h"
@@ -11,41 +13,37 @@
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_opener.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
+#include "ios/web/public/test/test_web_thread_bundle.h"
 #include "testing/platform_test.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-namespace {
-// The full Browser object is not used by OverlayManagerImpl; just its user data
-// support.  base::SupportsUserData has a protected destructor, so a subclass
-// must be used.
-class TestBrowser : public base::SupportsUserData {
- public:
-  TestBrowser() = default;
-  ~TestBrowser() override = default;
-};
-}  // namespace
-
 // Test fixture for OverlayManagerImpl.
 class OverlayManagerImplTest : public PlatformTest {
  public:
   OverlayManagerImplTest() : web_state_list_(&web_state_list_delegate_) {
-    web_state_list_.InsertWebState(/* index */ 0,
-                                   std::make_unique<web::TestWebState>(), 0,
-                                   WebStateOpener());
-    OverlayManagerImpl::Container::CreateForUserData(&browser_,
-                                                     &web_state_list_);
-    manager_ = OverlayManagerImpl::Container::FromUserData(&browser_)
+    // Set up a TestChromeBrowserState instance.
+    TestChromeBrowserState::Builder browser_state_builder;
+    chrome_browser_state_ = browser_state_builder.Build();
+    // Create the Browser.
+    browser_ = std::make_unique<TestBrowser>(chrome_browser_state_.get(),
+                                             &web_state_list_);
+    // Use the kWebContentArea modality manager for testing.
+    OverlayManagerImpl::Container::CreateForUserData(browser_.get(),
+                                                     browser_.get());
+    manager_ = OverlayManagerImpl::Container::FromUserData(browser_.get())
                    ->ManagerForModality(OverlayModality::kWebContentArea);
   }
   OverlayManagerImpl* manager() const { return manager_; }
   web::WebState* web_state() const { return web_state_list_.GetWebStateAt(0); }
 
  private:
+  web::TestWebThreadBundle thread_bundle_;
   FakeWebStateListDelegate web_state_list_delegate_;
   WebStateList web_state_list_;
-  TestBrowser browser_;
+  std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
+  std::unique_ptr<Browser> browser_;
   OverlayManagerImpl* manager_;
 };
diff --git a/ios/chrome/browser/overlays/overlay_presenter.h b/ios/chrome/browser/overlays/overlay_presenter.h
new file mode 100644
index 0000000..0b676c91
--- /dev/null
+++ b/ios/chrome/browser/overlays/overlay_presenter.h
@@ -0,0 +1,72 @@
+// 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 IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_H_
+#define IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_H_
+
+#import "ios/chrome/browser/overlays/overlay_request_queue_impl_observer.h"
+#import "ios/chrome/browser/overlays/public/overlay_modality.h"
+#import "ios/chrome/browser/web_state_list/web_state_list_observer.h"
+
+class OverlayUIDelegate;
+
+// OverlayPresenter is responsible for triggering the presentation of overlay UI
+// at a given modality.  It observes OverlayRequestQueue modifications for the
+// active WebState and triggers the presentation for added requests using the UI
+// delegate.  Additionally, the presenter will manage hiding and showing
+// overlays when the foreground tab is updated.
+class OverlayPresenter : public OverlayRequestQueueImplObserver,
+                         public WebStateListObserver {
+ public:
+  OverlayPresenter(OverlayModality modality, WebStateList* web_state_list);
+  ~OverlayPresenter() override;
+
+  // Setter for the UI delegate.  The presenter will begin trying to present
+  // overlay UI when the delegate is set.
+  void SetUIDelegate(OverlayUIDelegate* ui_delegate);
+
+  // Disconnects observers in preparation of shutdown.  Must be called before
+  // destruction.
+  void Disconnect();
+
+ private:
+  // Fetches the request queue for |web_state|, creating it if necessary.
+  OverlayRequestQueueImpl* GetQueueForWebState(web::WebState* web_state);
+
+  // Starts and stops observing |web_state_list_| and its WebStates request
+  // queues.
+  void StartObserving();
+  void StopObserving();
+
+  // OverlayRequestQueueImplObserver:
+  void OnRequestAdded(OverlayRequestQueueImpl* queue,
+                      OverlayRequest* request) override;
+  void OnRequestRemoved(OverlayRequestQueueImpl* queue,
+                        OverlayRequest* request,
+                        bool frontmost) override;
+
+  // WebStateListObserver:
+  void WebStateInsertedAt(WebStateList* web_state_list,
+                          web::WebState* web_state,
+                          int index,
+                          bool activating) override;
+  void WebStateReplacedAt(WebStateList* web_state_list,
+                          web::WebState* old_web_state,
+                          web::WebState* new_web_state,
+                          int index) override;
+  void WillDetachWebStateAt(WebStateList* web_state_list,
+                            web::WebState* web_state,
+                            int index) override;
+  void WebStateActivatedAt(WebStateList* web_state_list,
+                           web::WebState* old_web_state,
+                           web::WebState* new_web_state,
+                           int active_index,
+                           int reason) override;
+
+  OverlayModality modality_;
+  WebStateList* web_state_list_ = nullptr;
+  OverlayUIDelegate* ui_delegate_ = nullptr;
+};
+
+#endif  // IOS_CHROME_BROWSER_OVERLAYS_OVERLAY_PRESENTER_H_
diff --git a/ios/chrome/browser/overlays/overlay_presenter.mm b/ios/chrome/browser/overlays/overlay_presenter.mm
new file mode 100644
index 0000000..92c722f5
--- /dev/null
+++ b/ios/chrome/browser/overlays/overlay_presenter.mm
@@ -0,0 +1,130 @@
+// 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.
+
+#import "ios/chrome/browser/overlays/overlay_presenter.h"
+
+#include "base/logging.h"
+#import "ios/chrome/browser/overlays/overlay_request_queue_impl.h"
+#import "ios/chrome/browser/overlays/public/overlay_ui_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+OverlayPresenter::OverlayPresenter(OverlayModality modality,
+                                   WebStateList* web_state_list)
+    : modality_(modality), web_state_list_(web_state_list) {
+  DCHECK(web_state_list_);
+}
+
+OverlayPresenter::~OverlayPresenter() {
+  // Disconnect() must be called before destruction.
+  DCHECK(!ui_delegate_);
+  DCHECK(!web_state_list_);
+}
+
+#pragma mark - Public
+
+void OverlayPresenter::SetUIDelegate(OverlayUIDelegate* ui_delegate) {
+  if (ui_delegate_) {
+    // TODO:(crbug.com/941745): Cancel all overlays for previous UI delegate.
+    StopObserving();
+  }
+  ui_delegate_ = ui_delegate;
+  if (ui_delegate_) {
+    StartObserving();
+    // TODO:(crbug.com/941745): Show overlay for frontmost request in active
+    // WebState's queue.
+  }
+}
+
+void OverlayPresenter::Disconnect() {
+  SetUIDelegate(nullptr);
+  web_state_list_ = nullptr;
+}
+
+#pragma mark - Private
+
+OverlayRequestQueueImpl* OverlayPresenter::GetQueueForWebState(
+    web::WebState* web_state) {
+  OverlayRequestQueueImpl::Container::CreateForWebState(web_state);
+  return OverlayRequestQueueImpl::Container::FromWebState(web_state)
+      ->QueueForModality(modality_);
+}
+
+void OverlayPresenter::StartObserving() {
+  web_state_list_->AddObserver(this);
+  for (int i = 0; i < web_state_list_->count(); ++i) {
+    GetQueueForWebState(web_state_list_->GetWebStateAt(i))->AddObserver(this);
+  }
+}
+
+void OverlayPresenter::StopObserving() {
+  for (int i = 0; i < web_state_list_->count(); ++i) {
+    GetQueueForWebState(web_state_list_->GetWebStateAt(i))
+        ->RemoveObserver(this);
+  }
+  web_state_list_->RemoveObserver(this);
+}
+
+#pragma mark - OverlayRequestQueueImplObserver
+
+void OverlayPresenter::OnRequestAdded(OverlayRequestQueueImpl* queue,
+                                      OverlayRequest* request) {
+  // If the added request is first in the queue, trigger the UI presentation for
+  // that reqeust.
+  if (request == queue->front_request()) {
+    // TODO:(crbug.com/941745): Trigger presentation for request.
+  }
+}
+
+void OverlayPresenter::OnRequestRemoved(OverlayRequestQueueImpl* queue,
+                                        OverlayRequest* request,
+                                        bool frontmost) {
+  // Only attempt to present overlay UI for the next reqeust for removal of the
+  // frontmost request.
+  if (frontmost) {
+    // TODO:(crbug.com/941745): Trigger presentation for next request in queue.
+  }
+}
+
+#pragma mark - WebStateListObserver
+
+void OverlayPresenter::WebStateInsertedAt(WebStateList* web_state_list,
+                                          web::WebState* web_state,
+                                          int index,
+                                          bool activating) {
+  GetQueueForWebState(web_state)->AddObserver(this);
+  if (activating) {
+    // TODO:(crbug.com/941745): If showing an overlay, dismiss it.  Then show
+    // the overlay for the frontmost request in |web_state|'s queue.
+  }
+}
+
+void OverlayPresenter::WebStateReplacedAt(WebStateList* web_state_list,
+                                          web::WebState* old_web_state,
+                                          web::WebState* new_web_state,
+                                          int index) {
+  GetQueueForWebState(old_web_state)->RemoveObserver(this);
+  GetQueueForWebState(new_web_state)->AddObserver(this);
+  // TODO:(crbug.com/941745): Show overlay for first request in |new_web_state|
+  // if it's active.
+}
+
+void OverlayPresenter::WillDetachWebStateAt(WebStateList* web_state_list,
+                                            web::WebState* web_state,
+                                            int index) {
+  GetQueueForWebState(web_state)->RemoveObserver(this);
+  // TODO:(crbug.com/941745): Cancel overlays for |web_state|.
+}
+
+void OverlayPresenter::WebStateActivatedAt(WebStateList* web_state_list,
+                                           web::WebState* old_web_state,
+                                           web::WebState* new_web_state,
+                                           int active_index,
+                                           int reason) {
+  // TODO:(crbug.com/941745): If showing an overlay, dismiss it.  Then show the
+  // overlay for the frontmost request in |web_state|'s queue.
+}
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 0efbee9e..0416916 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -34,7 +34,6 @@
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/sync/password_model_worker.h"
 #include "components/reading_list/core/reading_list_model.h"
-#include "components/search_engines/search_engine_data_type_controller.h"
 #include "components/sync/base/report_unrecoverable_error.h"
 #include "components/sync/driver/sync_api_component_factory.h"
 #include "components/sync/driver/sync_service.h"
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
index 9b638484..f3f45db 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/fallback_coordinator_egtest.mm
@@ -569,6 +569,10 @@
 
 // Tests that the manual fallback view is present in incognito.
 - (void)testIncognitoManualFallbackMenu {
+  // TODO(crbug.com/958015): reenable test.
+  if (UIScreen.mainScreen.bounds.size.height == 568) {
+    EARL_GREY_TEST_DISABLED(@"Test disabled on iPhone 5S.");
+  }
   // Add the profile to use for verification.
   AddAutofillProfile(_personalDataManager);
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index 5cfd303..6247f5b64 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -31,7 +31,6 @@
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/chrome/test/app/bookmarks_test_util.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/chrome/test/earl_grey/accessibility_util.h"
diff --git a/ios/chrome/browser/ui/keyboard/keyboard_commands_egtest.mm b/ios/chrome/browser/ui/keyboard/keyboard_commands_egtest.mm
index 56be81f..8d96038 100644
--- a/ios/chrome/browser/ui/keyboard/keyboard_commands_egtest.mm
+++ b/ios/chrome/browser/ui/keyboard/keyboard_commands_egtest.mm
@@ -14,7 +14,6 @@
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/chrome/test/app/bookmarks_test_util.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
diff --git a/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm b/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm
index f444107..700a8e0 100644
--- a/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm
+++ b/ios/chrome/browser/ui/settings/sync/utils/sync_fake_server_egtest.mm
@@ -20,7 +20,6 @@
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/settings/settings_table_view_controller.h"
 #include "ios/chrome/grit/ios_strings.h"
-#import "ios/chrome/test/app/bookmarks_test_util.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/history_test_util.h"
 #import "ios/chrome/test/app/sync_test_util.h"
diff --git a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
index 380ebf6..470b907 100644
--- a/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
+++ b/ios/chrome/browser/ui/toolbar/adaptive_toolbar_egtest.mm
@@ -20,7 +20,6 @@
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
-#include "ios/chrome/test/app/bookmarks_test_util.h"
 #import "ios/chrome/test/app/chrome_test_util.h"
 #import "ios/chrome/test/app/tab_test_util.h"
 #import "ios/chrome/test/earl_grey/chrome_actions.h"
diff --git a/ios/public/provider/chrome/browser/signin/OWNERS b/ios/public/provider/chrome/browser/signin/OWNERS
index 6068057..5ccf334 100644
--- a/ios/public/provider/chrome/browser/signin/OWNERS
+++ b/ios/public/provider/chrome/browser/signin/OWNERS
@@ -1,4 +1,4 @@
-bzanotti@chromium.org
+jlebel@chromium.org
 msarda@chromium.org
 
 # COMPONENT: Services>SignIn
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index cfa45642..5aacaa54 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -340,7 +340,6 @@
     "net/crw_ssl_status_updater_unittest.mm",
     "net/request_group_util_unittest.mm",
     "net/request_tracker_impl_unittest.mm",
-    "net/web_http_protocol_handler_delegate_unittest.mm",
   ]
 }
 
diff --git a/ios/web/net/BUILD.gn b/ios/web/net/BUILD.gn
index a5c74b69..2ebaf6a6 100644
--- a/ios/web/net/BUILD.gn
+++ b/ios/web/net/BUILD.gn
@@ -35,8 +35,6 @@
     "request_tracker_factory_impl.mm",
     "request_tracker_impl.h",
     "request_tracker_impl.mm",
-    "web_http_protocol_handler_delegate.h",
-    "web_http_protocol_handler_delegate.mm",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/web/net/web_http_protocol_handler_delegate.h b/ios/web/net/web_http_protocol_handler_delegate.h
deleted file mode 100644
index 0865bc0..0000000
--- a/ios/web/net/web_http_protocol_handler_delegate.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_WEB_NET_WEB_HTTP_PROTOCOL_HANDLER_DELEGATE_H_
-#define IOS_WEB_NET_WEB_HTTP_PROTOCOL_HANDLER_DELEGATE_H_
-
-#include "base/memory/ref_counted.h"
-#import "ios/net/crn_http_protocol_handler.h"
-
-@class NSURLRequest;
-
-namespace web {
-
-// Returns whether the request should be allowed for rendering into a special
-// UIWebView that allows static file content.
-bool IsStaticFileRequest(NSURLRequest* request);
-
-// Web-specific implementation of net::HTTPProtocolHandlerDelegate.
-class WebHTTPProtocolHandlerDelegate : public net::HTTPProtocolHandlerDelegate {
- public:
-  WebHTTPProtocolHandlerDelegate(net::URLRequestContextGetter* default_getter);
-  ~WebHTTPProtocolHandlerDelegate() override;
-
-  // net::HTTPProtocolHandlerDelegate implementation:
-  bool CanHandleRequest(NSURLRequest* request) override;
-  bool IsRequestSupported(NSURLRequest* request) override;
-  net::URLRequestContextGetter* GetDefaultURLRequestContext() override;
-
- private:
-  scoped_refptr<net::URLRequestContextGetter> default_getter_;
-};
-
-}  // namespace web
-
-#endif  // IOS_WEB_NET_WEB_HTTP_PROTOCOL_HANDLER_DELEGATE_H_
diff --git a/ios/web/net/web_http_protocol_handler_delegate.mm b/ios/web/net/web_http_protocol_handler_delegate.mm
deleted file mode 100644
index 7c335ab..0000000
--- a/ios/web/net/web_http_protocol_handler_delegate.mm
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/web/net/web_http_protocol_handler_delegate.h"
-
-#import <Foundation/Foundation.h>
-
-#import "base/strings/sys_string_conversions.h"
-#import "ios/web/public/url_scheme_util.h"
-#import "ios/web/public/web_client.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-
-bool IsAppSpecificScheme(NSURL* url) {
-  NSString* scheme = [url scheme];
-  if (![scheme length])
-    return false;
-  // Use the GURL implementation, but with a scheme-only URL to avoid
-  // unnecessary parsing in GURL construction.
-  GURL gurl(base::SysNSStringToUTF8([scheme stringByAppendingString:@":"]));
-  return web::GetWebClient()->IsAppSpecificURL(gurl);
-}
-
-}  // namespace
-
-namespace web {
-
-bool IsStaticFileRequest(NSURLRequest* request) {
-  NSString* user_agent = [request allHTTPHeaderFields][@"User-Agent"];
-  if (user_agent) {
-    return [user_agent hasPrefix:@"UIWebViewForStaticFileContent"];
-  }
-
-  // If a request originated from another file:/// page, the User-Agent
-  // is not available. In this case, check that the request is for image
-  // resources only.
-  NSString* suffix = [[request URL] pathExtension];
-  return [@[ @"png", @"jpg", @"jpeg" ] containsObject:[suffix lowercaseString]];
-}
-
-WebHTTPProtocolHandlerDelegate::WebHTTPProtocolHandlerDelegate(
-    net::URLRequestContextGetter* default_getter)
-    : default_getter_(default_getter) {
-  DCHECK(default_getter_);
-}
-
-WebHTTPProtocolHandlerDelegate::~WebHTTPProtocolHandlerDelegate() {
-}
-
-bool WebHTTPProtocolHandlerDelegate::CanHandleRequest(NSURLRequest* request) {
-  // Accept all the requests. If we declined a request, it would then be passed
-  // to the default iOS network stack, which would possibly load it.
-  // As we want to control what is loaded, we have to prevent the default stack
-  // from loading anything.
-  return true;
-}
-
-bool WebHTTPProtocolHandlerDelegate::IsRequestSupported(NSURLRequest* request) {
-  return web::UrlHasWebScheme([request URL]) || IsStaticFileRequest(request) ||
-         (IsAppSpecificScheme([request URL]) &&
-          IsAppSpecificScheme([request mainDocumentURL]));
-}
-
-net::URLRequestContextGetter*
-WebHTTPProtocolHandlerDelegate::GetDefaultURLRequestContext() {
-  return default_getter_.get();
-}
-
-}  // namespace web
diff --git a/ios/web/net/web_http_protocol_handler_delegate_unittest.mm b/ios/web/net/web_http_protocol_handler_delegate_unittest.mm
deleted file mode 100644
index 12dcb2e..0000000
--- a/ios/web/net/web_http_protocol_handler_delegate_unittest.mm
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/web/net/web_http_protocol_handler_delegate.h"
-
-#import <Foundation/Foundation.h>
-
-#include <memory>
-
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/stl_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "ios/web/public/test/scoped_testing_web_client.h"
-#import "ios/web/public/web_client.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace web {
-
-namespace {
-
-// Test application specific scheme.
-const char kAppSpecificScheme[] = "appspecific";
-
-// URLs expected to be supported.
-const char* kSupportedURLs[] = {
-    "http://foo.com",
-    "https://foo.com",
-    "data:text/html;charset=utf-8,Hello",
-};
-
-// URLs expected to be unsupported.
-const char* kUnsupportedURLs[] = {
-    "foo:blank",          // Unknown scheme.
-    "appspecific:blank",  // No main document URL.
-};
-
-// Test web client with an application specific scheme.
-class AppSpecificURLTestWebClient : public WebClient {
- public:
-  bool IsAppSpecificURL(const GURL& url) const override {
-    return url.SchemeIs(kAppSpecificScheme);
-  }
-};
-
-class WebHTTPProtocolHandlerDelegateTest : public PlatformTest {
- public:
-  WebHTTPProtocolHandlerDelegateTest()
-      : context_getter_(new net::TestURLRequestContextGetter(
-            base::ThreadTaskRunnerHandle::Get())),
-        delegate_(new WebHTTPProtocolHandlerDelegate(context_getter_.get())),
-        web_client_(base::WrapUnique(new AppSpecificURLTestWebClient)) {}
-
- protected:
-  base::MessageLoop message_loop_;
-  scoped_refptr<net::URLRequestContextGetter> context_getter_;
-  std::unique_ptr<WebHTTPProtocolHandlerDelegate> delegate_;
-  web::ScopedTestingWebClient web_client_;
-};
-
-}  // namespace
-
-TEST_F(WebHTTPProtocolHandlerDelegateTest, IsRequestSupported) {
-  NSMutableURLRequest* request;
-
-  for (unsigned int i = 0; i < base::size(kSupportedURLs); ++i) {
-    NSString* url_string =
-        [[NSString alloc] initWithUTF8String:kSupportedURLs[i]];
-    request = [[NSMutableURLRequest alloc]
-        initWithURL:[NSURL URLWithString:url_string]];
-    EXPECT_TRUE(delegate_->IsRequestSupported(request))
-        << kSupportedURLs[i] << " should be supported.";
-  }
-
-  for (unsigned int i = 0; i < base::size(kUnsupportedURLs); ++i) {
-    NSString* url_string =
-        [[NSString alloc] initWithUTF8String:kUnsupportedURLs[i]];
-    request = [[NSMutableURLRequest alloc]
-        initWithURL:[NSURL URLWithString:url_string]];
-    EXPECT_FALSE(delegate_->IsRequestSupported(request))
-        << kUnsupportedURLs[i] << " should NOT be supported.";
-  }
-
-  // Application specific scheme with main document URL.
-  request = [[NSMutableURLRequest alloc]
-      initWithURL:[NSURL URLWithString:@"appspecific:blank"]];
-  [request setMainDocumentURL:[NSURL URLWithString:@"http://foo"]];
-  EXPECT_FALSE(delegate_->IsRequestSupported(request));
-  [request setMainDocumentURL:[NSURL URLWithString:@"appspecific:main"]];
-  EXPECT_TRUE(delegate_->IsRequestSupported(request));
-  request = [[NSMutableURLRequest alloc]
-      initWithURL:[NSURL URLWithString:@"foo:blank"]];
-  [request setMainDocumentURL:[NSURL URLWithString:@"appspecific:main"]];
-  EXPECT_FALSE(delegate_->IsRequestSupported(request));
-}
-
-TEST_F(WebHTTPProtocolHandlerDelegateTest, IsRequestSupportedMalformed) {
-  NSURLRequest* request;
-
-  // Null URL.
-  request = [[NSMutableURLRequest alloc] init];
-  ASSERT_FALSE([request URL]);
-  EXPECT_FALSE(delegate_->IsRequestSupported(request));
-
-  // URL with no scheme.
-  request =
-      [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"foo"]];
-  ASSERT_TRUE([request URL]);
-  ASSERT_FALSE([[request URL] scheme]);
-  EXPECT_FALSE(delegate_->IsRequestSupported(request));
-
-  // Empty scheme.
-  request =
-      [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@":foo"]];
-  ASSERT_TRUE([request URL]);
-  ASSERT_TRUE([[request URL] scheme]);
-  ASSERT_FALSE([[[request URL] scheme] length]);
-  EXPECT_FALSE(delegate_->IsRequestSupported(request));
-}
-
-// Tests that requests for images are considered as static file requests,
-// regardless of the user agent.
-TEST_F(WebHTTPProtocolHandlerDelegateTest, TestIsStaticImageRequestTrue) {
-  // Empty dictionary so User-Agent check fails.
-  NSDictionary* headers = @{};
-  NSURL* url = [NSURL URLWithString:@"file:///show/this.png"];
-  id mock_request = [OCMockObject mockForClass:[NSURLRequest class]];
-  [[[mock_request stub] andReturn:headers] allHTTPHeaderFields];
-  [[[mock_request stub] andReturn:url] URL];
-  EXPECT_TRUE(IsStaticFileRequest(mock_request));
-}
-
-// Tests that requests for files are considered as static file requests if they
-// have the static file user agent.
-TEST_F(WebHTTPProtocolHandlerDelegateTest, TestIsStaticFileRequestTrue) {
-  NSDictionary* headers =
-      @{ @"User-Agent" : @"UIWebViewForStaticFileContent foo" };
-  NSURL* url = [NSURL URLWithString:@"file:///some/random/url.html"];
-  id mock_request = [OCMockObject mockForClass:[NSURLRequest class]];
-  [[[mock_request stub] andReturn:headers] allHTTPHeaderFields];
-  [[[mock_request stub] andReturn:url] URL];
-  EXPECT_TRUE(IsStaticFileRequest(mock_request));
-}
-
-// Tests that arbitrary files cannot be retrieved by a web view for
-// static file content.
-TEST_F(WebHTTPProtocolHandlerDelegateTest, TestIsStaticFileRequestFalse) {
-  // Empty dictionary so User-Agent check fails.
-  NSDictionary* headers = @{};
-  NSURL* url = [NSURL URLWithString:@"file:///steal/this/file.html"];
-  id mock_request = [OCMockObject mockForClass:[NSURLRequest class]];
-  [[[mock_request stub] andReturn:headers] allHTTPHeaderFields];
-  [[[mock_request stub] andReturn:url] URL];
-  EXPECT_FALSE(IsStaticFileRequest(mock_request));
-}
-
-}  // namespace web
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index 272aa4f..0df6787f 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -148,6 +148,8 @@
   "internal/language/web_view_language_model_manager_factory.mm",
   "internal/language/web_view_url_language_histogram_factory.h",
   "internal/language/web_view_url_language_histogram_factory.mm",
+  "internal/leveldb_proto/web_view_proto_database_provider_factory.h",
+  "internal/leveldb_proto/web_view_proto_database_provider_factory.mm",
   "internal/passwords/mock_credentials_filter.h",
   "internal/passwords/mock_credentials_filter.mm",
   "internal/passwords/web_view_password_manager_client.h",
@@ -274,6 +276,7 @@
   "//components/keyed_service/ios",
   "//components/language/core/browser",
   "//components/language/core/common",
+  "//components/leveldb_proto",
   "//components/net_log",
   "//services/network:network_service",
   "//components/password_manager/core/browser",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index e400b91..76ed62f 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -13,6 +13,7 @@
   "+components/keyed_service/ios",
   "+components/language/core/browser",
   "+components/language/core/common",
+  "+components/leveldb_proto/public",
   "+components/net_log",
   "+components/password_manager/core",
   "+components/password_manager/ios",
diff --git a/ios/web_view/internal/autofill/web_view_legacy_strike_database_factory.mm b/ios/web_view/internal/autofill/web_view_legacy_strike_database_factory.mm
index 39dc93e..ddb91cc2 100644
--- a/ios/web_view/internal/autofill/web_view_legacy_strike_database_factory.mm
+++ b/ios/web_view/internal/autofill/web_view_legacy_strike_database_factory.mm
@@ -10,6 +10,7 @@
 #include "components/autofill/core/browser/payments/legacy_strike_database.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "ios/web_view/internal/app/application_context.h"
+#include "ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -36,7 +37,9 @@
 WebViewLegacyStrikeDatabaseFactory::WebViewLegacyStrikeDatabaseFactory()
     : BrowserStateKeyedServiceFactory(
           "AutofillLegacyStrikeDatabase",
-          BrowserStateDependencyManager::GetInstance()) {}
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(leveldb_proto::WebViewProtoDatabaseProviderFactory::GetInstance());
+}
 
 WebViewLegacyStrikeDatabaseFactory::~WebViewLegacyStrikeDatabaseFactory() {}
 
@@ -45,9 +48,13 @@
     web::BrowserState* context) const {
   WebViewBrowserState* browser_state =
       WebViewBrowserState::FromBrowserState(context);
+
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::WebViewProtoDatabaseProviderFactory::GetInstance()
+          ->GetForBrowserState(browser_state);
+
   return std::make_unique<autofill::LegacyStrikeDatabase>(
-      browser_state->GetStatePath().Append(
-          FILE_PATH_LITERAL("AutofillStrikeDatabase")));
+      db_provider, browser_state->GetStatePath());
 }
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/autofill/web_view_strike_database_factory.mm b/ios/web_view/internal/autofill/web_view_strike_database_factory.mm
index ba9eb83..eb921bb 100644
--- a/ios/web_view/internal/autofill/web_view_strike_database_factory.mm
+++ b/ios/web_view/internal/autofill/web_view_strike_database_factory.mm
@@ -10,6 +10,7 @@
 #include "components/autofill/core/browser/payments/strike_database.h"
 #include "components/keyed_service/ios/browser_state_dependency_manager.h"
 #include "ios/web_view/internal/app/application_context.h"
+#include "ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -34,7 +35,9 @@
 WebViewStrikeDatabaseFactory::WebViewStrikeDatabaseFactory()
     : BrowserStateKeyedServiceFactory(
           "AutofillStrikeDatabase",
-          BrowserStateDependencyManager::GetInstance()) {}
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(leveldb_proto::WebViewProtoDatabaseProviderFactory::GetInstance());
+}
 
 WebViewStrikeDatabaseFactory::~WebViewStrikeDatabaseFactory() {}
 
@@ -43,9 +46,13 @@
     web::BrowserState* context) const {
   WebViewBrowserState* browser_state =
       WebViewBrowserState::FromBrowserState(context);
+
+  leveldb_proto::ProtoDatabaseProvider* db_provider =
+      leveldb_proto::WebViewProtoDatabaseProviderFactory::GetInstance()
+          ->GetForBrowserState(browser_state);
+
   return std::make_unique<autofill::StrikeDatabase>(
-      browser_state->GetStatePath().Append(
-          FILE_PATH_LITERAL("AutofillStrikeDatabase")));
+      db_provider, browser_state->GetStatePath());
 }
 
 }  // namespace ios_web_view
diff --git a/ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.h b/ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.h
new file mode 100644
index 0000000..0a8e165
--- /dev/null
+++ b/ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.h
@@ -0,0 +1,49 @@
+// 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 IOS_WEB_VIEW_INTERNAL_LEVELDB_PROTO_WEB_VIEW_PROTO_DATABASE_PROVIDER_FACTORY_H_
+#define IOS_WEB_VIEW_INTERNAL_LEVELDB_PROTO_WEB_VIEW_PROTO_DATABASE_PROVIDER_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+namespace ios_web_view {
+class WebViewBrowserState;
+}  // namespace ios_web_view
+
+namespace leveldb_proto {
+class ProtoDatabaseProvider;
+
+// A factory for ProtoDatabaseProvider, a class that provides proto databases
+// stored in the appropriate directory given an
+// ios_web_view::WebViewBrowserState object.
+class WebViewProtoDatabaseProviderFactory
+    : public BrowserStateKeyedServiceFactory {
+ public:
+  // Returns singleton instance of WebViewProtoDatabaseProviderFactory.
+  static WebViewProtoDatabaseProviderFactory* GetInstance();
+
+  // Returns ProtoDatabaseProvider associated with |context|, so we can
+  // instantiate ProtoDatabases that use the appropriate profile directory.
+  static ProtoDatabaseProvider* GetForBrowserState(
+      ios_web_view::WebViewBrowserState* browser_state);
+
+ protected:
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+
+ private:
+  friend class base::NoDestructor<WebViewProtoDatabaseProviderFactory>;
+
+  WebViewProtoDatabaseProviderFactory();
+  ~WebViewProtoDatabaseProviderFactory() override;
+
+  DISALLOW_COPY_AND_ASSIGN(WebViewProtoDatabaseProviderFactory);
+};
+
+}  // namespace leveldb_proto
+
+#endif  // IOS_WEB_VIEW_INTERNAL_LEVELDB_PROTO_WEB_VIEW_PROTO_DATABASE_PROVIDER_FACTORY_H_
diff --git a/ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.mm b/ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.mm
new file mode 100644
index 0000000..1b17a28
--- /dev/null
+++ b/ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.mm
@@ -0,0 +1,46 @@
+// 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 "ios/web_view/internal/leveldb_proto/web_view_proto_database_provider_factory.h"
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/leveldb_proto/public/proto_database_provider.h"
+#include "ios/web_view/internal/web_view_browser_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace leveldb_proto {
+
+// static
+WebViewProtoDatabaseProviderFactory*
+WebViewProtoDatabaseProviderFactory::GetInstance() {
+  static base::NoDestructor<WebViewProtoDatabaseProviderFactory> instance;
+  return instance.get();
+}
+
+// static
+ProtoDatabaseProvider* WebViewProtoDatabaseProviderFactory::GetForBrowserState(
+    ios_web_view::WebViewBrowserState* browser_state) {
+  return static_cast<ProtoDatabaseProvider*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+WebViewProtoDatabaseProviderFactory::WebViewProtoDatabaseProviderFactory()
+    : BrowserStateKeyedServiceFactory(
+          "leveldb_proto::ProtoDatabaseProvider",
+          BrowserStateDependencyManager::GetInstance()) {}
+
+WebViewProtoDatabaseProviderFactory::~WebViewProtoDatabaseProviderFactory() =
+    default;
+
+std::unique_ptr<KeyedService>
+WebViewProtoDatabaseProviderFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  return std::make_unique<ProtoDatabaseProvider>(context->GetStatePath());
+}
+
+}  // namespace leveldb_proto
\ No newline at end of file
diff --git a/media/blink/webcontentdecryptionmodulesession_impl.cc b/media/blink/webcontentdecryptionmodulesession_impl.cc
index bc1bb19..5f081a9 100644
--- a/media/blink/webcontentdecryptionmodulesession_impl.cc
+++ b/media/blink/webcontentdecryptionmodulesession_impl.cc
@@ -152,8 +152,12 @@
   if (sanitized_session_id->length() > limits::kMaxSessionIdLength)
     return false;
 
+  // Check that |sanitized_session_id| only contains non-space printable
+  // characters for easier logging. Note that checking alphanumeric is too
+  // strict because there are key systems using Base64 session IDs. See
+  // https://crbug.com/902828.
   for (const char c : *sanitized_session_id) {
-    if (!base::IsAsciiAlpha(c) && !base::IsAsciiDigit(c))
+    if (!base::IsAsciiPrintable(c) || c == ' ')
       return false;
   }
 
diff --git a/media/capture/video/win/sink_input_pin_win.cc b/media/capture/video/win/sink_input_pin_win.cc
index ed40946a..92ae610 100644
--- a/media/capture/video/win/sink_input_pin_win.cc
+++ b/media/capture/video/win/sink_input_pin_win.cc
@@ -13,6 +13,7 @@
 
 #include "base/logging.h"
 #include "base/stl_util.h"
+#include "base/win/win_util.h"
 #include "media/base/timestamp_constants.h"
 
 namespace media {
@@ -111,11 +112,8 @@
     return true;
   }
 
-#ifndef NDEBUG
-  WCHAR guid_str[128];
-  StringFromGUID2(sub_type, guid_str, base::size(guid_str));
-  DVLOG(2) << __func__ << " unsupported media type: " << guid_str;
-#endif
+  DVLOG(2) << __func__ << " unsupported media type: "
+           << base::win::String16FromGUID(sub_type);
   return false;
 }
 
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc
index ee71ff53..db7ea55 100644
--- a/media/capture/video/win/video_capture_device_win.cc
+++ b/media/capture/video/win/video_capture_device_win.cc
@@ -17,6 +17,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_variant.h"
+#include "base/win/win_util.h"
 #include "media/base/media_switches.h"
 #include "media/base/timestamp_constants.h"
 #include "media/capture/mojom/image_capture_types.h"
@@ -338,11 +339,8 @@
     if (sub_type == pixel_format.sub_type)
       return pixel_format.format;
   }
-#ifndef NDEBUG
-  WCHAR guid_str[128];
-  StringFromGUID2(sub_type, guid_str, base::size(guid_str));
-  DVLOG(2) << "Device (also) supports an unknown media type " << guid_str;
-#endif
+  DVLOG(2) << "Device (also) supports an unknown media type "
+           << base::win::String16FromGUID(sub_type);
   return PIXEL_FORMAT_UNKNOWN;
 }
 
diff --git a/media/gpu/android/shared_image_video.cc b/media/gpu/android/shared_image_video.cc
index 26ecfa1..0bd0476e 100644
--- a/media/gpu/android/shared_image_video.cc
+++ b/media/gpu/android/shared_image_video.cc
@@ -12,9 +12,14 @@
 #include "gpu/command_buffer/service/abstract_texture.h"
 #include "gpu/command_buffer/service/mailbox_manager.h"
 #include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_representation.h"
+#include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/command_buffer/service/texture_manager.h"
 #include "media/gpu/android/codec_image.h"
+#include "third_party/skia/include/core/SkPromiseImageTexture.h"
+#include "third_party/skia/include/gpu/GrBackendSemaphore.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
 
 namespace media {
 
@@ -101,61 +106,125 @@
   bool BeginAccess(GLenum mode) override {
     auto* video_backing = static_cast<SharedImageVideo*>(backing());
     DCHECK(video_backing);
-
-    // For (old) overlays, we don't have a texture owner, but overlay promotion
-    // might not happen for some reasons. In that case, it will try to draw
-    // which should results in no image.
-    if (!texture_owner())
-      return true;
+    auto* codec_image = video_backing->codec_image_.get();
+    auto* texture_owner = codec_image->texture_owner().get();
 
     // Render the codec image.
-    codec_image()->RenderToFrontBuffer();
+    codec_image->RenderToFrontBuffer();
 
-    // Bind the tex image if its not already bound.
-    if (!texture_owner()->binds_texture_on_update())
-      texture_owner()->EnsureTexImageBound();
+    // Bind the tex image if it's not already bound.
+    if (!texture_owner->binds_texture_on_update())
+      texture_owner->EnsureTexImageBound();
     return true;
   }
 
   void EndAccess() override {}
 
  private:
-  SharedImageVideo* video_backing() {
-    auto* video_backing = static_cast<SharedImageVideo*>(backing());
-    return video_backing;
-  }
-
-  CodecImage* codec_image() {
-    DCHECK(video_backing());
-    return video_backing()->codec_image_.get();
-  }
-
-  TextureOwner* texture_owner() { return codec_image()->texture_owner().get(); }
-
   gpu::gles2::Texture* texture_;
 
   DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationGLTextureVideo);
 };
 
+// GL backed Skia representation of SharedImageVideo.
+class SharedImageRepresentationVideoSkiaGL
+    : public gpu::SharedImageRepresentationSkia {
+ public:
+  SharedImageRepresentationVideoSkiaGL(gpu::SharedImageManager* manager,
+                                       gpu::SharedImageBacking* backing,
+                                       gpu::MemoryTypeTracker* tracker)
+      : gpu::SharedImageRepresentationSkia(manager, backing, tracker) {}
+
+  ~SharedImageRepresentationVideoSkiaGL() override = default;
+
+  sk_sp<SkSurface> BeginWriteAccess(
+      int final_msaa_count,
+      const SkSurfaceProps& surface_props,
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores) override {
+    // Writes are not intended to used for video backed representations.
+    NOTIMPLEMENTED();
+    return nullptr;
+  }
+
+  void EndWriteAccess(sk_sp<SkSurface> surface) override { NOTIMPLEMENTED(); }
+
+  sk_sp<SkPromiseImageTexture> BeginReadAccess(
+      std::vector<GrBackendSemaphore>* begin_semaphores,
+      std::vector<GrBackendSemaphore>* end_semaphores) override {
+    if (!promise_texture_) {
+      auto* video_backing = static_cast<SharedImageVideo*>(backing());
+      DCHECK(video_backing);
+      auto* codec_image = video_backing->codec_image_.get();
+      auto* texture_owner = codec_image->texture_owner().get();
+
+      // Render the codec image.
+      codec_image->RenderToFrontBuffer();
+
+      // Bind the tex image if it's not already bound.
+      if (!texture_owner->binds_texture_on_update())
+        texture_owner->EnsureTexImageBound();
+      GrBackendTexture backend_texture;
+      if (!gpu::GetGrBackendTexture(
+              gl::GLContext::GetCurrent()->GetVersionInfo(),
+              GL_TEXTURE_EXTERNAL_OES, size(), texture_owner->GetTextureId(),
+              format(), &backend_texture)) {
+        return nullptr;
+      }
+      promise_texture_ = SkPromiseImageTexture::Make(backend_texture);
+    }
+    return promise_texture_;
+  }
+
+  void EndReadAccess() override {}
+
+ private:
+  sk_sp<SkPromiseImageTexture> promise_texture_;
+};
+
+// TODO(vikassoni): Currently GLRenderer doesn't support overlays with shared
+// image. Add support for overlays in GLRenderer as well as overlay
+// representations of shared image.
 std::unique_ptr<gpu::SharedImageRepresentationGLTexture>
 SharedImageVideo::ProduceGLTexture(gpu::SharedImageManager* manager,
                                    gpu::MemoryTypeTracker* tracker) {
-  // TODO(vikassoni): Also fix how overlays work with shared images to enable
-  // this representation. To make overlays work, we need to add a new overlay
-  // representation which can notify promotion hints and schedule overlay
-  // planes via |codec_image_|.
-  NOTIMPLEMENTED();
-  return nullptr;
+  // For (old) overlays, we don't have a texture owner, but overlay promotion
+  // might not happen for some reasons. In that case, it will try to draw
+  // which should result in no image.
+  if (!codec_image_->texture_owner())
+    return nullptr;
+  auto* texture = gpu::gles2::Texture::CheckedCast(
+      codec_image_->texture_owner()->GetTextureBase());
+  DCHECK(texture);
+
+  return std::make_unique<SharedImageRepresentationGLTextureVideo>(
+      manager, this, tracker, texture);
 }
 
+// Currently SkiaRenderer doesn't support overlays.
 std::unique_ptr<gpu::SharedImageRepresentationSkia>
 SharedImageVideo::ProduceSkia(
     gpu::SharedImageManager* manager,
     gpu::MemoryTypeTracker* tracker,
     scoped_refptr<gpu::SharedContextState> context_state) {
-  // TODO(vikassoni): Implement in follow up patch.
-  NOTIMPLEMENTED();
-  return nullptr;
+  DCHECK(context_state);
+
+  // Right now we only support GL mode.
+  // TODO(vikassoni): Land follow up patches to enable vulkan mode.
+  if (!context_state->GrContextIsGL()) {
+    DLOG(ERROR) << "SharedImage video path not yet supported in Vulkan.";
+    return nullptr;
+  }
+
+  // For (old) overlays, we don't have a texture owner, but overlay promotion
+  // might not happen for some reasons. In that case, it will try to draw
+  // which should result in no image.
+  if (!codec_image_->texture_owner())
+    return nullptr;
+
+  // In GL mode, use the texture id of the TextureOwner.
+  return std::make_unique<SharedImageRepresentationVideoSkiaGL>(manager, this,
+                                                                tracker);
 }
 
 }  // namespace media
diff --git a/media/gpu/android/shared_image_video.h b/media/gpu/android/shared_image_video.h
index 0cd0875d..a90ec9a 100644
--- a/media/gpu/android/shared_image_video.h
+++ b/media/gpu/android/shared_image_video.h
@@ -68,6 +68,7 @@
 
  private:
   friend class SharedImageRepresentationGLTextureVideo;
+  friend class SharedImageRepresentationVideoSkiaGL;
 
   scoped_refptr<CodecImage> codec_image_;
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index e9506b1..11169e9 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1152,7 +1152,6 @@
       "spdy/platform/impl/spdy_string_utils_impl.cc",
       "spdy/platform/impl/spdy_string_utils_impl.h",
       "spdy/platform/impl/spdy_test_utils_prod_impl.h",
-      "spdy/platform/impl/spdy_unsafe_arena_impl.cc",
       "spdy/platform/impl/spdy_unsafe_arena_impl.h",
       "spdy/server_push_delegate.h",
       "spdy/spdy_buffer.cc",
@@ -1704,6 +1703,8 @@
       "third_party/quiche/src/spdy/core/spdy_prefixed_buffer_reader.h",
       "third_party/quiche/src/spdy/core/spdy_protocol.cc",
       "third_party/quiche/src/spdy/core/spdy_protocol.h",
+      "third_party/quiche/src/spdy/core/spdy_simple_arena.cc",
+      "third_party/quiche/src/spdy/core/spdy_simple_arena.h",
       "third_party/quiche/src/spdy/core/write_scheduler.h",
       "third_party/quiche/src/spdy/core/zero_copy_output_buffer.h",
       "third_party/quiche/src/spdy/platform/api/spdy_arraysize.h",
@@ -5415,6 +5416,7 @@
     "third_party/quiche/src/spdy/core/spdy_protocol_test.cc",
     "third_party/quiche/src/spdy/core/spdy_protocol_test_utils.cc",
     "third_party/quiche/src/spdy/core/spdy_protocol_test_utils.h",
+    "third_party/quiche/src/spdy/core/spdy_simple_arena_test.cc",
     "third_party/quiche/src/spdy/core/spdy_test_utils.cc",
     "third_party/quiche/src/spdy/core/spdy_test_utils.h",
     "third_party/quiche/src/spdy/platform/api/spdy_mem_slice_test.cc",
diff --git a/net/base/network_interfaces_unittest.cc b/net/base/network_interfaces_unittest.cc
index 843de293..b5c5a19 100644
--- a/net/base/network_interfaces_unittest.cc
+++ b/net/base/network_interfaces_unittest.cc
@@ -18,6 +18,8 @@
 #elif defined(OS_WIN)
 #include <iphlpapi.h>
 #include <objbase.h>
+#include "base/strings/string_util.h"
+#include "base/win/win_util.h"
 #endif
 
 namespace net {
@@ -48,10 +50,8 @@
     GUID guid;
     EXPECT_EQ(static_cast<DWORD>(NO_ERROR),
               ConvertInterfaceLuidToGuid(&luid, &guid));
-    LPOLESTR name;
-    StringFromCLSID(guid, &name);
-    EXPECT_STREQ(base::UTF8ToWide(it->name).c_str(), name);
-    CoTaskMemFree(name);
+    auto name = base::win::String16FromGUID(guid);
+    EXPECT_EQ(base::as_u16cstr(base::UTF8ToWide(it->name)), name);
 
     if (it->type == NetworkChangeNotifier::CONNECTION_WIFI) {
       EXPECT_NE(WIFI_PHY_LAYER_PROTOCOL_NONE, GetWifiPHYLayerProtocol());
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 09e7ad8..3062d6f9 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -20056,118 +20056,6 @@
   session->CloseAllConnections();
 }
 
-// Test the proxy requesting HTTP auth and the server requesting TLS client
-// certificates. This is a regression test for https://crbug.com/946406.
-TEST_F(HttpNetworkTransactionTest, ProxyHTTPAndServerTLSAuth) {
-  // Note these hosts must match the CheckBasic*Auth() functions.
-  session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixed(
-      "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
-
-  auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>();
-  cert_request_info_origin->host_and_port =
-      HostPortPair("www.example.org", 443);
-
-  std::unique_ptr<FakeClientCertIdentity> identity_origin =
-      FakeClientCertIdentity::CreateFromCertAndKeyFiles(
-          GetTestCertsDirectory(), "client_2.pem", "client_2.pk8");
-  ASSERT_TRUE(identity_origin);
-
-  HttpRequestInfo request;
-  request.method = "GET";
-  request.url = GURL("https://www.example.org/");
-  request.traffic_annotation =
-      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
-
-  // We connect to the proxy. The handshake succeeds.
-  SSLSocketDataProvider ssl_proxy1(ASYNC, OK);
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
-  // We attempt a connect. The proxy requests basic auth.
-  std::vector<MockWrite> mock_writes1;
-  std::vector<MockRead> mock_reads1;
-  mock_writes1.emplace_back(
-      "CONNECT www.example.org:443 HTTP/1.1\r\n"
-      "Host: www.example.org:443\r\n"
-      "Proxy-Connection: keep-alive\r\n\r\n");
-  mock_reads1.emplace_back(
-      "HTTP/1.1 407 Proxy Authentication Required\r\n"
-      "Content-Length: 0\r\n"
-      "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
-  // We respond.
-  mock_writes1.emplace_back(
-      "CONNECT www.example.org:443 HTTP/1.1\r\n"
-      "Host: www.example.org:443\r\n"
-      "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
-      "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
-  mock_reads1.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
-  // The origin requests client certificates.
-  SSLSocketDataProvider ssl_origin1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
-  ssl_origin1.cert_request_info = cert_request_info_origin.get();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin1);
-  StaticSocketDataProvider data2(mock_reads1, mock_writes1);
-  session_deps_.socket_factory->AddSocketDataProvider(&data2);
-
-  // We respond to the origin client certificate request on a new connection.
-  SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
-  std::vector<MockWrite> mock_writes2;
-  std::vector<MockRead> mock_reads2;
-  mock_writes2.emplace_back(
-      "CONNECT www.example.org:443 HTTP/1.1\r\n"
-      "Host: www.example.org:443\r\n"
-      "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
-      "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
-  mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
-  SSLSocketDataProvider ssl_origin2(ASYNC, OK);
-  ssl_origin2.expected_send_client_cert = true;
-  ssl_origin2.expected_client_cert = identity_origin->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2);
-  // We send the origin HTTP request, which succeeds.
-  mock_writes2.emplace_back(
-      "GET / HTTP/1.1\r\n"
-      "Host: www.example.org\r\n"
-      "Connection: keep-alive\r\n\r\n");
-  mock_reads2.emplace_back(
-      "HTTP/1.1 200 OK\r\n"
-      "Content-Length: 0\r\n\r\n");
-  StaticSocketDataProvider data3(mock_reads2, mock_writes2);
-  session_deps_.socket_factory->AddSocketDataProvider(&data3);
-
-  std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
-
-  // Start the request.
-  TestCompletionCallback callback;
-  auto trans =
-      std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
-  int rv = callback.GetResult(
-      trans->Start(&request, callback.callback(), NetLogWithSource()));
-
-  // Handle the proxy HTTP auth challenge.
-  ASSERT_THAT(rv, IsOk());
-  EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code());
-  EXPECT_TRUE(
-      CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge));
-  rv = callback.GetResult(trans->RestartWithAuth(
-      AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")),
-      callback.callback()));
-
-  // Handle the origin client certificate challenge.
-  ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
-  SSLCertRequestInfo* cert_request_info =
-      trans->GetResponseInfo()->cert_request_info.get();
-  ASSERT_TRUE(cert_request_info);
-  EXPECT_FALSE(cert_request_info->is_proxy);
-  EXPECT_EQ(cert_request_info->host_and_port,
-            cert_request_info_origin->host_and_port);
-  rv = callback.GetResult(trans->RestartWithCertificate(
-      identity_origin->certificate(), identity_origin->ssl_private_key(),
-      callback.callback()));
-
-  // The request completes.
-  ASSERT_THAT(rv, IsOk());
-}
-
 // Test the proxy and origin server each requesting both TLS client certificates
 // and HTTP auth. This is a regression test for https://crbug.com/946406.
 TEST_F(HttpNetworkTransactionTest, AuthEverything) {
@@ -20198,20 +20086,21 @@
   request.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
 
-  // First, we connect and the proxy requests client certificates.
+  // First, the client connects to the proxy, which requests a client
+  // certificate.
   SSLSocketDataProvider ssl_proxy1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
   ssl_proxy1.cert_request_info = cert_request_info_proxy.get();
   ssl_proxy1.expected_send_client_cert = false;
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
   StaticSocketDataProvider data1;
   session_deps_.socket_factory->AddSocketDataProvider(&data1);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
 
-  // We respond with a certificate on a new connection. The handshake succeeds.
+  // The client responds with a certificate on a new connection. The handshake
+  // succeeds.
   SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
   ssl_proxy2.expected_send_client_cert = true;
   ssl_proxy2.expected_client_cert = identity_proxy->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
-  // We attempt a connect. The proxy requests basic auth.
+  // The client attempts an HTTP CONNECT, but the proxy requests basic auth.
   std::vector<MockWrite> mock_writes2;
   std::vector<MockRead> mock_reads2;
   mock_writes2.emplace_back(
@@ -20222,41 +20111,41 @@
       "HTTP/1.1 407 Proxy Authentication Required\r\n"
       "Content-Length: 0\r\n"
       "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
-  // We respond.
+  // The client retries with credentials.
   mock_writes2.emplace_back(
       "CONNECT www.example.org:443 HTTP/1.1\r\n"
       "Host: www.example.org:443\r\n"
       "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
+      // Authenticate as proxyuser:proxypass.
       "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
   mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
   // The origin requests client certificates.
   SSLSocketDataProvider ssl_origin2(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
   ssl_origin2.cert_request_info = cert_request_info_origin.get();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2);
   StaticSocketDataProvider data2(mock_reads2, mock_writes2);
   session_deps_.socket_factory->AddSocketDataProvider(&data2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2);
 
-  // We respond to the origin client certificate request on a new connection.
+  // The client responds to the origin client certificate request on a new
+  // connection.
   SSLSocketDataProvider ssl_proxy3(ASYNC, OK);
   ssl_proxy3.expected_send_client_cert = true;
   ssl_proxy3.expected_client_cert = identity_proxy->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3);
   std::vector<MockWrite> mock_writes3;
   std::vector<MockRead> mock_reads3;
   mock_writes3.emplace_back(
       "CONNECT www.example.org:443 HTTP/1.1\r\n"
       "Host: www.example.org:443\r\n"
       "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
+      // Authenticate as proxyuser:proxypass.
       "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
   mock_reads3.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
   SSLSocketDataProvider ssl_origin3(ASYNC, OK);
   ssl_origin3.expected_send_client_cert = true;
   ssl_origin3.expected_client_cert = identity_origin->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3);
-  // We send the origin HTTP request, which results in another HTTP auth
-  // request.
+  // The client sends the origin HTTP request, which results in another HTTP
+  // auth request.
   mock_writes3.emplace_back(
       "GET / HTTP/1.1\r\n"
       "Host: www.example.org\r\n"
@@ -20265,18 +20154,20 @@
       "HTTP/1.1 401 Unauthorized\r\n"
       "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
       "Content-Length: 0\r\n\r\n");
-  // We respond, and the request finally succeeds.
+  // The client retries with credentials, and the request finally succeeds.
   mock_writes3.emplace_back(
       "GET / HTTP/1.1\r\n"
       "Host: www.example.org\r\n"
       "Connection: keep-alive\r\n"
-      // user:pass
+      // Authenticate as user:pass.
       "Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
   mock_reads3.emplace_back(
       "HTTP/1.1 200 OK\r\n"
       "Content-Length: 0\r\n\r\n");
   StaticSocketDataProvider data3(mock_reads3, mock_writes3);
   session_deps_.socket_factory->AddSocketDataProvider(&data3);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3);
 
   std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
@@ -20330,6 +20221,7 @@
 
   // The request completes.
   ASSERT_THAT(rv, IsOk());
+  EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
 }
 
 // Test the proxy and origin server each requesting both TLS client certificates
@@ -20363,21 +20255,21 @@
   request.traffic_annotation =
       net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
 
-  // First, we connect and the proxy requests client certificates.
+  // First, the client connects to the proxy, which requests a client
+  // certificate.
   SSLSocketDataProvider ssl_proxy1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
   ssl_proxy1.cert_request_info = cert_request_info_proxy.get();
   ssl_proxy1.expected_send_client_cert = false;
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
   StaticSocketDataProvider data1;
   session_deps_.socket_factory->AddSocketDataProvider(&data1);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
 
-  // We respond with a certificate on a new connection. The handshake succeeds.
+  // The client responds with a certificate on a new connection. The handshake
+  // succeeds.
   SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
   ssl_proxy2.expected_send_client_cert = true;
   ssl_proxy2.expected_client_cert = identity_proxy->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
-  // We attempt a connnect. The proxy requests basic auth and closes the
-  // connection.
+  // The client attempts an HTTP CONNECT, but the proxy requests basic auth.
   std::vector<MockWrite> mock_writes2;
   std::vector<MockRead> mock_reads2;
   mock_writes2.emplace_back(
@@ -20391,48 +20283,48 @@
       "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
   StaticSocketDataProvider data2(mock_reads2, mock_writes2);
   session_deps_.socket_factory->AddSocketDataProvider(&data2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
 
-  // We respond on a new connection.
+  // The client retries with credentials on a new connection.
   SSLSocketDataProvider ssl_proxy3(ASYNC, OK);
   ssl_proxy3.expected_send_client_cert = true;
   ssl_proxy3.expected_client_cert = identity_proxy->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3);
   std::vector<MockWrite> mock_writes3;
   std::vector<MockRead> mock_reads3;
   mock_writes3.emplace_back(
       "CONNECT www.example.org:443 HTTP/1.1\r\n"
       "Host: www.example.org:443\r\n"
       "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
+      // Authenticate as proxyuser:proxypass.
       "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
   mock_reads3.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
   // The origin requests client certificates.
   SSLSocketDataProvider ssl_origin3(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
   ssl_origin3.cert_request_info = cert_request_info_origin.get();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3);
   StaticSocketDataProvider data3(mock_reads3, mock_writes3);
   session_deps_.socket_factory->AddSocketDataProvider(&data3);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3);
 
-  // We respond to the origin client certificate request on a new connection.
+  // The client responds to the origin client certificate request on a new
+  // connection.
   SSLSocketDataProvider ssl_proxy4(ASYNC, OK);
   ssl_proxy4.expected_send_client_cert = true;
   ssl_proxy4.expected_client_cert = identity_proxy->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy4);
   std::vector<MockWrite> mock_writes4;
   std::vector<MockRead> mock_reads4;
   mock_writes4.emplace_back(
       "CONNECT www.example.org:443 HTTP/1.1\r\n"
       "Host: www.example.org:443\r\n"
       "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
+      // Authenticate as proxyuser:proxypass.
       "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
   mock_reads4.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
   SSLSocketDataProvider ssl_origin4(ASYNC, OK);
   ssl_origin4.expected_send_client_cert = true;
   ssl_origin4.expected_client_cert = identity_origin->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin4);
-  // We send the origin HTTP request, which results in another HTTP auth
-  // request and closed connection.
+  // The client sends the origin HTTP request, which results in another HTTP
+  // auth request and closed connection.
   mock_writes4.emplace_back(
       "GET / HTTP/1.1\r\n"
       "Host: www.example.org\r\n"
@@ -20444,30 +20336,31 @@
       "Content-Length: 0\r\n\r\n");
   StaticSocketDataProvider data4(mock_reads4, mock_writes4);
   session_deps_.socket_factory->AddSocketDataProvider(&data4);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy4);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin4);
 
-  // We respond on a new connection, and the request finally succeeds.
+  // The client retries with credentials on a new connection, and the request
+  // finally succeeds.
   SSLSocketDataProvider ssl_proxy5(ASYNC, OK);
   ssl_proxy5.expected_send_client_cert = true;
   ssl_proxy5.expected_client_cert = identity_proxy->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy5);
   std::vector<MockWrite> mock_writes5;
   std::vector<MockRead> mock_reads5;
   mock_writes5.emplace_back(
       "CONNECT www.example.org:443 HTTP/1.1\r\n"
       "Host: www.example.org:443\r\n"
       "Proxy-Connection: keep-alive\r\n"
-      // proxyuser:proxypass
+      // Authenticate as proxyuser:proxypass.
       "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
   mock_reads5.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
   SSLSocketDataProvider ssl_origin5(ASYNC, OK);
   ssl_origin5.expected_send_client_cert = true;
   ssl_origin5.expected_client_cert = identity_origin->certificate();
-  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin5);
   mock_writes5.emplace_back(
       "GET / HTTP/1.1\r\n"
       "Host: www.example.org\r\n"
       "Connection: keep-alive\r\n"
-      // user:pass
+      // Authenticate as user:pass.
       "Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
   mock_reads5.emplace_back(
       "HTTP/1.1 200 OK\r\n"
@@ -20475,6 +20368,8 @@
       "Content-Length: 0\r\n\r\n");
   StaticSocketDataProvider data5(mock_reads5, mock_writes5);
   session_deps_.socket_factory->AddSocketDataProvider(&data5);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy5);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin5);
 
   std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
 
@@ -20528,6 +20423,121 @@
 
   // The request completes.
   ASSERT_THAT(rv, IsOk());
+  EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
+}
+
+// Test the proxy requesting HTTP auth and the server requesting TLS client
+// certificates. This is a regression test for https://crbug.com/946406.
+TEST_F(HttpNetworkTransactionTest, ProxyHTTPAndServerTLSAuth) {
+  // Note these hosts must match the CheckBasic*Auth() functions.
+  session_deps_.proxy_resolution_service = ProxyResolutionService::CreateFixed(
+      "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
+
+  auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>();
+  cert_request_info_origin->host_and_port =
+      HostPortPair("www.example.org", 443);
+
+  std::unique_ptr<FakeClientCertIdentity> identity_origin =
+      FakeClientCertIdentity::CreateFromCertAndKeyFiles(
+          GetTestCertsDirectory(), "client_2.pem", "client_2.pk8");
+  ASSERT_TRUE(identity_origin);
+
+  HttpRequestInfo request;
+  request.method = "GET";
+  request.url = GURL("https://www.example.org/");
+  request.traffic_annotation =
+      net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
+
+  // The client connects to the proxy. The handshake succeeds.
+  SSLSocketDataProvider ssl_proxy1(ASYNC, OK);
+  // The client attempts an HTTP CONNECT, but the proxy requests basic auth.
+  std::vector<MockWrite> mock_writes1;
+  std::vector<MockRead> mock_reads1;
+  mock_writes1.emplace_back(
+      "CONNECT www.example.org:443 HTTP/1.1\r\n"
+      "Host: www.example.org:443\r\n"
+      "Proxy-Connection: keep-alive\r\n\r\n");
+  mock_reads1.emplace_back(
+      "HTTP/1.1 407 Proxy Authentication Required\r\n"
+      "Content-Length: 0\r\n"
+      "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
+  // The client retries with credentials, and the request finally succeeds.
+  mock_writes1.emplace_back(
+      "CONNECT www.example.org:443 HTTP/1.1\r\n"
+      "Host: www.example.org:443\r\n"
+      "Proxy-Connection: keep-alive\r\n"
+      // Authenticate as proxyuser:proxypass.
+      "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
+  mock_reads1.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
+  // The origin requests client certificates.
+  SSLSocketDataProvider ssl_origin1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+  ssl_origin1.cert_request_info = cert_request_info_origin.get();
+  StaticSocketDataProvider data1(mock_reads1, mock_writes1);
+  session_deps_.socket_factory->AddSocketDataProvider(&data1);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin1);
+
+  // The client responds to the origin client certificate request on a new
+  // connection.
+  SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
+  std::vector<MockWrite> mock_writes2;
+  std::vector<MockRead> mock_reads2;
+  mock_writes2.emplace_back(
+      "CONNECT www.example.org:443 HTTP/1.1\r\n"
+      "Host: www.example.org:443\r\n"
+      "Proxy-Connection: keep-alive\r\n"
+      // Authenticate as proxyuser:proxypass.
+      "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
+  mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
+  SSLSocketDataProvider ssl_origin2(ASYNC, OK);
+  ssl_origin2.expected_send_client_cert = true;
+  ssl_origin2.expected_client_cert = identity_origin->certificate();
+  // The client sends the origin HTTP request, which succeeds.
+  mock_writes2.emplace_back(
+      "GET / HTTP/1.1\r\n"
+      "Host: www.example.org\r\n"
+      "Connection: keep-alive\r\n\r\n");
+  mock_reads2.emplace_back(
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 0\r\n\r\n");
+  StaticSocketDataProvider data2(mock_reads2, mock_writes2);
+  session_deps_.socket_factory->AddSocketDataProvider(&data2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
+  session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2);
+
+  std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
+
+  // Start the request.
+  TestCompletionCallback callback;
+  auto trans =
+      std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
+  int rv = callback.GetResult(
+      trans->Start(&request, callback.callback(), NetLogWithSource()));
+
+  // Handle the proxy HTTP auth challenge.
+  ASSERT_THAT(rv, IsOk());
+  EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code());
+  EXPECT_TRUE(
+      CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge));
+  rv = callback.GetResult(trans->RestartWithAuth(
+      AuthCredentials(ASCIIToUTF16("proxyuser"), ASCIIToUTF16("proxypass")),
+      callback.callback()));
+
+  // Handle the origin client certificate challenge.
+  ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
+  SSLCertRequestInfo* cert_request_info =
+      trans->GetResponseInfo()->cert_request_info.get();
+  ASSERT_TRUE(cert_request_info);
+  EXPECT_FALSE(cert_request_info->is_proxy);
+  EXPECT_EQ(cert_request_info->host_and_port,
+            cert_request_info_origin->host_and_port);
+  rv = callback.GetResult(trans->RestartWithCertificate(
+      identity_origin->certificate(), identity_origin->ssl_private_key(),
+      callback.callback()));
+
+  // The request completes.
+  ASSERT_THAT(rv, IsOk());
+  EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
 }
 
 }  // namespace net
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 5efff24..5713762 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -1457,7 +1457,6 @@
     { "name": "cimballa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "daylightcompany.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "denh.am", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "devh.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "evstatus.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "filedir.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gplintegratedit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -2037,7 +2036,6 @@
     { "name": "9point6.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "andere-gedanken.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "andymartin.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "aroonchande.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "atc.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "auto4trade.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bagelsbakery.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -2783,7 +2781,6 @@
     { "name": "payments-reference.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pbprint.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "poedgirl.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "poiema.com.sg", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "posttigo.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "presidentials2016.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "projectascension.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -4117,7 +4114,6 @@
     { "name": "alexwardweb.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "atolm.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "avastantivirus.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "beeksnetwork.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "berst.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bigbluedoor.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "binaryevolved.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -4658,7 +4654,6 @@
     { "name": "count.sh", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "culinae.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cvjm-memmingen.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "david-schiffmann.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "decafu.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dergeilstestammderwelt.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dibiphp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -5389,7 +5384,6 @@
     { "name": "heartsucker.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "hmm.nyc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "homecareassociatespa.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "i95.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "iamokay.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "infilock.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "iseulde.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -5449,7 +5443,6 @@
     { "name": "saikarra.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "sailormoonevents.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "saltstack.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "samkelleher.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "seatbeltpledge.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "shv25.se", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "stmbgr.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -5616,7 +5609,6 @@
     { "name": "baiker.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ballotapi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bananium.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "barbaros.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "barbu.family", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "barrut.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bartel.ws", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -5807,7 +5799,6 @@
     { "name": "eatlowcarb.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "eb7.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "echopaper.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "echosystem.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ecogen.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ecogen.net.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "eduif.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -6260,7 +6251,6 @@
     { "name": "pittonpreschool.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pixelbash.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "playmaker.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "po.gl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pocloud.homelinux.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "polynomapp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "povitria.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -7150,7 +7140,6 @@
     { "name": "vmem.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vogt.tech", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vonedelmann.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "vvl.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "wangqiliang.xn--fiqs8s", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "warekon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "waterfedpole.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -8023,7 +8012,6 @@
     { "name": "arbitrarion.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "auth.adult", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "baby-click.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "barqo.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bayden.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bckp.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bespokestraps.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -9674,7 +9662,6 @@
     { "name": "nixien.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nl-ix.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nmsnj.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "nnqc.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "no17sifangjie.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nodespin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "noedidacticos.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -11312,7 +11299,6 @@
     { "name": "ons.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "onearth.one", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "onarto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "newline.online", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "openbsd.id", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ogogoshop.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "oneminutefilm.tv", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -12769,7 +12755,6 @@
     { "name": "counterglobal.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "couragefound.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "courses.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "cousincouples.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cprnearme.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "craigrouse.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "crazy-crawler.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -13941,7 +13926,6 @@
     { "name": "tributh.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tripcombi.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "trueinstincts.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "trustcase.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tsuyuzakihiroyuki.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tts.co.nz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ttt.tt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -14522,7 +14506,6 @@
     { "name": "christians.dating", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "droncentrum.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dyktig.as", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "drschruefer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dopesoft.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dune.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "emilvarga.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -18876,7 +18859,6 @@
     { "name": "respon.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rencaijia.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ridwan.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "reinouthoornweg.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rca.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rehabthailand.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "rtejr.ie", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -20379,7 +20361,6 @@
     { "name": "gay-sissies.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ftpi.ml", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gaysfisting.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "fantasyfootballpundit.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gandgliquors.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gayxsite.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "frp-roleplay.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -21300,7 +21281,6 @@
     { "name": "pharmaboard.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "piercraft.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "popkins.tk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "pixelpoint.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pmac.pt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "plzh4x.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "platomania.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -23737,7 +23717,6 @@
     { "name": "britishmeat.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "brodowski.cc", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "brompton-cocktail.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "brookehatton.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "brouillard.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bruna-cdn.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bs-network.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -24266,7 +24245,6 @@
     { "name": "eletesstilus.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "elite-box.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "elitecovering.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "ellen-skye.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "eltair.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "eltransportquevolem.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "elytronsecurity.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -26796,7 +26774,6 @@
     { "name": "vider.ga", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "viekelis.lt", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "viemontante.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "vierpfeile.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vierpluseins.wtf", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vieux.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "vigenebio.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -27421,7 +27398,6 @@
     { "name": "benburwell.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "benfairclough.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aurora-multimedia.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "bambambaby.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "balidesignshop.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "around-the-blog.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bariseau-mottrie.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29645,7 +29621,6 @@
     { "name": "properticons.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "projectunity.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "phcimages.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "prinesdoma.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pornohub.su", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ploofer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pmconference.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -30336,7 +30311,6 @@
     { "name": "themacoaching.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tkjg.fi", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "startup.melbourne", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "tomica.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tjp.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tobischo.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "trangcongnghe.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -31271,7 +31245,6 @@
     { "name": "deped.blog", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "dataformers.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "derrickemery.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "czirnich.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "criadorespet.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cvl.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "decalquai.ch", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -37791,7 +37764,6 @@
     { "name": "partytownmarquees.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "partyzone.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pascal-bourhis.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "patbatesremodeling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pathagoras.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "paulpetersen.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pavelkahouseforcisco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -40531,7 +40503,6 @@
     { "name": "casino-trio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "caspar.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cayounglab.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cdbtech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cdsdigital.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "centralebigmat.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cerberusinformatica.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -42500,7 +42471,6 @@
     { "name": "joefixit.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "johansf.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jollygoodspudz.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "jonathanha.as", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jondowdle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jrabasco.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "jsbevents.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -43628,7 +43598,6 @@
     { "name": "skizzen-zeichnungen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sksdrivingschool.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "skybloom.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "snrat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sobersys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "songsmp3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "songsmp3.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44382,7 +44351,6 @@
     { "name": "rucksack-rauf-und-weg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rusmolotok.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ryancarter.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "safeui.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "salexy.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "salvagedfurnitureparlour.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sanipousse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -45760,7 +45728,6 @@
     { "name": "mes-bouquins.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "metanodo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mijnetz.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "millennium-thisiswhoweare.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "moc.ac", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "modalrakyat.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "molokai.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47436,7 +47403,6 @@
     { "name": "bigshort.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bijouxcherie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "binarization.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "blockchainced.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bluerootsmarketing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bluestardiabetes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bokka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47504,8 +47470,6 @@
     { "name": "cougarsland.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cr0nus.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crawlspaceandbasementsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cryptoegg.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cryptofrog.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cryptopro.shop", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "crystalgrid.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cultureelbeleggen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -47759,8 +47723,6 @@
     { "name": "lcy.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lcybox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "legalisepeacebloom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lemonthy.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lemonthy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lenaneva.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "letsdebug.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "leumi-how-to.co.il", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51562,7 +51524,6 @@
     { "name": "mudgezero.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "multitenantlaravel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "multiterm.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "mushfiqweb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "musicaconleali.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mybonfire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "myeisenbahn.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51931,7 +51892,6 @@
     { "name": "12photos.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "20zq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "319k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "3ank.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "5518k3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "5986fc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "64970.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -52367,7 +52327,6 @@
     { "name": "arpamip.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "arpnet.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "arrazane.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "artisan-cheminees-poeles-design.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aseko.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ashleyedisonuk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "asian-archi.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -52962,7 +52921,6 @@
     { "name": "manski.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mapstack.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marcbeije.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "marcberndtgen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marchwj.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marguerite-maison.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marin-dom.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54010,7 +53968,6 @@
     { "name": "proadvanced.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prodottogiusto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "progressnet.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "projectborealisgitlab.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "promoteiq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prontointerventoimmediato.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "prosharp.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -54065,7 +54022,6 @@
     { "name": "seby.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sec4share.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "securityheaders.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "semantica.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sendaiouji.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "serendeputy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "serwusik.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56635,7 +56591,6 @@
     { "name": "2chan.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "2chan.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "4x4tt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "65d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aaex.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "adnanoktar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "advancedsurgicalconsultantsllc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56721,9 +56676,6 @@
     { "name": "creditta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cstrong.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cxadd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88871.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88988.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "darklaunch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "davypropper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dedicatedtowomenobgyn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56884,9 +56836,6 @@
     { "name": "loanreadycredit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "locomocosec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long139.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long18.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "longtermcare.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loteamentomontereiitu.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lovemanagementaccounts.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -57094,7 +57043,6 @@
     { "name": "virtualspeech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vlakem.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vos-systems.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "vseomedia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vtuber.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webutils.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "weems.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -57122,7 +57070,6 @@
     { "name": "yxs.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zeibekiko-souvlaki.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zirka24.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8862.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zunda.cafe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zxc.science", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1895media.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -57381,7 +57328,6 @@
     { "name": "liljohnsanitary.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lilylasvegas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lintellift.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "liyunbin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lolic.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lolico.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lrdo.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -58822,7 +58768,6 @@
     { "name": "ae-dir.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ae-dir.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aedollon.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "afcmrs.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "affittisalento.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "afscheidsportret.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ahegao.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -60306,7 +60251,6 @@
     { "name": "versalhost.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "verses.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vet-planet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "vetergysurveys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vhs-bad-wurzach.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "via.blog.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "viablog.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -61199,7 +61143,6 @@
     { "name": "jpbe-network.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "justin-tech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kabos.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kalyanmatka.guru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kamata-shinkyu-seikotsu.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kameari-za.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kamilki.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -61879,7 +61822,6 @@
     { "name": "britanniacateringyeovil.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bryantzheng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btshe.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "builditfl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bukiskola.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bukivallalkozasok.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bukpcszerviz.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64009,7 +63951,6 @@
     { "name": "malibumodas.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mantuo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "manwish.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "maorx.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "markhoodwrites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marron-dietrecipe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "masterpassword.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64084,7 +64025,6 @@
     { "name": "ptasiepodroze.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "qklshequ.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "qxzgssr.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rbuddenhagen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "reby.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "redmangallpsychologists.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "revivalsstores.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64232,7 +64172,6 @@
     { "name": "3d1t0r4.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3xm.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "42l.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "4o5.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "4x4-27mc.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "4x4coatingen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "7milesglobal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64493,7 +64432,6 @@
     { "name": "sandrabernardo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "scalpel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "schoenstatt-fathers.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sestolab.pp.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sharecrypted.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shelike.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shellcode.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -64808,7 +64746,6 @@
     { "name": "khorne.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kidsdaysout.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kordamed.ee", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kpopsource.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks626.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "la-laitonnerie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lawlessenglish.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65819,7 +65756,6 @@
     { "name": "theclinician.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "theobora.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "theologyz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "thomas717.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "thomascauquil.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "totalclean.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "toxoproject.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -66030,7 +65966,6 @@
     { "name": "hikawa.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hillier-swift.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hitrost.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hoctracnghiem.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "honglitrading.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hybrydowe-samochody.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hypnovir.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -66610,9 +66545,7 @@
     { "name": "zhanglu.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "07stars.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "089818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "131ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "162231.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "186kb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "2468lhc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "258877.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "267661.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -66809,8 +66742,6 @@
     { "name": "kaizenjuku.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kamilmagdziak.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "katsunet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kb786.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kb88dc28.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "keypointfrancine.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kimkuhlmanphoto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kizzedbykelz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -66831,7 +66762,6 @@
     { "name": "lorenz-hundler.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loto-tele.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "makefoodrecipes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "manipurmatka.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "manuall.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "manuall.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "manuall.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67427,7 +67357,6 @@
     { "name": "vractive.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "warung.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webhoffmann.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wei.bz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "what.tf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "whiskey.town", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "windowsdoors.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67452,18 +67381,8 @@
     { "name": "zonky.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zontractors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zy.si", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "0017d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "0018d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "005555.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "00d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "013zl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "015zl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "020ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "022ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "025ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "029ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "02am8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "03d88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "060579.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0chan.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0x00c.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67472,13 +67391,9 @@
     { "name": "123derivatives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "145ks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "147ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "151ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "1520322.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "162223.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "17kpw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "182ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "182wh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "187kb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "192080.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1chan.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "204504byse.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67496,15 +67411,12 @@
     { "name": "3361p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "357601.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "361116.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "365d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "365electricalvn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "371687.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3838onndo.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "42.tools", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "455327.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "4smart.house", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "518d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "531k8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "54lsj.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "595380.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "5conejos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67514,7 +67426,6 @@
     { "name": "657990.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "666am8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "668am8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "66d88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "671660.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "671990.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "672990.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67538,75 +67449,19 @@
     { "name": "762116.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "7777k8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "780aa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8002d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8007d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8017d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8019d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8020d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8021d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8026d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8028d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8029d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8032d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8033d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8035d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8036d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8037d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "80780780.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8078d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8081d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8092d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8100d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8105d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8130d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8162d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8190d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8207d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "82kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "83kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "85kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "86kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "87kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8815d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8816d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8816d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8826d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8829d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8850d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8860d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8860d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "8862ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8866d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "886k8.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "8880ks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "8925d88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "89kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "8pc.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "911216.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "9181181.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "9182289.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "91d00.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "91d01.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "91d02.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "91d30.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "91d31.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "91d33.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "92kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "93kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "95kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "96kb88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "99lib.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k266.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k282.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k286.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k635.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k637.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k639.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k675.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k677.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k679.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k695.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "9k697.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "a122.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "a22z.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "abdulrahman.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67797,7 +67652,6 @@
     { "name": "cerrajeriaenvillavicencio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cevin.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cgeceia.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "cgelves.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chengfayun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chernevclima.bg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chicback.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67845,17 +67699,7 @@
     { "name": "customcontract.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cwwise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cybermotives.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d166.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d8181.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88118.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d8812.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d8816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "d8853.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88869.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88agqj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88d99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "d88md04.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dagmarhamalova.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dahliacake.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dakin.nyc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67867,11 +67711,7 @@
     { "name": "datacool.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "datelligent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dcdestetica.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dd11d.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dd207d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dd211d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dd215d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dd44d.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "death.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "decor-prazdnik.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "defantasia.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -67892,7 +67732,6 @@
     { "name": "derw.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "designerchad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "destyntek.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "devafexcur-dntg.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "devdeb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dexonservicedeskws.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "diabetessucks.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68081,7 +67920,6 @@
     { "name": "hjyl6999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hjyl7999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "homoo.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "hr-automation.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hr28.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hsn-tsn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "htcp99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68153,11 +67991,7 @@
     { "name": "k8013.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "k807.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "k8084.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "k819.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "k821.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "k8668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "k88201.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "k88214.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kaloni.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kartbird.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "karuna.community", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68166,8 +68000,6 @@
     { "name": "kb09.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb4141.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb4343.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kb866.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kb8803.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb8823.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb883.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb88666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68178,12 +68010,8 @@
     { "name": "kexino.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "keymicrosystems.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "keynes.id.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kf117.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kf2525.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kf2828.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kf5252.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kf8484g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kf8825.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "khetmaal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kievkiralikotel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kimitang.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68200,10 +68028,8 @@
     { "name": "koof.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "koreaninhd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "korem011-tniad.mil.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kornmesser-goldankauf.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "krikorianconstruction.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks0299.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ks0404.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks0618.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks0718.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks0768.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68217,7 +68043,6 @@
     { "name": "ks1909.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks2022.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks2055.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ks206.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks2500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks2600.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks2608.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68230,9 +68055,6 @@
     { "name": "ks6767.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks88.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ks8832.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ks8887.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ks920.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ks958.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ksoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kumbayops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kumpulannamabayi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68272,81 +68094,6 @@
     { "name": "logo-vogtland.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lohmeyer.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lolas-vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0310.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0311.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0316.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0317.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0318.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0319.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0355.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0356.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0376.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0377.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0378.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0396.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0398.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0536.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0538.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0539.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0556.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0557.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0559.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0596.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0598.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0599.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0728.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0730.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0732.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0733.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0735.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0736.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0737.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0738.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0739.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0755.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0756.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0768.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0770.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0776.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0778.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0779.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0798.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0799.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long08.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0812.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0833.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0855.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0856.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0876.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0877.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0878.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0887.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0896.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0897.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0898.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0906.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0908.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0976.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0977.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0990.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0991.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0992.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0993.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0995.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0996.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0997.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0998.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long0999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long139.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long288.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long566.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "long8039.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loonylatke.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lottoland.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lou.ist", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68492,7 +68239,6 @@
     { "name": "paneldoorsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "parentsandzebrasunited.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "partage-noir.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pdm.ac.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "peoplescu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pgp.lol", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "phildonaldson.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68722,7 +68468,6 @@
     { "name": "sospeed.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "soundclick.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sounds-familiar.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "soyocloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "soyvigilante.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "spaziofamiglie.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "splash.solar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68736,7 +68481,6 @@
     { "name": "stadsbos013.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "star-one.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "startloop.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "staticaly.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stb-lemke.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stehlik.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "stephycom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68962,7 +68706,6 @@
     { "name": "xb853.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xbjt66.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xbyl.xn--fiqs8s", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xda.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xinsto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--die-hrercharts-zpb.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xn--t8jo9k1b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68970,7 +68713,6 @@
     { "name": "yamei1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yamei8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yamei88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "yan68d88vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yao28.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yesogovinpetcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ym039.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68983,23 +68725,7 @@
     { "name": "yourcleaningcompany.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yoyoost.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "z8022.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "z8029.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zbib.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd0808.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd2727.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd3434.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd6161.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd6464.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd7575.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd7676.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8828.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8829.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8836.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8838.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8839.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8878.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd8898.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zd9090.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zenidees.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zhaostephen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zhattyt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69007,40 +68733,6 @@
     { "name": "zjbuilding.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zl0101.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zl0303.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl056.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl0707.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl071.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl0909.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl0sz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl1010.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl1616.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl2020.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl2727.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl2929.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl3737.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl4231.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl4290.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl5050.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl5151.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl5656.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl6464.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl6565.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl6969.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl7070.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl7171.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl738.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8181.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8484.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8686.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8787.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl883.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8853.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl8870.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl9191.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl969.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zl9898.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zlhuodong.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zlong8.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "znti.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zodgame.fun", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zookids.uy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69147,7 +68839,6 @@
     { "name": "doggo.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dotweb.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dragcave.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "dsa.cy", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "e-referendum.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "echomall.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "edsinet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69436,6 +69127,767 @@
     { "name": "zanshinkankarate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zen-solutions.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "znaj.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "00370038.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0038088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "01media.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0205wc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0380l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0531009.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0999sfce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "0x0000.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "100086ll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1049578.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1265353.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1325390854.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "13866670.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "13982407454.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1406304513.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1441805971.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "168wcw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1834202695.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "18680288.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "18858586888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1918173197.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "198752qq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1ki174.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "20000615.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2001617.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "20190204.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "20190508.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2019318.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2112323.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2324275338.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "233hub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "24796559.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2569abc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "260842907.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2686288.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2692646200.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "2941798824.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375511.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375522.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375533.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375544.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375566.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375577.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375588.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "30375599.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3054056550.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "308xsj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "360008888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380021868.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380138000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3801808.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3801988.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380201314.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3802024.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3802025.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222222.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222333.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222444.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222777.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380222999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3802288.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3803300.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3804488.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3805201314.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3805355.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3805500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3805511abc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3806600.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3806677.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3806789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3807344.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3807711.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3807722.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3807733.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3807755.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3808822.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3808833.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3808844.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3808855.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3808866.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3809900.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3809911.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3809922.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3809933.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3809944.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "380zz8989.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "38138938.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "3886aa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "39661463.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4999016.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4monar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "504737.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "518558.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5197.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5197dns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5197dz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5197sx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051h.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051n.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051o.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051v.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52051z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067h.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067n.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067o.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067v.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067y.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "52067z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5225sf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "5356699.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "556021.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "57771399.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "578637.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "58586668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "588007008.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "60068vb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "6133feng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "6859551.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "715805617.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "758m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "7717411.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "781371.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "781376.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "781671.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "781683.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "781713.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "783631.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "81000906.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8363p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8367p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8368p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8369p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8371p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8373p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8376p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8378p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8379p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8387p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8391p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "83969789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8396p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8666213.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8880005555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "919093590.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "91d27.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297c.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297dns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297h.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297hb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297hd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297i.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297j.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297k.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297m.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297o.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297p.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297q.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297r.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297s.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297t.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297v.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297w.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297x.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9297z.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "962312.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9728.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9728dns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9728dz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9728hb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9728hd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "9728sx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "98198823.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "989868888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "99818adc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "a1972894570.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "a19840925.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "a666l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aa753159.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abc9981.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abcdzgx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abstudio.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adept-elearning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "advancedendoscopycenter.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agentur-pottkinder.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ahd1234.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ainishitou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "airslate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ajwebsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alfaproweb.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aliv.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aloexn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "alplogopedia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amao999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amplead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "andrewpucci.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "annalitvinova.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apc.ec", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "appassionata.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aramloebmd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "art-et-tonneaux.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "artigianociao.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "assetbacked.capital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "associatedwomenshealthcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "asu.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "atf.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "athenacle.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "audioboom.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "auto-i-dat.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autocobot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autohomehub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autouncle.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "azh-kunden.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "babineaux.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baidu389.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "basement961.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "baterioverolety.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bavaroparadise.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bavarovillage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "beau.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "belgicaservices.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bethanypeds.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bi-ec.ac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bianvip888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bikhof.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "binwu666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "biofrequenze.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bolgarka.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brandonhaynesmd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brooklyncosmetics.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buckscountyobgyn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "buziaczki.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "caipao123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "camdenboneandjoint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "campingshop.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "canavillage.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "candinya.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carlavitalesteticista.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carlosabarbamd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casacomcharme.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "catholic8964.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cc-customer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "celebrasianconference.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "centrodeesteticarecife.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chadpugsley.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chc9912.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chen22311.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chrisgieger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cio.guide", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cloudeezy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubegolfpt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coaching-harmonique.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coaching-park.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "codenlife.kr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "color01.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "colyakoomusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "consciente.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "consciente.ngo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "consciente.ong", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "consegne.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "construct.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "coop.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "couponbates.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cpcp380.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cryptizy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "csjministriesfoundation.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "css125.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "culan.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "curacaodiveguide.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cxq77128.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dadahen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dakotasjoint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dallasmenshealth.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "danielmiessler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "danielpenno.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "danna888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datax-cloud.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "davidzack.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dawnofhope.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dbudj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "decidio.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dein-baumdienst.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "demibaguette.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dhedegaard.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digicode.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digitalredshirts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "digitalspiders.pk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "displayenergycertificate.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dmfj.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dq12321.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drglassgyn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drhyler.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drsubbio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dutrac.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecologikashop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ecuadorbienesraices.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "edubase.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eirik.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elchamandelaprosperidad.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "electerious.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elegance-sm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elforno.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elysiandigital.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emsadi.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emzi0767.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "encountercss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "endustriyelfirinlar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "entrezdansladanse.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epagos.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epcreport.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "epiclub.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eppione.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "equi.ac", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ertir.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "escapejoplin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "esu.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "etajerka.spb.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "evaluate.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "example4d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "expromo.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fabianbeiner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "facchinaggio.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "facfox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fafa106.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fallenmoons.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fallin.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "familleseux.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fattailcall.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fdfz.edu.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ferienstpeter.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "filebox.one", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "firestuff.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flamingowomenspavilion.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "florida-prep.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flossexanten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "francescoyatesfansite.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "frostednetwork.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fy380.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "g-fruit.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gabinetejuridicotecnologicojuandemeseguer.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "galaltosalento.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gamesme.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ganaenergia.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gathermycrew.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gc.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gdsqua.re", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "geektier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gentcdn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gentlent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gentlent.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "giveoneup.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gladiac.duckdns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "globe-flight.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "globologic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gomelagromashplus.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "grapheneos.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "guytarrant.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "haarstudiok99.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hag27.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "haoshen666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hb5197.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hd5197.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hedge.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "heroliker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hh46953255.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "highdesertroboticsurgery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hillsandsaunders.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hillsandsaunders.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hingston.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hm5189.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "houhaoyi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "howson.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hpvtimmerwerken.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "html2gutenberg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hugonote.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hugovr.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hui89119.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "huyaya123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyansc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hyper.ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ictbiz.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iegat.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iliz-kafe.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iloli.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "indianareflux.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "inshop.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "insideevs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "insideevs.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "intr0.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ione.net.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iotac.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isa357.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isa5417.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "italbavaro.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ivisitorinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jaingynecology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jb159632.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jianyuan.art", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jmx520.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joebiden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joodari.fi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "josephbarela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jydwz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k819.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kaioken.bar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kandofu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kevinschreuder.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kiczela.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kjfaudio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "klev.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kolaprestaurant.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kompjoeter.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "koolauwomenshealthcare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kreativbande.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ktmclubitalia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kuwichitaim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "l456852.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "labavn.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laegernevedlillebaelt.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lakersview.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laudableapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laudablesites.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "laudwein.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lay1688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lettersblogatory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lev103.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "li756.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lifestylefoto.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lin2018168.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linuxgiggle.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liujr.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ll.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "llsv666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "localcryptopremium.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "londonindustryshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "long228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "longdie88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loteamentoabertoamparo.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "louisvillefibroids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lovemybubbles.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loyisa.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lwsl.ink", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lyclive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "m-cont.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "m-kugpn.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "macrostudent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "madeinrussia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "makita-online.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mamatting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mamoris-net.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mangel.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manilaprinciples.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "martin-weil.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meccano.srl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medguide-bg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mehrnevesht.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mercadeolocal.com.ar", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meridianenvironmental.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meta4.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "metronews.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mhurologytriad.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "midi-ctes.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mikemooresales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "miniwolke.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "minmaxgame.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mistinecn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mm4447761.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mojt.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "monsecretariat.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moonboys.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "morvo.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mrnordic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mt1016.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mtechprecisioninc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mulk.hopto.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myconf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "myhmz.bid", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mywiwe.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nb10000.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neev.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "neo2k.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "newenglandworkinjury.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "next-server.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nicolaottomano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "normantobar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "northtexasvasectomy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nriol.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nstnet.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nursemom.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nxgn.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nzbs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "obgynmiamifl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ok3on.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "oklahomafibroids.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "omnifurgone.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "omnimoto.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "onlineweblearning.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "openrtm.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "opium.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "otvertka.kz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ovabastecedoraindustrial.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "p1group.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pacificgynsurgicalgroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "padelbox.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "parrocchiamontevecchia.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pc9865.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pedalsbarcelona.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pinellaslaser.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ploxel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "poopchart.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pornskyhub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "potomacurology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ppwancai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "precision-tops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "privacybydesign.foundation", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "privatislauga.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "procarswoking.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "professionalbeautyshop.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "provinciaotlavoro.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ps2911.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qdqlh.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qlarititech.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "qmee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "raccoon-music.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "raewardfresh.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rclaywilliamsdo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reparacionesdecalefones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "reparizy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rideapart.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rodeoimport.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "romail.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "royjr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rueduparticulier.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sagitta.hr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saitama.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schokoladensouffle.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "schoolofphilosophy.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scitheory.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sdfleetmanagement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seabooty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "segenstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sentinelsmotorcycleclub.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "serenavillage.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "serviciales.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "servmaslt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sesamecare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sewamobilperdana.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sf3223.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shiji456.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shuai1122.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "siga.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "silvernight.social", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "skyportcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smelly.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smithf.red", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sneakers88.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sointelcom.com.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sort.land", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sourdough.vc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soverin.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soyfanonline.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "space-inc.co.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ssc8809.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stagespediatrics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stevengrech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "subtlelonging.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sugarlandurology.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sumit.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "support-ticino.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swid.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "swisservers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sxwancai18.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "synd.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tagtoys.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tarfin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxi-edessas.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "techzjc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "televizeseznam.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "testvocacional.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "texasurodoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thavmacode.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thebigslow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thefootinstitutela.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thegarage961.co.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "theissen.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thijs.amsterdam", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "timeclub24.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tk-its.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tonarinoliusan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tonight.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tourdewestwoud.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "traderbot.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trickle.works", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "troplo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trueminecraft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "truendo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ts5server.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tylyjj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ujiyasu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "unnamed.download", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upforshare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uplead.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uspaacc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "utavatu.mk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "utorg.com.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vape-hit.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "venstar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vibgyyor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vip380.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "visitorguard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vivaio.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "voordeuren-opmaat.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vwh-kunden.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancai666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancai880.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancai886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancaibbin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancaip66.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancaiqe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancaiqwe5967.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wancaiwang8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangbin1023.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wangfuhe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "waterheaterdallastx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "watervillewomenscare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wc11122.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wc168cp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wclhtzs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw10000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw130.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw179.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw618.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw635290.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcw9366.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcwcp88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wdj1023.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "webrabbit.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wendabisheng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wg1907.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "whanwhy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wo211997.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "worldmeetings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wucanyao.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wyjmb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xanimalcaps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xanyl.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt22.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt33.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt4.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt5.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt55.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt77.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbjt9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbyl17.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbyl28.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbyl62.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbyl67.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbyl73.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xbyl85.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xiang111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xiazhaobing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo010.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo016.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo020.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo026.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo028.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo030.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinbo050.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--0kq33cbsi8bk6d417b.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--p3t555glxhnwa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--svezavaukuu-ulb08i.rs", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xun3708855.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xxx020625.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ykqpw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yonema.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yourstage.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yusukesakai.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yuvibrands.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zanzariere.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zcwtl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zhengqiangonglue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zhouzeng1314.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zjh6888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zp.do", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zuanqianni.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zz0036.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index ec394873..4767480b 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -820,6 +820,7 @@
 //      "load_flags": <Numeric value of the combined load flags>,
 //      "privacy_mode": <True if privacy mode is enabled for the request>
 //      "priority": <Numeric priority of the request>,
+//      "traffic_annotation": <int32 for the request's TrafficAnnotationTag>,
 //      "upload_id" <String of upload body identifier, if present>,
 //   }
 //
diff --git a/net/quic/platform/impl/quic_ip_address_impl.cc b/net/quic/platform/impl/quic_ip_address_impl.cc
index 85af5747..37fa742 100644
--- a/net/quic/platform/impl/quic_ip_address_impl.cc
+++ b/net/quic/platform/impl/quic_ip_address_impl.cc
@@ -140,4 +140,14 @@
                                      subnet_length);
 }
 
+in_addr QuicIpAddressImpl::GetIPv4() const {
+  DCHECK_EQ(sizeof(in_addr), ip_address_.bytes().size());
+  return *(reinterpret_cast<const in_addr*>(ip_address_.bytes().data()));
+}
+
+in6_addr QuicIpAddressImpl::GetIPv6() const {
+  DCHECK_EQ(sizeof(in6_addr), ip_address_.bytes().size());
+  return *(reinterpret_cast<const in6_addr*>(ip_address_.bytes().data()));
+}
+
 }  // namespace quic
diff --git a/net/quic/platform/impl/quic_ip_address_impl.h b/net/quic/platform/impl/quic_ip_address_impl.h
index 6eefe66..84579fe 100644
--- a/net/quic/platform/impl/quic_ip_address_impl.h
+++ b/net/quic/platform/impl/quic_ip_address_impl.h
@@ -56,8 +56,10 @@
   bool FromString(std::string str);
   bool IsIPv4() const;
   bool IsIPv6() const;
-
   bool InSameSubnet(const QuicIpAddressImpl& other, int subnet_length);
+
+  in_addr GetIPv4() const;
+  in6_addr GetIPv6() const;
   const net::IPAddress& ip_address() const { return ip_address_; }
 
  private:
diff --git a/net/spdy/platform/impl/spdy_unsafe_arena_impl.cc b/net/spdy/platform/impl/spdy_unsafe_arena_impl.cc
deleted file mode 100644
index 1d3aa9c..0000000
--- a/net/spdy/platform/impl/spdy_unsafe_arena_impl.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/spdy/platform/impl/spdy_unsafe_arena_impl.h"
-
-#include <string.h>
-
-#include <algorithm>
-
-#include "base/logging.h"
-
-namespace spdy {
-
-SpdyUnsafeArenaImpl::SpdyUnsafeArenaImpl(size_t block_size)
-    : block_size_(block_size) {}
-
-SpdyUnsafeArenaImpl::~SpdyUnsafeArenaImpl() = default;
-
-SpdyUnsafeArenaImpl::SpdyUnsafeArenaImpl(SpdyUnsafeArenaImpl&& other) = default;
-SpdyUnsafeArenaImpl& SpdyUnsafeArenaImpl::operator=(
-    SpdyUnsafeArenaImpl&& other) = default;
-
-char* SpdyUnsafeArenaImpl::Alloc(size_t size) {
-  Reserve(size);
-  Block& b = blocks_.back();
-  DCHECK_GE(b.size, b.used + size);
-  char* out = b.data.get() + b.used;
-  b.used += size;
-  return out;
-}
-
-char* SpdyUnsafeArenaImpl::Realloc(char* original,
-                                   size_t oldsize,
-                                   size_t newsize) {
-  DCHECK(!blocks_.empty());
-  Block& last = blocks_.back();
-  if (last.data.get() <= original && original < last.data.get() + last.size) {
-    // (original, oldsize) is in the last Block.
-    DCHECK_GE(last.data.get() + last.used, original + oldsize);
-    if (original + oldsize == last.data.get() + last.used) {
-      // (original, oldsize) was the most recent allocation,
-      if (original + newsize < last.data.get() + last.size) {
-        // (original, newsize) fits in the same Block.
-        last.used += newsize - oldsize;
-        return original;
-      }
-    }
-  }
-  char* out = Alloc(newsize);
-  memcpy(out, original, oldsize);
-  return out;
-}
-
-char* SpdyUnsafeArenaImpl::Memdup(const char* data, size_t size) {
-  char* out = Alloc(size);
-  memcpy(out, data, size);
-  return out;
-}
-
-void SpdyUnsafeArenaImpl::Free(char* data, size_t size) {
-  if (blocks_.empty()) {
-    return;
-  }
-  Block& b = blocks_.back();
-  if (size <= b.used && data + size == b.data.get() + b.used) {
-    // The memory region passed by the caller was the most recent allocation
-    // from the final block in this arena.
-    b.used -= size;
-  }
-}
-
-void SpdyUnsafeArenaImpl::Reset() {
-  blocks_.clear();
-  status_.bytes_allocated_ = 0;
-}
-
-void SpdyUnsafeArenaImpl::Reserve(size_t additional_space) {
-  if (blocks_.empty()) {
-    AllocBlock(std::max(additional_space, block_size_));
-  } else {
-    const Block& last = blocks_.back();
-    if (last.size < last.used + additional_space) {
-      AllocBlock(std::max(additional_space, block_size_));
-    }
-  }
-}
-
-void SpdyUnsafeArenaImpl::AllocBlock(size_t size) {
-  blocks_.push_back(Block(size));
-  status_.bytes_allocated_ += size;
-}
-
-SpdyUnsafeArenaImpl::Block::Block(size_t s)
-    : data(new char[s]), size(s), used(0) {}
-
-SpdyUnsafeArenaImpl::Block::~Block() = default;
-
-SpdyUnsafeArenaImpl::Block::Block(SpdyUnsafeArenaImpl::Block&& other)
-    : size(other.size), used(other.used) {
-  data = std::move(other.data);
-}
-
-SpdyUnsafeArenaImpl::Block& SpdyUnsafeArenaImpl::Block::operator=(
-    SpdyUnsafeArenaImpl::Block&& other) {
-  size = other.size;
-  used = other.used;
-  data = std::move(other.data);
-  return *this;
-}
-
-}  // namespace spdy
diff --git a/net/spdy/platform/impl/spdy_unsafe_arena_impl.h b/net/spdy/platform/impl/spdy_unsafe_arena_impl.h
index f7867a7..faa1c1e 100644
--- a/net/spdy/platform/impl/spdy_unsafe_arena_impl.h
+++ b/net/spdy/platform/impl/spdy_unsafe_arena_impl.h
@@ -8,69 +8,11 @@
 #include <memory>
 #include <vector>
 
-#include "net/third_party/quiche/src/spdy/platform/api/spdy_export.h"
+#include "net/third_party/quiche/src/spdy/core/spdy_simple_arena.h"
 
 namespace spdy {
 
-// Allocates large blocks of memory, and doles them out in smaller chunks.
-// Not thread-safe.
-class SPDY_EXPORT_PRIVATE SpdyUnsafeArenaImpl {
- public:
-  class Status {
-   private:
-    friend class SpdyUnsafeArenaImpl;
-    size_t bytes_allocated_;
-
-   public:
-    Status() : bytes_allocated_(0) {}
-    size_t bytes_allocated() const { return bytes_allocated_; }
-  };
-
-  // Blocks allocated by this arena will be at least |block_size| bytes.
-  explicit SpdyUnsafeArenaImpl(size_t block_size);
-  ~SpdyUnsafeArenaImpl();
-
-  // Copy and assign are not allowed.
-  SpdyUnsafeArenaImpl() = delete;
-  SpdyUnsafeArenaImpl(const SpdyUnsafeArenaImpl&) = delete;
-  SpdyUnsafeArenaImpl& operator=(const SpdyUnsafeArenaImpl&) = delete;
-
-  // Move is allowed.
-  SpdyUnsafeArenaImpl(SpdyUnsafeArenaImpl&& other);
-  SpdyUnsafeArenaImpl& operator=(SpdyUnsafeArenaImpl&& other);
-
-  char* Alloc(size_t size);
-  char* Realloc(char* original, size_t oldsize, size_t newsize);
-  char* Memdup(const char* data, size_t size);
-
-  // If |data| and |size| describe the most recent allocation made from this
-  // arena, the memory is reclaimed. Otherwise, this method is a no-op.
-  void Free(char* data, size_t size);
-
-  void Reset();
-
-  Status status() const { return status_; }
-
- private:
-  struct Block {
-    std::unique_ptr<char[]> data;
-    size_t size = 0;
-    size_t used = 0;
-
-    explicit Block(size_t s);
-    ~Block();
-
-    Block(Block&& other);
-    Block& operator=(Block&& other);
-  };
-
-  void Reserve(size_t additional_space);
-  void AllocBlock(size_t size);
-
-  size_t block_size_;
-  std::vector<Block> blocks_;
-  Status status_;
-};
+using SpdyUnsafeArenaImpl = SpdySimpleArena;
 
 }  // namespace spdy
 
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 21205ca4..524459f 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -305,6 +305,9 @@
   dict->SetBoolean("has_upload", has_upload());
   dict->SetBoolean("is_pending", is_pending_);
 
+  dict->SetInteger("traffic_annotation",
+                   traffic_annotation_.unique_id_hash_code);
+
   // Add the status of the request.  The status should always be IO_PENDING, and
   // the error should always be OK, unless something is holding onto a request
   // that has finished or a request was leaked.  Neither of these should happen.
@@ -609,7 +612,8 @@
   context->url_requests()->insert(this);
   net_log_.BeginEvent(
       NetLogEventType::REQUEST_ALIVE,
-      base::Bind(&NetLogURLRequestConstructorCallback, &url, priority_));
+      base::BindRepeating(&NetLogURLRequestConstructorCallback, &url, priority_,
+                          traffic_annotation_));
 }
 
 void URLRequest::BeforeRequestComplete(int error) {
diff --git a/net/url_request/url_request_netlog_params.cc b/net/url_request/url_request_netlog_params.cc
index 360ab31c..fc4882a 100644
--- a/net/url_request/url_request_netlog_params.cc
+++ b/net/url_request/url_request_netlog_params.cc
@@ -16,10 +16,13 @@
 std::unique_ptr<base::Value> NetLogURLRequestConstructorCallback(
     const GURL* url,
     RequestPriority priority,
+    NetworkTrafficAnnotationTag traffic_annotation,
     NetLogCaptureMode /* capture_mode */) {
   std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
   dict->SetString("url", url->possibly_invalid_spec());
   dict->SetString("priority", RequestPriorityToString(priority));
+  dict->SetInteger("traffic_annotation",
+                   traffic_annotation.unique_id_hash_code);
   return std::move(dict);
 }
 
diff --git a/net/url_request/url_request_netlog_params.h b/net/url_request/url_request_netlog_params.h
index bb259a3e..e1be060 100644
--- a/net/url_request/url_request_netlog_params.h
+++ b/net/url_request/url_request_netlog_params.h
@@ -13,6 +13,7 @@
 #include "net/base/net_export.h"
 #include "net/base/privacy_mode.h"
 #include "net/base/request_priority.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 class GURL;
 
@@ -28,6 +29,7 @@
 NET_EXPORT std::unique_ptr<base::Value> NetLogURLRequestConstructorCallback(
     const GURL* url,
     RequestPriority priority,
+    NetworkTrafficAnnotationTag traffic_annotation,
     NetLogCaptureMode /* capture_mode */);
 
 // Returns a Value containing NetLog parameters for starting a URLRequest.
diff --git a/remoting/signaling/ftl_grpc_context.cc b/remoting/signaling/ftl_grpc_context.cc
index a01195e..b84dd23 100644
--- a/remoting/signaling/ftl_grpc_context.cc
+++ b/remoting/signaling/ftl_grpc_context.cc
@@ -84,7 +84,12 @@
 // static
 std::unique_ptr<grpc::ClientContext> FtlGrpcContext::CreateClientContext() {
   auto context = std::make_unique<grpc::ClientContext>();
-  context->AddMetadata("x-goog-api-key", google_apis::GetRemotingFtlAPIKey());
+#if defined(OS_ANDROID) || defined(OS_IOS)
+  std::string api_key = google_apis::GetRemotingFtlMobileAPIKey();
+#else
+  std::string api_key = google_apis::GetRemotingFtlAPIKey();
+#endif
+  context->AddMetadata("x-goog-api-key", api_key);
   return context;
 }
 
diff --git a/services/device/wake_lock/wake_lock.h b/services/device/wake_lock/wake_lock.h
index ed14fe9..adefd6f 100644
--- a/services/device/wake_lock/wake_lock.h
+++ b/services/device/wake_lock/wake_lock.h
@@ -28,8 +28,6 @@
 class WakeLock : public mojom::WakeLock {
  public:
   // This is an interface for classes to be notified of wake lock events.
-  // Observers should register themselves by calling the parent class's
-  // |AddObserver| method.
   class Observer {
    public:
     virtual ~Observer() = default;
@@ -63,7 +61,7 @@
            Observer* observer);
   ~WakeLock() override;
 
-  // WakeLockSevice implementation.
+  // mojom::WakeLock implementation.
   void RequestWakeLock() override;
   void CancelWakeLock() override;
   void AddClient(mojom::WakeLockRequest request) override;
diff --git a/services/resource_coordinator/OWNERS b/services/resource_coordinator/OWNERS
index 021ff20..2b8c9bcc 100644
--- a/services/resource_coordinator/OWNERS
+++ b/services/resource_coordinator/OWNERS
@@ -8,3 +8,6 @@
 zhenw@chromium.org
 
 per-file BUILD.gn=file://services/resource_coordinator/memory_instrumentation/OWNERS
+
+# TEAM: catan-team@chromium.org
+# COMPONENT: Internals>ResourceCoordinator
diff --git a/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc b/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
index e865db9..87194f3 100644
--- a/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
+++ b/services/tracing/public/cpp/perfetto/perfetto_traced_process.cc
@@ -6,7 +6,6 @@
 
 #include "base/no_destructor.h"
 #include "base/task/post_task.h"
-#include "base/task/thread_pool/scheduler_lock_impl.h"
 #include "services/tracing/public/cpp/perfetto/producer_client.h"
 
 namespace tracing {
diff --git a/services/tracing/public/cpp/perfetto/task_runner.cc b/services/tracing/public/cpp/perfetto/task_runner.cc
index 154ac32f..9f6faac 100644
--- a/services/tracing/public/cpp/perfetto/task_runner.cc
+++ b/services/tracing/public/cpp/perfetto/task_runner.cc
@@ -9,8 +9,8 @@
 
 #include "base/bind.h"
 #include "base/no_destructor.h"
+#include "base/task/common/checked_lock_impl.h"
 #include "base/task/post_task.h"
-#include "base/task/thread_pool/scheduler_lock_impl.h"
 #include "base/task/thread_pool/thread_pool.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/threading/thread_local.h"
@@ -33,7 +33,7 @@
   if (enabled_) {
     PerfettoTaskRunner::BlockPostTaskForThread();
   } else {
-    base::internal::SchedulerLockImpl::AssertNoLockHeldOnCurrentThread();
+    base::internal::CheckedLockImpl::AssertNoLockHeldOnCurrentThread();
   }
 }
 
diff --git a/testing/buildbot/chromium.chrome.json b/testing/buildbot/chromium.chrome.json
index 7d2c7533..ad59c2f 100644
--- a/testing/buildbot/chromium.chrome.json
+++ b/testing/buildbot/chromium.chrome.json
@@ -85,23 +85,6 @@
         "test": "ash_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
         "experiment_percentage": 100,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -235,46 +218,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
-        ],
-        "experiment_percentage": 100,
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ],
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "experiment_percentage": 100,
@@ -471,25 +414,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
         ],
@@ -539,23 +463,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "experiment_percentage": 100,
@@ -650,23 +557,6 @@
         "test": "exo_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
         "experiment_percentage": 100,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -798,24 +688,6 @@
         "test": "interactive_ui_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
         "experiment_percentage": 100,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -1326,23 +1198,6 @@
         "test": "unit_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "experiment_percentage": 100,
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04",
-              "pool": "chrome.tests"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
         "experiment_percentage": 100,
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 734f2994..3d4dfdb0 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -540,21 +540,6 @@
         "test": "ash_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -668,25 +653,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
-        ],
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--disable-features=NetworkService"
         ],
         "name": "non_network_service_browser_tests",
@@ -703,23 +669,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 20
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_browser_tests",
@@ -918,23 +867,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
         ],
@@ -978,21 +910,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_unittests",
@@ -1073,21 +990,6 @@
         "test": "exo_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1230,22 +1132,6 @@
         "test": "interactive_ui_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1694,21 +1580,6 @@
         "test": "unit_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1838,21 +1709,6 @@
         "test": "ash_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -1966,42 +1822,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
-        ],
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_browser_tests",
@@ -2170,23 +1990,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
         ],
@@ -2230,21 +2033,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_unittests",
@@ -2325,21 +2113,6 @@
         "test": "exo_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2451,22 +2224,6 @@
         "test": "interactive_ui_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -2899,21 +2656,6 @@
         "test": "unit_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 292941b..251c64c 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -1370,21 +1370,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter"
-        ],
-        "name": "mash_fyi_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "hard_timeout": 1800,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=NetworkService"
         ],
         "name": "network_service_browser_tests",
@@ -1445,17 +1430,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash"
-        ],
-        "name": "mash_fyi_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "name": "viz_content_unittests",
@@ -1476,19 +1450,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter"
-        ],
-        "name": "mash_fyi_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
-        "args": [
           "--enable-features=NetworkService"
         ],
         "name": "network_service_interactive_ui_tests",
@@ -2985,9 +2946,6 @@
     ],
     "gtest_tests": [
       {
-        "args": [
-          "--use-host-tast-bin"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3004,9 +2962,6 @@
         "test": "chrome_all_tast_tests"
       },
       {
-        "args": [
-          "--use-host-tast-bin"
-        ],
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -3607,6 +3562,15 @@
         "test": "fidlgen_js_unittests"
       },
       {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.gfx_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "gfx_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true
         },
@@ -3844,6 +3808,20 @@
         "test": "fidlgen_js_unittests"
       },
       {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.gfx_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
+        "test": "gfx_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -4146,6 +4124,20 @@
         "test": "fidlgen_js_unittests"
       },
       {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.gfx_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "kvm": "1"
+            }
+          ]
+        },
+        "test": "gfx_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
@@ -6703,22 +6695,6 @@
         "test": "ash_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -6842,44 +6818,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
-        ],
-        "isolate_coverage_data": true,
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 20
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "isolate_coverage_data": true,
@@ -7062,24 +7000,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
         ],
@@ -7126,22 +7046,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "isolate_coverage_data": true,
@@ -7229,22 +7133,6 @@
         "test": "exo_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7366,23 +7254,6 @@
         "test": "interactive_ui_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -7854,22 +7725,6 @@
         "test": "unit_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -8022,22 +7877,6 @@
         "test": "ash_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -8161,44 +8000,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter"
-        ],
-        "isolate_coverage_data": true,
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 20
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "isolate_coverage_data": true,
@@ -8381,24 +8182,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*"
         ],
@@ -8445,22 +8228,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor"
         ],
         "isolate_coverage_data": true,
@@ -8548,22 +8315,6 @@
         "test": "exo_unittests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -8685,23 +8436,6 @@
         "test": "interactive_ui_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -9173,22 +8907,6 @@
         "test": "unit_tests"
       },
       {
-        "args": [
-          "--disable-features=SingleProcessMash"
-        ],
-        "isolate_coverage_data": true,
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
         "isolate_coverage_data": true,
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 37a4ba1..3afd092 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5940,24 +5940,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -6852,24 +6834,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:1cb3-410.78",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -7395,24 +7359,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -8075,24 +8021,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -8633,24 +8561,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -9216,24 +9126,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -9582,32 +9474,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "os": "Mac-10.14.4",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "optional_dimensions": {
-            "600": [
-              {
-                "os": "Mac-10.14.3"
-              }
-            ]
-          },
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -10218,32 +10084,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.14.4",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "optional_dimensions": {
-            "600": [
-              {
-                "os": "Mac-10.14.3"
-              }
-            ]
-          },
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -10854,32 +10694,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:0fe9",
-              "os": "Mac-10.14.4",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "optional_dimensions": {
-            "600": [
-              {
-                "os": "Mac-10.14.3"
-              }
-            ]
-          },
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -11444,23 +11258,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -11871,25 +11668,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -12349,26 +12127,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -12844,26 +12602,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:0fe9",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -13348,29 +13086,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            },
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -13873,23 +13588,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -14305,25 +14003,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -14745,25 +14424,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:0fe9",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -15180,25 +14840,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -15669,25 +15310,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:0fe9",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -16286,25 +15908,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:679e",
-              "os": "Mac-10.12.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -16748,24 +16351,6 @@
       },
       {
         "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "intel-hd-630-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
           "--use-gpu-in-tests"
         ],
         "swarming": {
@@ -17018,24 +16603,6 @@
       },
       {
         "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-ubuntu-stable",
-              "os": "Ubuntu",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
           "--use-gpu-in-tests"
         ],
         "swarming": {
@@ -17280,23 +16847,6 @@
       },
       {
         "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:0a2e",
-              "os": "Mac-10.12.6"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
           "--use-gpu-in-tests"
         ],
         "swarming": {
@@ -17454,25 +17004,6 @@
       },
       {
         "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:6821",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
           "--use-gpu-in-tests"
         ],
         "swarming": {
@@ -17644,25 +17175,6 @@
       },
       {
         "args": [
-          "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:0fe9",
-              "hidpi": "1",
-              "os": "Mac-10.13.6",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
           "--use-gpu-in-tests"
         ],
         "swarming": {
@@ -17839,24 +17351,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "intel-hd-630-win10-stable",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=passthrough"
         ],
         "name": "gl_tests_passthrough",
@@ -18300,33 +17794,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-win10-stable",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests",
-        "trigger_script": {
-          "args": [
-            "--multiple-trigger-configs",
-            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
-            "--multiple-dimension-script-verbose",
-            "True"
-          ],
-          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
-        }
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=passthrough"
         ],
         "name": "gl_tests_passthrough",
@@ -19017,24 +18484,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-win10-stable",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -19790,25 +19239,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "8086:5912-24.20.100.6286",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -20623,25 +20053,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "1002:699f",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -21361,24 +20772,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "intel-hd-630-win10-stable",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -22135,25 +21528,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "10de:2184",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "expiration": 21600,
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests"
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
@@ -22972,33 +22346,6 @@
       {
         "args": [
           "--use-gpu-in-tests",
-          "--test-launcher-retry-limit=0"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "gpu": "nvidia-quadro-p400-win10-stable",
-              "os": "Windows-10",
-              "pool": "Chrome-GPU"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "dawn_end2end_tests",
-        "trigger_script": {
-          "args": [
-            "--multiple-trigger-configs",
-            "[{\"gpu\": \"nvidia-quadro-p400-win10-stable\", \"os\": \"Windows-10\", \"pool\": \"Chrome-GPU\"}]",
-            "--multiple-dimension-script-verbose",
-            "True"
-          ],
-          "script": "//testing/trigger_scripts/trigger_multiple_dimensions.py"
-        }
-      },
-      {
-        "args": [
-          "--use-gpu-in-tests",
           "--use-cmd-decoder=validating"
         ],
         "swarming": {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 5a59532f..1ee2b6f 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -5004,22 +5004,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -5162,44 +5146,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 30
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor",
           "--test-launcher-print-test-stdio=always"
         ],
@@ -5405,24 +5351,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*",
           "--test-launcher-print-test-stdio=always"
@@ -5471,22 +5399,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor",
           "--test-launcher-print-test-stdio=always"
         ],
@@ -5587,22 +5499,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -5730,23 +5626,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -6296,22 +6175,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -6490,23 +6353,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_ash_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "ash_unittests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -6659,46 +6505,6 @@
       },
       {
         "args": [
-          "--enable-features=Mash",
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "hard_timeout": 1800
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_browser_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 20
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor",
           "--test-launcher-print-test-stdio=always"
         ],
@@ -6917,25 +6723,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_content_browsertests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 5
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
           "--disable-perfetto",
           "--gtest_filter=TracingControllerTest.*:BackgroundTracingManagerBrowserTest.*",
           "--test-launcher-print-test-stdio=always"
@@ -6988,23 +6775,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_content_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
           "--enable-features=VizDisplayCompositor",
           "--test-launcher-print-test-stdio=always"
         ],
@@ -7112,23 +6882,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_exo_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "exo_unittests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -7265,24 +7018,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_interactive_ui_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
@@ -7856,23 +7591,6 @@
       },
       {
         "args": [
-          "--disable-features=SingleProcessMash",
-          "--test-launcher-print-test-stdio=always"
-        ],
-        "name": "non_single_process_mash_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "cpu": "x86-64",
-              "os": "Ubuntu-14.04"
-            }
-          ]
-        },
-        "test": "unit_tests"
-      },
-      {
-        "args": [
           "--test-launcher-print-test-stdio=always"
         ],
         "swarming": {
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 4c005ce..53bb516 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -52,8 +52,10 @@
       {
         "args": [
           "-v",
-          "--browser=android-chrome",
+          "--browser=exact",
           "--upload-results",
+          "--browser-executable=../../out/Release/bin/monochrome_64_32_bundle",
+          "--device=android",
           "--run-ref-build",
           "--test-shard-map-filename=android-pixel2-perf_map.json"
         ],
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index c8fab81..2981e77 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -28,8 +28,6 @@
   testonly = true
 
   data = [
-    "//testing/buildbot/filters/chromeos.mash.browser_tests.filter",
-    "//testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter",
     "//testing/buildbot/filters/webui_html_imports_polyfill_browser_tests.filter",
     "//testing/buildbot/filters/webrtc_functional.browser_tests.filter",
   ]
@@ -73,6 +71,7 @@
   data = [
     "//testing/buildbot/filters/fuchsia.base_perftests.filter",
     "//testing/buildbot/filters/fuchsia.content_unittests.filter",
+    "//testing/buildbot/filters/fuchsia.gfx_unittests.filter",
     "//testing/buildbot/filters/fuchsia.mojo_unittests.filter",
     "//testing/buildbot/filters/fuchsia.net_perftests.filter",
     "//testing/buildbot/filters/fuchsia.net_unittests.filter",
@@ -80,14 +79,6 @@
   ]
 }
 
-source_set("interactive_ui_tests_filters") {
-  testonly = true
-
-  data = [
-    "//testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter",
-  ]
-}
-
 source_set("webview_cts_tests_filters") {
   testonly = true
 
diff --git a/testing/buildbot/filters/chromeos.mash.browser_tests.filter b/testing/buildbot/filters/chromeos.mash.browser_tests.filter
deleted file mode 100644
index fb319e2d..0000000
--- a/testing/buildbot/filters/chromeos.mash.browser_tests.filter
+++ /dev/null
@@ -1,4 +0,0 @@
-# Sanity test that validates basic login functionality.  The full suite of
-# Mash browser tests runs on the mojo.fyi waterfall.
-# Context: http://crbug.com/874090
-LoginUtilsTest.MashLogin
diff --git a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter b/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
deleted file mode 100644
index bf4a152d..0000000
--- a/testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter
+++ /dev/null
@@ -1,338 +0,0 @@
-# These tests fail when running browser_tests with out-of-process ash
-# system UI on Chrome OS ("mash"). Most new features are expected to work
-# with mash, see //ash/README.md. If you need to disable more than
-# ~10 tests, please contact someone on mustash-team@google.com to discuss.
-# Meta-bug: http://crbug.com/678687
-#
-# This is a blacklist. Don't add positive filters. Mixing filter types can
-# result in no tests running. See README.md.
-
-# Unknown failure.
--BrowserTabRestoreTest.*
--ExtensionApiTest.IdleGetAutoLockDelay
--MediaRouterIntegrationOneUABrowserTest.Basic
--MediaRouterIntegrationOneUABrowserTest.Fail_SendMessage
--MediaRouterIntegrationOneUABrowserTest.ReconnectSession
--MediaRouterIntegrationOneUABrowserTest.ReconnectSessionSameTab
--MediaRouterIntegrationOneUANoReceiverBrowserTest.Basic
--MediaRouterIntegrationOneUANoReceiverBrowserTest.Fail_SendMessage
--MediaRouterIntegrationOneUANoReceiverBrowserTest.ReconnectSession
--MediaRouterIntegrationOneUANoReceiverBrowserTest.ReconnectSessionSameTab
--MediaSessionPictureInPictureWindowControllerBrowserTest.SkipAdButtonVisibility
--MediaSessionPictureInPictureWindowControllerBrowserTest.SkipAdHandlerCalled
--NoBestEffortTasksTest.LoadAndPaintAboutBlank
--NoBestEffortTasksTest.LoadAndPaintFromNetwork
--ProcessMemoryMetricsEmitterTest.FetchDuringTrace
--ScreenLockerTest.FingerprintAuthWhenAuthDisabled
--ScreenLockerTest.PasswordAuthWhenAuthDisabled
--ScreenLockerTest.TestBadThenGoodPassword
--ScreenLockerTest.TestShowTwice
--SwitchAccessAutoScanManagerTest.RestartIfRunningMultiple
--SwitchAccessAutoScanManagerTest.SetEnabledMultiple
--SwitchAccessAutoScanManagerTest.SetEnabled
--SwitchAccessAutoScanManagerTest.RestartIfRunningWhenOff
--SwitchAccessAutoScanManagerTest.EnableAndDisable
--SwitchAccessAutoScanManagerTest.SetScanTime
--SwitchAccessNavigationManagerTest.MoveForward
--SwitchAccessNavigationManagerTest.MoveBackward
--SwitchAccessNavigationManagerTest.MoveBackAndForth
--SwitchAccessNavigationManagerTest.SelectButton
--SwitchAccessPredicateTest.IsActionable
--SwitchAccessPredicateTest.IsGroup
--SwitchAccessPredicateTest.IsInterestingSubtree
--SwitchAccessPredicateTest.IsInteresting
--SwitchAccessPredicateTest.LeafPredicate
--SwitchAccessPredicateTest.RootPredicate
--SwitchAccessPredicateTest.VisitPredicate
--TrayAccessibilityLoginTestInstance/TrayAccessibilityLoginTest.ShowMenuWithShowOnLoginScreen/0
--TrayAccessibilityLoginTestInstance/TrayAccessibilityLoginTest.ShowMenuWithShowOnLoginScreen/1
--WebRtcGetDisplayMediaBrowserTestWithFakeUI.GetDisplayMedia/2
--WebRtcGetDisplayMediaBrowserTestWithFakeUI.GetDisplayMediaWithConstraints/2
-
-# Volume adjustment fails.
--WizardControllerTest.*ChromeVox
-
-# Login constructs ash::FocusRingController and KeyboardDrivenOobeKeyHandler,
-# both of which use ash::Shell.
--WizardControllerKioskFlowTest.*
-
-# Accesses ash::Shelf to make assertions about the shelf view.
--ArcAppDeferredLauncherBrowserTest.*
--ArcAppDeferredLauncherWithParamsBrowserTestInstance/ArcAppDeferredLauncherWithParamsBrowserTest.*
-
-# AutomationManagerAura::Enable() uses ash to get active window. More generally,
-# chrome a11y code directly accesses ash system UI widgets and views.
--AutomationApiTest.*
--AutomationApiTestWithDeviceScaleFactor.*
--AutomationManagerAuraBrowserTest.*
-
-# ChromeVox and Select-to-Speak not yet supported. https://crbug.com/594887
--ChromeVox*
--SelectToSpeak*
-
-# Touch gestures don't work in webcontents. https://crbug.com/866991.
--TopControlsSlideControllerTest.TestScrollingMaximizedPageBeforeGoingToTabletMode
--TopControlsSlideControllerTest.TestScrollingPage
--TopControlsSlideControllerTest.TestScrollingPageAndSwitchingToNTP
--TopControlsSlideControllerTest.TestClosingATab
--TopControlsSlideControllerTest.TestFocusEditableElements
--TopControlsSlideControllerTest.DisplayRotation
-
-# ash::Shell access from ChromeViewsDelegate::CreateDefaultNonClientFrameView()
-# e.g. from chromeos::CaptivePortalWindowProxy::Show().
-# See https://crbug.com/838974
--CaptivePortalWindowCtorDtorTest.*
--CaptivePortalWindowTest.*
--SimpleWebViewDialogTest.*
-
-# Need pixel copy support. http://crbug.com/754864 http://crbug.com/754872
--ArcAccessibilityHelperBridgeBrowserTest.*
--CastStreamingApiTest.*
--CastStreamingApiTestWithPixelOutput.*
--TabCaptureApiPixelTest.*
--TabCaptureApiTest.*
-
-# RefCounted check failed: CalledOnValidSequence() from SchedulerWorkerDelegate::OnMainExit
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.*
-
-# aura::CrashInFlightChange::ChangeFailed() when searching PDF.
--ChromeFindRequestManagerTest.*
--PDFExtensionTest.*
--PDFExtensionHitTestTest.*
--PDFExtensionLoadTest.*
-
-# Need screenshot support. http://crbug.com/706246
--ChromeScreenshotGrabberBrowserTest.*
-
-# Flaky. SessionRestoreStatsCollector::Observe failure. crbug.com/785298
-# session_restore_stats_collector.cc(210) Check failed: 0u < loading_tab_count_ (0 vs. 0)
--ContinueWhereILeftOffTest.*
--DeviceIDTest.*
--SessionRestoreTest.*
--SessionRestoreTestChromeOS.*
--SAMLPolicyTest.TransferCookiesAffiliated
--SmartSessionRestoreTest.*
-
-# ash::Shell access for LogoutConfirmationController
--DeviceLocalAccountTest.*
-
-# ash::PowerStatus access. https://crbug.com/770866.
--PowerHandlerTest.*
-
-# DBusThreadManager initialized for testing in chrome is not recognized as
-# initialized in window manager service. https://crbug.com/830816.
--PowerPolicyInSessionBrowserTest.AllowScreenWakeLocks
--PowerPolicyInSessionBrowserTest.SetLegacyUserPolicy
--PowerPolicyInSessionBrowserTest.SetUserPolicy
--PowerPolicyLoginScreenBrowserTest.SetDevicePolicy
-
-# TODO: Very slow (>25 seconds) and occasional timeouts.
--ExecuteScriptApiTest/DestructiveScriptTest.*
-
-# ozone_platform.cc(61) Check failed: instance_. OzonePlatform is not initialized
--ExtensionWebstoreGetWebGLStatusTest.*
-
-# SystemLogsFetcher -> TouchLogSource -> ash::TouchHudDebug -> ash::Shell
--FeedbackTest.*
-
-# ash::Shell::display_manager() to update displays.
-# http://crbug.com/831826
--ForceMaximizeOnFirstRunTest.*
--ForceMaximizePolicyFalseTest.*
--PolicyDisplayRotationDefault/DisplayRotationBootTest.*
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.*
-
-# ash::Shell::display_manager() to get display state.
-# http://crbug.com/831826
--PolicyTest.UnifiedDesktopEnabledByDefault
--PolicyDeviceDisplayResolution/*
-
-# Kiosk mode has a variety of failures:
-# termination_observer_->terminated() is false.
-# Value of: login_display_host == NULL || login_display_host->GetNativeWindow()->layer()->GetTargetOpacity() == 0.0f
-# Check failed: !browser_client || browser_client->IsShuttingDown() || did_respond() || ignore_all_did_respond_for_testing_do_not_use. app.window.create
--KioskAppManagerTest.*
--KioskAppSettingsWebUITest.*
--KioskCrashRestoreTest.*
--KioskEnterpriseTest.*
--KioskHiddenWebUITest.*
--KioskTest.*
--KioskUpdateTest.*
-
-# Panel state lookup failures for window active, item running, etc.
--LauncherPlatformAppBrowserTest.PanelAttentionStatus
--LauncherPlatformAppBrowserTest.PanelItemClickBehavior
-
-# Missing magnification manager and also RefCounted check failed:
-# CalledOnValidSequence() from SchedulerWorkerDelegate::OnMainExit
--LoginScreenDefaultPolicyInSessionBrowsertest.*
--LoginScreenDefaultPolicyLoginScreenBrowsertest.*
--PolicyTest.ScreenMagnifierTypeFull
--PolicyTest.ScreenMagnifierTypeNone
-
-# Crashes in pre-login phase, probably MagnificationManager not created.
--MagnificationManagerTest.*
-
-# ash::FocusRingController::SetVisible() from LoginDisplayHostWebUI.
--MultiAuthEnrollmentScreenTest.*
--ProvisionedEnrollmentScreenTest.*
-
-# Ash currently uses its own NetworkHandler instance so the
-# captive_portal_provider_ member of networkState is not set correctly.
-# https://crbug.com/862420
--NetworkingConfigChromeosTest.SystemTrayItem
-
-# Timeout device_event_log_impl.cc(156) Network: network_portal_detector_impl.cc:486 Portal detection timeout:  name= id=
--NetworkingConfigTest.*
--NetworkPortalDetectorImplBrowserTest.*
-
-# ash::Shell access in test for display configuration.
-# http://crbug.com/831826
--ShelfAppBrowserTest.LaunchAppFromDisplayWithoutFocus*
-
-# Test fails. https://crbug.com/899867
--ShelfAppBrowserTest.SettingsAndTaskManagerWindows
-
-# content::WaitForChildFrameSurfaceReady hangs.
--SitePerProcessDevToolsSanityTest.InputDispatchEventsToOOPIF
--ChromeMimeHandlerViewBrowserPluginTest.TouchFocusesBrowserPluginInEmbedder
-
-# Function under test uses ash::Shell for window list.
--SortWindowsByZIndexBrowserTest.*
-
-# Timeout because first non-empty paint isn't triggered.
-# https://crbug.com/885318
--NoBackgroundTasksTest.FirstNonEmptyPaintWithoutBackgroundTasks
--StartupMetricsTest.*
-
-# ash::Shell access in test for StatusAreaWidget.
--SupervisedUserCreationTest.*
-
-# Crash. Database is locked.
--SyncAwareCounterTest.*
-
-# ash::Shell access in test.
--SystemTrayTrayCastMediaRouterChromeOSTest.*
-
-# Flaky shutdown crashes in ~MusClient http://crbug.com/786234 and AtExit
-# crashes in ~WebContentsTaskProvider http://crbug.com/786230
--AppBackgroundPageApiTest.*
--DefaultIsolation/TaskManagerOOPIFBrowserTest.*
--PrerenderBrowserTest.*
--SitePerProcess/TaskManagerOOPIFBrowserTest.*
--TaskManagerBrowserTest.*
--TaskManagerUtilityProcessBrowserTest.*
-
-# ash::Shell access in test.
--TrayAccessibilityTestInstance/TrayAccessibilityTest.*
-
-# Changing the Chrome keyboard window size does not change the Ash keyboard
-# window size. These tests may require a test mojo interface for Mash.
-# https://crbug.com/843332.
--KeyboardControllerAppWindowTest.DisableOverscrollForImeWindow
--KeyboardEndToEndOverscrollTest.ToggleKeyboardOnMaximizedWindowAffectsViewport
-
-# Keyboard window does not move browser windows. https://crbug.com/906888.
--KeyboardEndToEndOverscrollTest.ToggleKeyboardOnShortOverlappingWindowMovesWindowUpwards
--KeyboardEndToEndOverscrollTest.ToggleKeyboardOnTallOverlappingWindowMovesWindowUpwardsAndAffectsViewport
-
-# Mouse move events are not handled correctly in tests.
-# TODO(stevenjb): Determine why this works in practice but fails in the test.
--KeyboardControllerWebContentTest.CanDragFloatingKeyboardWithMouse
-
-# RemoteTextInputClient is not forwarding focus requests to show/hide the
-# virtual keyboard: https://crbug.com/631527
--KeyboardEndToEndFormTest.ChangeInputModeToNoneHidesKeyboard
--KeyboardEndToEndFocusTest.TriggerAsyncInputFocusFromUserGestureAfterBlurShowsKeyboard
-
-# These tests succeed in SingleProcessMash but time out in Mash. They rely on
-# focusing an input element to show the virtual keyboard.
-# https://crbug.com/912233
--KeyboardEndToEndFocusTest.*
--KeyboardEndToEndFormTest.*
--KeyboardEndToEndOverscrollTest.*
--SelectFileDialogExtensionBrowserTest.SelectFileVirtualKeyboard_TabletMode
--SelectFileDialogExtensionBrowserTest/SelectFileDialogExtensionBrowserTest.SelectFileVirtualKeyboard_TabletMode/1
--SelectFileDialogExtensionBrowserTest/SelectFileDialogExtensionBrowserTest.SelectFileVirtualKeyboard_TabletMode/0
-
-# Chrome keyboard window -> root -> host -> input method is null in Mash.
-# https://crbug.com/756059
--KeyboardControllerWebContentTest.EnableIMEInDifferentExtension
-
-# Uses ash::LockWindow. https://crbug.com/899862
--ShutdownPolicyLockerTest.*
-
-# Timeouts in content::WaitForChildFrameSurfaceReady()
-# Crashes in viz::HostFrameSinkManager::RegisterFrameSinkId()
-# http://crbug.com/755328
--WebViewTest.*
-
-# Crashes in RenderProcessHostImpl::CreateEmbeddedFrameSinkProvider(). Refer
-# crbug.com/848039.
--DeclarativeNetRequestBrowserTest.PageWhitelistingAPI_Resources/0
--DeclarativeNetRequestBrowserTest.PageWhitelistingAPI_Resources/1
-
-# Sending invalid FrameSinkIds crbug.com/796999
--WebviewLoginTest.AllowNewUser
--EnterpriseEnrollmentTest.TestAuthCodeGetsProperlyReceivedFromGaia
--PowerPolicyLoginScreenBrowserTest.SetDevicePolicy
--EnterpriseEnrollmentTest.TestActiveDirectoryEnrollment_Success
-
-# HostedAppMenu needs porting to BrowserNonClientFrameViewMash crbug.com/813666
--HostedAppPWAOnlyTest.AppInfoOpensPageInfo*
-
-# DCHECK in DelegatedFrameHost
--SafeBrowsingTriggeredPopupBlockerBrowserTest.NoFeature_NoMessages
-
-# App list code flake: https://crbug.com/847154 https://crbug.com/843429
--MultiProfileFileManagerBrowserTest.*
-
-# Flaky segfaults: https://crbug.com/818147
--ExtensionApiTest.BookmarkManager
-
-# RenderFrameMetadata observation not supported: https://crbug.com/820974
--WebViewFocusBrowserPluginSpecificTest.*
--WebViewScrollBubbling/WebViewGuestScrollTest.ScrollLatchingPreservedInGuests/*
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.*
--WebViewScrollGuestContentBrowserPluginSpecificTest.OverscrollControllerSeesConsumedScrollsInGuest
--WebViewScrollBubbling/WebViewGuestScrollTest.TestGuestWheelScrollsBubble/*
-
-# https://crbug.com/843760: webm in <object> triggers RegisterFrameSinkId crash
--*SavePageOriginalVsSavedComparisonTest.CrossSiteObject*
-
-# DisplayPrefs need to be loaded synchronously, which currently is not
-# supported in mash. crbug/834775
--DisplayPrefsBrowserTest.*
-
-# Picture-in-Picture does not work with mash because VideoSurfaceLayer is
-# disabled.
-# https://crbug.com/827327
--PictureInPictureWindowControllerBrowserTest.*
--BrowserActionApiTest.TestPictureInPictureOnBrowserActionIconClick
--PlatformAppBrowserTest.PictureInPicture
--PictureInPictureLazyBackgroundPageApiTest.PictureInPictureInBackgroundPage
-
-# Has become super flaky on linux-chromeos-rel bot. Note that the test itself
-# is also flaky on Windows and Mac even without "mash":
-# https://crbug.com/671891
--SiteDetailsBrowserTest.IsolateExtensions
-
-# Often timing out. https://crbug.com/899860
--TopControlsSlideControllerTest.*
-
-# Crashing. https://crbug.com/899864
--ExtensionDialogBoundsTest.*
-
-# Crashing. https://crbug.com/899865
--MemoryTracingBrowserTest.TestMemoryInfra
-
-# Use of Shell. https://crbug.com/899869
--AutotestPrivateApiTest.AutotestPrivate
-
-# https://crbug.com/918876
--SwitchAccessPredicateTest.IsActionableFocusableElements
-
-# Flaky. https://crbug.com/919256
--PDFAnnotationsTest.AnnotationsFeatureEnabled
-
-# See comment at top of file regarding adding test exclusions.
diff --git a/testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter b/testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter
deleted file mode 100644
index b91a9b4..0000000
--- a/testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter
+++ /dev/null
@@ -1,112 +0,0 @@
-# These tests currently fail with SingleProcessMash enabled.
-# Bug: crbug.com/883523
-
-# TODO(sky): this now fails because of differences in timing. In particular,
-# in classic mode an accelerator that moves focus is processed *after* text
-# is inserted, where as now the accelerator runs first, resulting in text
-# going to the wrong place. The right fix likely entails updating the test for
-# ChromeOS.
--BrowserKeyEventsTest.AccessKeys
-
-# Broken tests related to accessibility. crbug.com/888750 and crbug.com/889093
--GuestSpokenFeedbackTest.FocusToolbar
--LoggedInSpokenFeedbackTest.KeyboardShortcutViewer
--MagnificationControllerTest.FollowFocusOnWebButtonContained
--MagnificationControllerTest.FollowFocusOnWebPageButtonIntersected
--MagnificationControllerTest.FollowFocusOnWebPageButtonNotIntersected
--SelectToSpeakTest.ActivatesWithTapOnSelectToSpeakTray
--SelectToSpeakTest.BreaksAtParagraphBounds
--SelectToSpeakTest.ContinuesReadingDuringResize
--SelectToSpeakTest.FocusRingMovesWithMouse
--SelectToSpeakTest.ReadsStaticTextWithoutInlineTextChildren
--SelectToSpeakTest.SelectToSpeakTrayNotSpoken
--SelectToSpeakTest.SmoothlyReadsAcrossFormattedText
--SelectToSpeakTest.SmoothlyReadsAcrossInlineUrl
--SelectToSpeakTest.SmoothlyReadsAcrossMultipleLines
--SelectToSpeakTest.SpeakStatusTray
--SelectToSpeakTest.WorksWithStickyKeys
--StickyKeysBrowserTest.CtrlClickHomeButton
--StickyKeysBrowserTest.OpenNewTabs
--StickyKeysBrowserTest.OpenTrayMenu
--StickyKeysBrowserTest.OverlayShown
--StickyKeysBrowserTest.SearchLeftOmnibox
--SwitchAccessTest.IgnoresVirtualKeyEvents
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.DisabledFullscreenExpandButton/0
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.DisabledFullscreenExpandButton/1
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.FullscreenLauncherFocusTraversal/0
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.FullscreenLauncherFocusTraversal/1
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.LauncherStateTransition/0
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.LauncherStateTransition/1
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.FullscreenLauncherFocusTraversal/0
--TestAsNormalAndGuestUser/SpokenFeedbackAppListTest.FullscreenLauncherFocusTraversal/1
--TestAsNormalAndGuestUser/SpokenFeedbackTest.ChromeVoxNextTabRecovery/0
--TestAsNormalAndGuestUser/SpokenFeedbackTest.ChromeVoxNextTabRecovery/1
--TestAsNormalAndGuestUser/SpokenFeedbackTest.ChromeVoxShiftSearch/0
--TestAsNormalAndGuestUser/SpokenFeedbackTest.ChromeVoxShiftSearch/1
--TestAsNormalAndGuestUser/SpokenFeedbackTest.FocusShelf/0
--TestAsNormalAndGuestUser/SpokenFeedbackTest.FocusShelf/1
--TestAsNormalAndGuestUser/SpokenFeedbackTest.FocusToolbar/0
--TestAsNormalAndGuestUser/SpokenFeedbackTest.FocusToolbar/1
--TestAsNormalAndGuestUser/SpokenFeedbackTest.OpenStatusTray/0
--TestAsNormalAndGuestUser/SpokenFeedbackTest.OpenStatusTray/1
--TestAsNormalAndGuestUser/SpokenFeedbackTest.OverviewMode/0
--TestAsNormalAndGuestUser/SpokenFeedbackTest.OverviewMode/1
-
-# This test is flaky. https://crbug.com/897879
--ExtensionApiTest.DisplayModeWindowIsInFullscreen
-
-# Those tests seems failing on focus-related.
--BrowserFocusTest.ClickingMovesFocus
--BrowserFocusTest.FindFocusTest
--LocalNTPUITest.FakeboxRedirectsToOmnibox
--OmniboxViewViewsTest.DeactivateTouchEditingOnExecuteCommand
--OmniboxViewViewsTest.SelectAllOnClick
--OmniboxViewViewsTest.SelectAllOnTap
--OmniboxViewViewsTest.TextElideStatus
--WebViewFocusInteractiveTest.FrameInGuestWontStealFocus
-
-# screen lock
--ScreenLockerTest.TestBasic
--ScreenLockerTest.TestShowTwice
-
-# Access of ash::Shell.
--DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest.CancelDragTabToWindowIn1stDisplay
--DetachToBrowserInSeparateDisplayAndCancelTabDragControllerTest.CancelDragTabToWindowIn2ndDisplay
--LoginCursorTest.CursorHidden
--LoginGuestTest.GuestIsOTR
--LoginUserTest.UserPassed
--OobeDisplayChooserTest.RemovingPrimaryDisplaySanityCheck
--TabScrubberTest.Bounds
--TabScrubberTest.CloseBrowser
--TabScrubberTest.DeleteBeforeHighlighted
--TabScrubberTest.DeleteHighlighted
--TabScrubberTest.FullScreenBrowser
--TabScrubberTest.MoveAfter
--TabScrubberTest.MoveBefore
--TabScrubberTest.MoveHighlighted
--TabScrubberTest.Multi
--TabScrubberTest.MultiBrowser
--TabScrubberTest.NoChange
--TabScrubberTest.RTLMoveBefore
--TabScrubberTest.RTLMulti
--TabScrubberTest.RTLSkipped
--TabScrubberTest.Repeated
--TabScrubberTest.Single
--TabScrubberTest.Skipped
--WindowSizerTest.OpenBrowserUsingContextMenu
--WindowSizerTest.OpenBrowserUsingShelfItem
-
-# timeout on ExtensionTestManagerListener::WaitUntilSatisfied
--ClipboardExtensionApiTest.ClipboardDataChanged
--ClipboardExtensionApiTest.SetImageData
-
-# MouseEventsTest
--MouseEventsTest.ClickAndDoubleClick
--MouseEventsTest.ContextMenu
--MouseEventsTest.MouseOver
-
-# CrashInFlightChange::ChangeFailed()
--FlashFullscreenInteractiveBrowserTest.FullscreenWithinTab_EscapeKeyExitsFullscreen
-
-#Flaky https://crbug.com/933847
--LocationIconViewTest.HideOnSecondClick
diff --git a/testing/buildbot/filters/fuchsia.gfx_unittests.filter b/testing/buildbot/filters/fuchsia.gfx_unittests.filter
new file mode 100644
index 0000000..5864370
--- /dev/null
+++ b/testing/buildbot/filters/fuchsia.gfx_unittests.filter
@@ -0,0 +1,18 @@
+# https://crbug.com/952652 - Fail due to missing fonts.
+-FontListTest.FirstAvailableOrFirst
+-FontListTest.Fonts_*
+-FontTest.LoadArial*
+-FontTest.GetActualFontNameForTesting
+-PlatformFontSkiaTest.DefaultFont
+-RenderTextTest.HarfBuzz_BreakRunsByEmojiVariationSelectors
+-RenderTextTest.HarfBuzz_FontListFallback
+-RenderTextTest.HarfBuzz_UnicodeFallback
+-RenderTextTest.SetFontList
+-RenderTextTest.StringSizeBoldWidth
+-RenderTextTest.StringSizeRespectsFontListMetrics
+-RenderTextTest.StylePropagated
+-RenderTextTest.SubpixelRenderingSuppressed
+-RenderTextTest.TextDoesntClip
+
+# https://crbug.com/952652 - GpuMemoryBufferHandle Mojo struct traits.
+-StructTraitsTest.GpuMemoryBufferHandle
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index badb76e6..d72385b 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -492,6 +492,12 @@
       },
     },
   },
+  'gfx_unittests': {
+    'remove_from': [
+      # chromium.linux
+      'Fuchsia x64',  # https://crbug.com/952652
+    ],
+  },
   'gin_unittests': {
     'remove_from': [
       # chromium.clang
@@ -1032,40 +1038,6 @@
       },
     },
   },
-  'non_single_process_mash_browser_tests': {
-    'modifications': {
-      # chromium.fyi
-      'linux-chromeos-code-coverage': {
-        'swarming': {
-          'shards': 20,
-        },
-      },
-      'linux-chromeos-oobe-code-coverage': {
-        'swarming': {
-          'shards': 20,
-        },
-      },
-      # chromium.chromiumos
-      'linux-chromeos-dbg': {
-        'swarming': {
-          'shards': 20,
-        },
-      },
-      # chromium.memory
-      'Linux Chromium OS ASan LSan Tests (1)': {
-        # These are very slow on the ASAN trybot for some reason.
-        # crbug.com/794372
-        'swarming': {
-          'shards': 30,
-        },
-      },
-      'Linux ChromiumOS MSan Tests': {
-        'swarming': {
-          'shards': 20,
-        },
-      },
-    },
-  },
   'not_site_per_process_webkit_layout_tests': {
     'remove_from': [
       # chromium.linux
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index bf9ec81..c9e7331 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -283,17 +283,11 @@
 
     'chromeos_device_friendly_gtests_experimental': {
       'chrome_all_tast_tests': {
-        'args': [
-          '--use-host-tast-bin',
-        ],
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         }
       },
       'chrome_login_tast_tests': {
-        'args': [
-          '--use-host-tast-bin',
-        ],
         'swarming': {
           'idempotent': False,  # https://crbug.com/923426#c27
         }
@@ -2647,6 +2641,11 @@
       'cronet_unittests': {},
       'crypto_unittests': {},
       'fidlgen_js_unittests': {},
+      'gfx_unittests': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.gfx_unittests.filter',
+        ],
+      },
       'gpu_unittests': {},
       'http_service_tests': {},
       'ipc_tests': {},
@@ -3623,19 +3622,6 @@
       'exo_unittests': {},
       'gl_unittests_ozone': {},
       'keyboard_unittests': {},
-      'mash_browser_tests': {
-        'test': 'browser_tests',
-        'args': [
-          '--enable-features=Mash',
-          '--disable-features=SingleProcessMash',
-          '--override-use-software-gl-for-tests',
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.browser_tests.filter',
-        ],
-        'swarming': {
-          'hard_timeout': 1800,
-          'shards': 1,
-        },
-      },
       'ozone_gl_unittests': {
         'args': [
           '--ozone-platform=headless',
@@ -3643,59 +3629,6 @@
       },
       'ozone_unittests': {},
       'ozone_x11_unittests': {},
-      'non_single_process_mash_ash_unittests': {
-        'test': 'ash_unittests',
-        'args': [
-          '--disable-features=SingleProcessMash',
-        ],
-      },
-      'non_single_process_mash_browser_tests': {
-        'test': 'browser_tests',
-        'args': [
-          '--disable-features=SingleProcessMash',
-          '--override-use-software-gl-for-tests'
-        ],
-        'swarming': {
-          'shards': 10,
-        },
-      },
-      'non_single_process_mash_content_unittests': {
-        'test': 'content_unittests',
-        'args': [
-          '--disable-features=SingleProcessMash',
-        ],
-      },
-      'non_single_process_mash_content_browsertests': {
-        'test': 'content_browsertests',
-        'args': [
-          '--disable-features=SingleProcessMash',
-          '--override-use-software-gl-for-tests'
-        ],
-        'swarming': {
-          'shards': 5,
-        },
-      },
-      'non_single_process_mash_exo_unittests': {
-        'test': 'exo_unittests',
-        'args': [
-          '--disable-features=SingleProcessMash',
-        ],
-      },
-      'non_single_process_mash_interactive_ui_tests': {
-        'test': 'interactive_ui_tests',
-        'args': [
-          '--disable-features=SingleProcessMash'
-        ],
-        'swarming': {
-          'shards': 3,
-        },
-      },
-      'non_single_process_mash_unit_tests': {
-        'test': 'unit_tests',
-        'args': [
-          '--disable-features=SingleProcessMash'
-        ],
-      },
       'ui_chromeos_unittests': {},
       'usage_time_limit_unittests': {
         'experiment_percentage': 100,
@@ -3765,40 +3698,6 @@
     },
 
 
-    'mash_fyi_chromium_gtests': {
-      'mash_fyi_browser_tests': {
-        'test': 'browser_tests',
-        'args': [
-          '--enable-features=Mash',
-          '--disable-features=SingleProcessMash',
-          '--override-use-software-gl-for-tests',
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.fyi.browser_tests.filter',
-        ],
-        'swarming': {
-          'hard_timeout': 1800,
-          'shards': 10,
-        },
-      },
-      'mash_fyi_content_unittests': {
-        'test': 'content_unittests',
-        'args': [
-          '--enable-features=Mash',
-          '--disable-features=SingleProcessMash',
-        ],
-      },
-      'mash_fyi_interactive_ui_tests': {
-        'test': 'interactive_ui_tests',
-        'args': [
-          '--enable-features=Mash',
-          '--disable-features=SingleProcessMash',
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter',
-        ],
-        'swarming': {
-          'shards': 3,
-        },
-      }
-    },
-
     'memory_infra_isolated_scripts': {
       'heap_profiling.mobile': {
         'args': [
@@ -4781,7 +4680,6 @@
       'gpu_angle_unit_gtests',
       'gpu_angle_white_box_gtests',
       'gpu_common_gtests',
-      'gpu_dawn_gtests',
       'gpu_fyi_vulkan_gtests',
       'gpu_gles2_conform_gtests',
       'gpu_swiftshader_gtests',
@@ -4800,7 +4698,6 @@
     'gpu_fyi_linux_optional_gtests': [
       'gpu_angle_end2end_gtests',
       'gpu_angle_white_box_gtests',
-      'gpu_dawn_gtests',
       'gpu_fyi_vulkan_gtests',
       'gpu_gles2_conform_gtests',
       'gpu_swiftshader_gtests',
@@ -4811,7 +4708,6 @@
       'gpu_angle_unit_gtests',
       'gpu_angle_white_box_gtests',
       'gpu_common_gtests',
-      'gpu_dawn_gtests',
       'gpu_desktop_specific_gtests',
       'gpu_fyi_vulkan_gtests',
       'gpu_gles2_conform_gtests',
@@ -4822,7 +4718,6 @@
       'gpu_angle_end2end_gtests',
       'gpu_angle_unit_gtests',
       'gpu_common_gtests',
-      'gpu_dawn_gtests',
       'gpu_fyi_and_optional_non_linux_gtests',
       'gpu_fyi_mac_specific_gtests',
       'gpu_gles2_conform_gtests',
@@ -4831,7 +4726,6 @@
 
     'gpu_fyi_mac_optional_gtests': [
       'gpu_angle_end2end_gtests',
-      'gpu_dawn_gtests',
       'gpu_fyi_and_optional_non_linux_gtests',
       'gpu_fyi_mac_specific_gtests',
       'gpu_gles2_conform_gtests',
@@ -4842,7 +4736,6 @@
       'gpu_angle_end2end_gtests',
       'gpu_angle_unit_gtests',
       'gpu_common_gtests',
-      'gpu_dawn_gtests',
       'gpu_desktop_specific_gtests',
       'gpu_fyi_and_optional_non_linux_gtests',
       'gpu_fyi_mac_specific_gtests',
@@ -4936,7 +4829,6 @@
       'gpu_angle_unit_gtests',
       'gpu_angle_white_box_gtests',
       'gpu_common_gtests',
-      'gpu_dawn_gtests',
       'gpu_default_and_optional_win_specific_gtests',
       'gpu_desktop_specific_gtests',
       'gpu_fyi_and_optional_non_linux_gtests',
@@ -4962,7 +4854,6 @@
     'gpu_fyi_win_optional_gtests': [
       'gpu_angle_end2end_gtests',
       'gpu_angle_white_box_gtests',
-      'gpu_dawn_gtests',
       'gpu_default_and_optional_win_specific_gtests',
       'gpu_fyi_and_optional_non_linux_gtests',
       'gpu_fyi_and_optional_win_specific_gtests',
@@ -5091,7 +4982,6 @@
 
     'mojo_chromiumos_fyi_gtests': [
       'aura_gtests',
-      'mash_fyi_chromium_gtests',
       'mojo_chromiumos_specific_gtests',
       'network_service_gtests',
       'viz_chromeos_fyi_gtests',
diff --git a/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json b/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json
new file mode 100644
index 0000000..a5bf1628
--- /dev/null
+++ b/testing/scripts/representative_perf_test_data/representatives_frame_times_upper_limit.json
@@ -0,0 +1,45 @@
+{
+  "win": {
+    "css_value_type_shadow": 33.30775,
+    "yahoo_sports_2018": 18.20989,
+    "mix_10k": 461.59862,
+    "microsoft_fish_ie_tank": 19.00327225,
+    "css_animations_staggered_infinite_iterations": 16.68411,
+    "pinterest_2018": 19.0722844,
+    "background_color_animation_with_gradient": 24.91983336,
+    "motion_mark_canvas_fill_shapes": 31.59578218,
+    "particles": 16.7502048,
+    "second_batch_js_light": 18.46476,
+    "microsoft_video_city": 18.01405,
+    "infinite_scroll_root_fixed_n_layers_99": 17.95172,
+    "css_value_type_length_complex": 38.44199,
+    "css_opacity_plus_n_layers_99": 16.681,
+    "canvas_90000_pixels_per_second": 18.09894,
+    "google_web_search_2018": 17.33381844,
+    "aquarium": 16.684
+  },
+  "mac": {
+    "yuv_decoding": 50.90241,
+    "canvas_animation_no_clear": 45.635,
+    "compositor_heavy_animation": 38.55816,
+    "web_animation_value_type_length_3d": 39.5491,
+    "stroke_shapes": 57.83637,
+    "wordpress_2018": 32.75465,
+    "web_animation_value_type_path": 43.3278,
+    "web_animations_many_keyframes": 30.47611,
+    "twitter_pinch_2018": 37.893,
+    "web_animation_value_type_length_complex": 54.9078,
+    "smash_cat": 52.30218,
+    "cc_poster_circle": 36.9494588,
+    "infinite_scroll_root_fixed_n_layers_99": 28.3575593,
+    "amazon_pinch_2018": 30.332,
+    "youtube_pinch_2018": 40.28703,
+    "earth": 63.3204628,
+    "css_value_type_shadow": 58.59559,
+    "js_opacity_plus_n_layers_99": 56.53884,
+    "fill_shapes": 30.02325,
+    "raf": 35.76062,
+    "canvas_lines": 41.84306,
+    "megi_dish": 83.855
+  }
+}
\ No newline at end of file
diff --git a/testing/scripts/run_performance_tests.py b/testing/scripts/run_performance_tests.py
index 02974bb..f4a5d1b 100755
--- a/testing/scripts/run_performance_tests.py
+++ b/testing/scripts/run_performance_tests.py
@@ -114,6 +114,16 @@
   def logs(self):
     return os.path.join(self.benchmark_path, 'benchmark_log.txt')
 
+  @property
+  def csv_perf_results(self):
+    """Path for csv perf results.
+
+    Note that the chrome.perf waterfall uses the json histogram perf results
+    exclusively. csv_perf_results are implemented here in case a user script
+    passes --output-format=csv.
+    """
+    return os.path.join(self.benchmark_path, 'perf_results.csv')
+
 
 def print_duration(step, start):
   print 'Duration of %s: %d seconds' % (step, time.time() - start)
@@ -297,8 +307,7 @@
   def _generate_reference_build_args(self):
     if self._is_reference:
       return ['--browser=reference',
-              '--max-failures=5',
-              '--output-trace-tag=_ref']
+              '--max-failures=5']
     return []
 
 
@@ -327,6 +336,10 @@
     shutil.move(expected_perf_filename, output_paths.perf_results)
     expected_results_filename = os.path.join(temp_dir, 'test-results.json')
     shutil.move(expected_results_filename, output_paths.test_results)
+
+    csv_file_path = os.path.join(temp_dir, 'results.csv')
+    if os.path.isfile(csv_file_path):
+      shutil.move(csv_file_path, output_paths.csv_perf_results)
   except Exception:
     print ('The following exception may have prevented the code from '
            'outputing structured test results and perf results output:')
@@ -394,8 +407,8 @@
   return options
 
 
-def main():
-  args = sys.argv[1:]  # Skip program name.
+def main(sys_args):
+  args = sys_args[1:]  # Skip program name.
   options = parse_arguments(args)
   isolated_out_dir = os.path.dirname(options.isolated_script_test_output)
   overall_return_code = 0
@@ -514,4 +527,4 @@
       'compile_targets': main_compile_targets,
     }
     sys.exit(common.run_script(sys.argv[1:], funcs))
-  sys.exit(main())
+  sys.exit(main(sys.argv))
\ No newline at end of file
diff --git a/testing/scripts/run_rendering_benchmark_with_gated_performance.py b/testing/scripts/run_rendering_benchmark_with_gated_performance.py
new file mode 100755
index 0000000..075d345
--- /dev/null
+++ b/testing/scripts/run_rendering_benchmark_with_gated_performance.py
@@ -0,0 +1,171 @@
+#!/usr/bin/env python
+# 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.
+
+"""Runs telemetry benchmarks on representative story tag.
+
+This script is a wrapper around run_performance_tests.py to capture the
+values of performance metrics and compare them with the acceptable limits
+in order to prevent regressions.
+
+Arguments used for this script are the same as run_performance_tests.py.
+
+The name and some functionalities of this script should be adjusted for
+use with other benchmarks.
+"""
+
+import argparse
+import csv
+import json
+import os
+import sys
+import time
+
+import common
+import run_performance_tests
+
+BENCHMARK = 'rendering.desktop'
+ERROR_MARGIN = 2.0
+
+class ResultRecorder(object):
+  def __init__(self):
+    self.fails = 0
+    self.tests = 0
+    self.start_time = time.time()
+    self.output = {}
+    self.return_code = 0
+
+  def setTests(self, output, testNum):
+    self.output = output
+    self.tests = testNum
+    self.fails = 0
+    if 'FAIL' in output['num_failures_by_type']:
+      self.fails = output['num_failures_by_type']['FAIL']
+
+  def addFailure(self, name):
+    self.output['tests'][BENCHMARK][name]['actual'] = 'FAIL'
+    self.output['tests'][BENCHMARK][name]['is_unexpected'] = True
+    self.fails += 1
+
+  def getOutput(self, return_code):
+    self.output['seconds_since_epoch'] = time.time() - self.start_time
+    self.output['num_failures_by_type']['PASS'] = self.tests - self.fails
+    if self.fails > 0:
+      self.output['num_failures_by_type']['FAIL'] = self.fails
+    if return_code == 1:
+      self.output["interrupted"] = True
+
+    if self.fails == 0:
+      print "[  PASSED  ] " + str(self.tests) + " tests."
+    else:
+      print "[  FAILED  ] " + str(self.fails) + "/" + str(self.tests)+ " tests."
+      self.return_code = 1
+
+    return (self.output, self.return_code)
+
+  def setAllToFail(self):
+    self.fails = self.tests
+
+def main():
+  overall_return_code = 0
+
+  # Linux does not have it's own specific representatives
+  # and uses the representatives chosen for winodws.
+  if sys.platform == 'win32':
+    platform = 'win'
+    story_tag = 'representative_win_desktop'
+  elif sys.platform == 'darwin':
+    platform = 'mac'
+    story_tag = 'representative_mac_desktop'
+  else:
+    return 1
+
+  options = parse_arguments()
+  args = sys.argv
+  args.extend(['--story-tag-filter', story_tag])
+
+  overall_return_code = run_performance_tests.main(args)
+  result_recorder = ResultRecorder()
+
+  # The values used as the upper limit are the 99th percentile of the
+  # average frame_times recorded by dashboard in the past 400 revisions.
+  # If the value measured here would be higher than this value at least by
+  # 2ms [ERROR_MARGIN], that would be considered a failure.
+  # crbug.com/953895
+  with open(
+    os.path.join(os.path.dirname(__file__),
+    'representative_perf_test_data',
+    'representatives_frame_times_upper_limit.json')
+  ) as bound_data:
+    frame_times_upper_limit = json.load(bound_data)
+
+  out_dir_path = os.path.dirname(options.isolated_script_test_output)
+  test_count = len(frame_times_upper_limit[platform])
+
+  output_path = os.path.join(out_dir_path, BENCHMARK, 'test_results.json')
+
+  with open(output_path, 'r+') as resultsFile:
+    initialOut = json.load(resultsFile)
+    result_recorder.setTests(initialOut, test_count)
+
+    results_path = os.path.join(out_dir_path, BENCHMARK, 'perf_results.csv')
+    marked_stories = set()
+    with open(results_path) as csv_file:
+      reader = csv.DictReader(csv_file)
+      for row in reader:
+        # For now only frame_times is used for testing representatives'
+        # performance.
+        if row['name'] != 'frame_times':
+          continue
+        story_name = row['stories']
+        if (story_name in marked_stories or story_name not in
+          frame_times_upper_limit[platform]):
+          continue
+        marked_stories.add(story_name)
+        if row['avg'] == '' or row['count'] == 0:
+          print "No values for " + story_name
+          result_recorder.addFailure(story_name)
+        elif (float(row['avg']) >
+          frame_times_upper_limit[platform][story_name] + ERROR_MARGIN):
+          print (story_name + ": average frame_times is higher than 99th " +
+            "percentile of the past 400 recorded frame_times(" +
+            row['avg'] + ")")
+          result_recorder.addFailure(story_name)
+
+    (
+      finalOut,
+      overall_return_code
+    ) = result_recorder.getOutput(overall_return_code)
+
+    # Clearing the result of run_benchmark and write the gated perf results
+    resultsFile.seek(0)
+    resultsFile.truncate(0)
+    json.dump(finalOut, resultsFile, indent=4)
+
+    with open(options.isolated_script_test_output, 'w') as outputFile:
+      json.dump(finalOut, outputFile, indent=4)
+
+  return overall_return_code
+
+def parse_arguments():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('executable', help='The name of the executable to run.')
+  parser.add_argument(
+      '--isolated-script-test-output', required=True)
+  parser.add_argument(
+      '--isolated-script-test-perf-output', required=False)
+  return parser.parse_known_args()[0]
+
+def main_compile_targets(args):
+  json.dump([], args.output)
+
+if __name__ == '__main__':
+  # Conform minimally to the protocol defined by ScriptTest.
+  if 'compile_targets' in sys.argv:
+    funcs = {
+      'run': None,
+      'compile_targets': main_compile_targets,
+    }
+    sys.exit(common.run_script(sys.argv[1:], funcs))
+  sys.exit(main())
\ No newline at end of file
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 178eb94..588ecfd 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -3178,21 +3178,6 @@
             ]
         }
     ],
-    "NoCreditCardAbort": [
-        {
-            "platforms": [
-                "android"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "NoCreditCardAbort"
-                    ]
-                }
-            ]
-        }
-    ],
     "NoSearchDomainCheck": [
         {
             "platforms": [
@@ -3731,6 +3716,21 @@
             ]
         }
     ],
+    "PaymentRequestNoCreditCardAbort": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NoCreditCardAbort"
+                    ]
+                }
+            ]
+        }
+    ],
     "PdfIsolation": [
         {
             "platforms": [
@@ -4981,36 +4981,6 @@
             ]
         }
     ],
-    "SyncPseudoUss'": [
-        {
-            "platforms": [
-                "android",
-                "chromeos",
-                "ios",
-                "linux",
-                "mac",
-                "windows"
-            ],
-            "experiments": [
-                {
-                    "name": "Enabled",
-                    "enable_features": [
-                        "SyncPseudoUSSAppList",
-                        "SyncPseudoUSSApps",
-                        "SyncPseudoUSSDictionary",
-                        "SyncPseudoUSSExtensions",
-                        "SyncPseudoUSSFavicons",
-                        "SyncPseudoUSSHistoryDeleteDirectives",
-                        "SyncPseudoUSSPreferences",
-                        "SyncPseudoUSSPriorityPreferences",
-                        "SyncPseudoUSSSearchEngines",
-                        "SyncPseudoUSSSupervisedUsers",
-                        "SyncPseudoUSSThemes"
-                    ]
-                }
-            ]
-        }
-    ],
     "SyncScryptCustomPassphrase": [
         {
             "platforms": [
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 01a4ec7..f561f7d 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -48,6 +48,10 @@
 const base::Feature kFreezePurgeMemoryAllPagesFrozen{
     "FreezePurgeMemoryAllPagesFrozen", base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Freezes the user-agent as part of https://github.com/WICG/ua-client-hints.
+const base::Feature kFreezeUserAgent{"FreezeUserAgent",
+                                     base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables the experimental sweep-line algorithm for tracking "jank" from
 // layout objects changing their visual location between animation frames.
 const base::Feature kJankTrackingSweepLine{"JankTrackingSweepLine",
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index a586c2b..3cafc1d 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -130,7 +130,6 @@
     "platform/modules/background_fetch/web_background_fetch_registration.h",
     "platform/modules/indexeddb/web_idb_database_exception.h",
     "platform/modules/installedapp/web_related_application.h",
-    "platform/modules/installedapp/web_related_apps_fetcher.h",
     "platform/modules/media_capabilities/web_audio_configuration.h",
     "platform/modules/media_capabilities/web_media_capabilities_callbacks.h",
     "platform/modules/media_capabilities/web_media_capabilities_client.h",
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h
index 4a13ca9..736d41c 100644
--- a/third_party/blink/public/common/features.h
+++ b/third_party/blink/public/common/features.h
@@ -22,6 +22,7 @@
 BLINK_COMMON_EXPORT extern const base::Feature kUserLevelMemoryPressureSignal;
 BLINK_COMMON_EXPORT extern const base::Feature kFirstContentfulPaintPlusPlus;
 BLINK_COMMON_EXPORT extern const base::Feature kFreezePurgeMemoryAllPagesFrozen;
+BLINK_COMMON_EXPORT extern const base::Feature kFreezeUserAgent;
 BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller;
 BLINK_COMMON_EXPORT extern const base::Feature kJankTrackingSweepLine;
 BLINK_COMMON_EXPORT extern const base::Feature kBlinkGenPropertyTrees;
diff --git a/third_party/blink/public/platform/modules/installedapp/web_related_apps_fetcher.h b/third_party/blink/public/platform/modules/installedapp/web_related_apps_fetcher.h
deleted file mode 100644
index 2f34998..0000000
--- a/third_party/blink/public/platform/modules/installedapp/web_related_apps_fetcher.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INSTALLEDAPP_WEB_RELATED_APPS_FETCHER_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INSTALLEDAPP_WEB_RELATED_APPS_FETCHER_H_
-
-#include "base/callback.h"
-#include "third_party/blink/public/platform/modules/installedapp/web_related_application.h"
-#include "third_party/blink/public/platform/web_security_origin.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-#include <memory>
-
-namespace blink {
-
-using GetManifestRelatedApplicationsCallback =
-    base::OnceCallback<void(const WebVector<WebRelatedApplication>&)>;
-
-class WebRelatedAppsFetcher {
- public:
-  virtual ~WebRelatedAppsFetcher() = default;
-
-  // Gets the list of related applications from the web frame's manifest.
-  virtual void GetManifestRelatedApplications(
-      GetManifestRelatedApplicationsCallback) = 0;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_INSTALLEDAPP_WEB_RELATED_APPS_FETCHER_H_
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index d104f6c..0d19ca0 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1733,81 +1733,10 @@
   testonly = true
   sources = [
     "content_capture/content_capture_test.cc",
-    "css/active_style_sheets_test.cc",
-    "css/affected_by_pseudo_test.cc",
-    "css/css_calculation_value_test.cc",
-    "css/css_computed_style_declaration_test.cc",
-    "css/css_font_face_source_test.cc",
-    "css/css_gradient_value_test.cc",
-    "css/css_invalid_variable_value_test.cc",
-    "css/css_page_rule_test.cc",
-    "css/css_paint_value_test.cc",
-    "css/css_primitive_value_test.cc",
-    "css/css_property_name_test.cc",
-    "css/css_property_value_set_test.cc",
-    "css/css_selector_test.cc",
-    "css/css_selector_watch_test.cc",
-    "css/css_style_declaration_test.cc",
-    "css/css_style_sheet_test.cc",
-    "css/css_syntax_string_parser_test.cc",
     "css/css_test_helpers.cc",
     "css/css_test_helpers.h",
     "css/css_uri_value_test.cc",
     "css/css_value_test_helper.h",
-    "css/cssom/cross_thread_style_value_test.cc",
-    "css/cssom/css_math_invert_test.cc",
-    "css/cssom/css_math_negate_test.cc",
-    "css/cssom/css_numeric_value_type_test.cc",
-    "css/cssom/css_resource_value_test.cc",
-    "css/cssom/css_style_image_value_test.cc",
-    "css/cssom/css_unit_value_test.cc",
-    "css/cssom/css_unparsed_value_test.cc",
-    "css/cssom/paint_worklet_style_property_map_test.cc",
-    "css/cssom/prepopulated_computed_style_property_map_test.cc",
-    "css/drag_update_test.cc",
-    "css/font_face_cache_test.cc",
-    "css/invalidation/invalidation_set_test.cc",
-    "css/invalidation/pending_invalidations_test.cc",
-    "css/media_query_evaluator_test.cc",
-    "css/media_query_list_test.cc",
-    "css/media_query_matcher_test.cc",
-    "css/media_query_set_test.cc",
-    "css/media_values_initial_viewport_test.cc",
-    "css/media_values_test.cc",
-    "css/parser/css_lazy_parsing_test.cc",
-    "css/parser/css_parser_fast_paths_test.cc",
-    "css/parser/css_parser_local_context_test.cc",
-    "css/parser/css_parser_token_stream_test.cc",
-    "css/parser/css_parser_token_test.cc",
-    "css/parser/css_property_parser_test.cc",
-    "css/parser/css_selector_parser_test.cc",
-    "css/parser/css_tokenizer_test.cc",
-    "css/parser/media_condition_test.cc",
-    "css/parser/sizes_attribute_parser_test.cc",
-    "css/parser/sizes_calc_parser_test.cc",
-    "css/properties/css_parsing_utils_test.cc",
-    "css/properties/css_property_ref_test.cc",
-    "css/properties/longhands/custom_property_test.cc",
-    "css/resolver/css_variable_data_test.cc",
-    "css/resolver/css_variable_resolver_test.cc",
-    "css/resolver/font_builder_test.cc",
-    "css/resolver/font_style_resolver_test.cc",
-    "css/resolver/match_result_test.cc",
-    "css/resolver/selector_filter_parent_scope_test.cc",
-    "css/resolver/style_adjuster_test.cc",
-    "css/rule_feature_set_test.cc",
-    "css/rule_set_test.cc",
-    "css/selector_query_test.cc",
-    "css/style_element_test.cc",
-    "css/style_engine_test.cc",
-    "css/style_environment_variables_test.cc",
-    "css/style_sheet_contents_test.cc",
-    "css/style_traversal_root_test.cc",
-    "css/threaded/css_parser_threaded_test.cc",
-    "css/threaded/css_to_length_conversion_data_threaded_test.cc",
-    "css/threaded/filter_operation_resolver_threaded_test.cc",
-    "css/threaded/font_object_threaded_test.cc",
-    "css/threaded/text_renderer_threaded_test.cc",
     "display_lock/display_lock_budget_test.cc",
     "display_lock/display_lock_context_test.cc",
     "display_lock/display_lock_utilities_test.cc",
@@ -2278,6 +2207,7 @@
     "//third_party/blink/renderer/core/accessibility:unit_tests",
     "//third_party/blink/renderer/core/animation:unit_tests",
     "//third_party/blink/renderer/core/clipboard:unit_tests",
+    "//third_party/blink/renderer/core/css:unit_tests",
     "//third_party/blink/renderer/core/editing:unit_tests",
     "//third_party/blink/renderer/core/fileapi:unit_tests",
   ]
diff --git a/third_party/blink/renderer/core/css/BUILD.gn b/third_party/blink/renderer/core/css/BUILD.gn
index d284dd6d..4230eeae 100644
--- a/third_party/blink/renderer/core/css/BUILD.gn
+++ b/third_party/blink/renderer/core/css/BUILD.gn
@@ -557,3 +557,79 @@
     "zoom_adjusted_pixel_value.h",
   ]
 }
+
+blink_core_tests("unit_tests") {
+  sources = [
+    "active_style_sheets_test.cc",
+    "affected_by_pseudo_test.cc",
+    "css_calculation_value_test.cc",
+    "css_computed_style_declaration_test.cc",
+    "css_font_face_source_test.cc",
+    "css_gradient_value_test.cc",
+    "css_invalid_variable_value_test.cc",
+    "css_page_rule_test.cc",
+    "css_paint_value_test.cc",
+    "css_primitive_value_test.cc",
+    "css_property_name_test.cc",
+    "css_property_value_set_test.cc",
+    "css_selector_test.cc",
+    "css_selector_watch_test.cc",
+    "css_style_declaration_test.cc",
+    "css_style_sheet_test.cc",
+    "css_syntax_string_parser_test.cc",
+    "cssom/cross_thread_style_value_test.cc",
+    "cssom/css_math_invert_test.cc",
+    "cssom/css_math_negate_test.cc",
+    "cssom/css_numeric_value_type_test.cc",
+    "cssom/css_resource_value_test.cc",
+    "cssom/css_style_image_value_test.cc",
+    "cssom/css_unit_value_test.cc",
+    "cssom/css_unparsed_value_test.cc",
+    "cssom/paint_worklet_style_property_map_test.cc",
+    "cssom/prepopulated_computed_style_property_map_test.cc",
+    "drag_update_test.cc",
+    "font_face_cache_test.cc",
+    "invalidation/invalidation_set_test.cc",
+    "invalidation/pending_invalidations_test.cc",
+    "media_query_evaluator_test.cc",
+    "media_query_list_test.cc",
+    "media_query_matcher_test.cc",
+    "media_query_set_test.cc",
+    "media_values_initial_viewport_test.cc",
+    "media_values_test.cc",
+    "parser/css_lazy_parsing_test.cc",
+    "parser/css_parser_fast_paths_test.cc",
+    "parser/css_parser_local_context_test.cc",
+    "parser/css_parser_token_stream_test.cc",
+    "parser/css_parser_token_test.cc",
+    "parser/css_property_parser_test.cc",
+    "parser/css_selector_parser_test.cc",
+    "parser/css_tokenizer_test.cc",
+    "parser/media_condition_test.cc",
+    "parser/sizes_attribute_parser_test.cc",
+    "parser/sizes_calc_parser_test.cc",
+    "properties/css_parsing_utils_test.cc",
+    "properties/css_property_ref_test.cc",
+    "properties/longhands/custom_property_test.cc",
+    "resolver/css_variable_data_test.cc",
+    "resolver/css_variable_resolver_test.cc",
+    "resolver/font_builder_test.cc",
+    "resolver/font_style_resolver_test.cc",
+    "resolver/match_result_test.cc",
+    "resolver/selector_filter_parent_scope_test.cc",
+    "resolver/style_adjuster_test.cc",
+    "rule_feature_set_test.cc",
+    "rule_set_test.cc",
+    "selector_query_test.cc",
+    "style_element_test.cc",
+    "style_engine_test.cc",
+    "style_environment_variables_test.cc",
+    "style_sheet_contents_test.cc",
+    "style_traversal_root_test.cc",
+    "threaded/css_parser_threaded_test.cc",
+    "threaded/css_to_length_conversion_data_threaded_test.cc",
+    "threaded/filter_operation_resolver_threaded_test.cc",
+    "threaded/font_object_threaded_test.cc",
+    "threaded/text_renderer_threaded_test.cc",
+  ]
+}
diff --git a/third_party/blink/renderer/core/dom/container_node.cc b/third_party/blink/renderer/core/dom/container_node.cc
index 02f23c9..af3d21e 100644
--- a/third_party/blink/renderer/core/dom/container_node.cc
+++ b/third_party/blink/renderer/core/dom/container_node.cc
@@ -141,10 +141,9 @@
     Node& node,
     NodeVector& nodes,
     ExceptionState& exception_state) {
-  if (node.IsDocumentFragment()) {
-    DocumentFragment& fragment = ToDocumentFragment(node);
-    GetChildNodes(fragment, nodes);
-    fragment.RemoveChildren();
+  if (auto* fragment = DynamicTo<DocumentFragment>(node)) {
+    GetChildNodes(*fragment, nodes);
+    fragment->RemoveChildren();
     return !nodes.IsEmpty();
   }
   nodes.push_back(&node);
@@ -168,10 +167,11 @@
 
 DISABLE_CFI_PERF
 bool ContainerNode::IsChildTypeAllowed(const Node& child) const {
-  if (!child.IsDocumentFragment())
+  auto* child_fragment = DynamicTo<DocumentFragment>(child);
+  if (!child_fragment)
     return ChildTypeAllowed(child.getNodeType());
 
-  for (Node* node = ToDocumentFragment(child).firstChild(); node;
+  for (Node* node = child_fragment->firstChild(); node;
        node = node->nextSibling()) {
     if (!ChildTypeAllowed(node->getNodeType()))
       return false;
@@ -194,8 +194,8 @@
     child_contains_parent = new_child.ContainsIncludingHostElements(*this);
   } else {
     const Node& root = TreeRoot();
-    if (root.IsDocumentFragment() &&
-        ToDocumentFragment(root).IsTemplateContent()) {
+    auto* fragment = DynamicTo<DocumentFragment>(root);
+    if (fragment && fragment->IsTemplateContent()) {
       child_contains_parent = new_child.ContainsIncludingHostElements(*this);
     } else {
       child_contains_parent = new_child.contains(this);
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index c3e77bc..d55ab81d 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3439,8 +3439,35 @@
          AllDescendantsAreComplete(frame_);
 }
 
-void Document::Abort() {
-  CancelParsing();
+void Document::Abort(bool for_form_submission) {
+  // The spec says that form submissions should start navigating
+  // asynchronously, but we currently start the navigation immediately. This
+  // mostly works. However, starting a navigation entails aborting the current
+  // document (i.e., this function), and compatibility seems to require a very
+  // weird kind of abort for form submissions. In
+  // https://bugs.webkit.org/show_bug.cgi?id=45627, we concluded that form
+  // submission should synchronously cancel parsing, and added a regression test
+  // for that behavior in fast/loader/form-submit-aborts-parsing.html, However,
+  // https://crbug.com/955556 shows that a document.write() immediately after a
+  // form submission should not implicitly open() a new document, thus
+  // cancelling the form submission, as tested in
+  // fast/loader/document-write-after-form-submit.html. Firefox passes both
+  // these tests, so matching their behavior seems to make sense. It appears
+  // that, unlike other aborts, we don't want to hard-detach the parser, but
+  // want it to let it unwind slightly more gently. Therefore, call
+  // DocumentParser::StopParsing() and suppress the load event, instead of
+  // calling CancelParsing().
+  // TODO(japhet): This special case is designed to be mergeable to M75, but
+  // should be fixed before M76 branches.
+  if (for_form_submission) {
+    if (!LoadEventFinished())
+      load_event_progress_ = kLoadEventCompleted;
+    if (parser_)
+      parser_->StopParsing();
+    SetParsingState(kFinishedParsing);
+  } else {
+    CancelParsing();
+  }
   CheckCompletedInternal();
 }
 
@@ -4346,9 +4373,8 @@
   }
 
   // Then, see how many doctypes and elements might be added by the new child.
-  if (new_child.IsDocumentFragment()) {
-    for (Node& child :
-         NodeTraversal::ChildrenOf(ToDocumentFragment(new_child))) {
+  if (auto* new_child_fragment = DynamicTo<DocumentFragment>(new_child)) {
+    for (Node& child : NodeTraversal::ChildrenOf(*new_child_fragment)) {
       switch (child.getNodeType()) {
         case kAttributeNode:
         case kCdataSectionNode:
diff --git a/third_party/blink/renderer/core/dom/document.h b/third_party/blink/renderer/core/dom/document.h
index 0dd4904d..0b5bbb1 100644
--- a/third_party/blink/renderer/core/dom/document.h
+++ b/third_party/blink/renderer/core/dom/document.h
@@ -605,7 +605,7 @@
 
   // Corresponds to "9. Abort the active document of browsingContext."
   // https://html.spec.whatwg.org/C/#navigate
-  void Abort();
+  void Abort(bool for_form_submission);
 
   void CheckCompleted();
 
diff --git a/third_party/blink/renderer/core/dom/document_fragment.h b/third_party/blink/renderer/core/dom/document_fragment.h
index fd362515..00c2703b 100644
--- a/third_party/blink/renderer/core/dom/document_fragment.h
+++ b/third_party/blink/renderer/core/dom/document_fragment.h
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/dom/container_node.h"
 #include "third_party/blink/renderer/core/dom/parser_content_policy.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
 
 namespace blink {
 
@@ -60,7 +61,10 @@
       delete;  // This will catch anyone doing an unnecessary check.
 };
 
-DEFINE_NODE_TYPE_CASTS(DocumentFragment, IsDocumentFragment());
+template <>
+struct DowncastTraits<DocumentFragment> {
+  static bool AllowFrom(const Node& node) { return node.IsDocumentFragment(); }
+};
 
 }  // namespace blink
 
diff --git a/third_party/blink/renderer/core/dom/node.cc b/third_party/blink/renderer/core/dom/node.cc
index b6e2081d..ff0972046 100644
--- a/third_party/blink/renderer/core/dom/node.cc
+++ b/third_party/blink/renderer/core/dom/node.cc
@@ -1350,8 +1350,8 @@
   do {
     if (current == this)
       return true;
-    if (current->IsDocumentFragment() &&
-        ToDocumentFragment(current)->IsTemplateContent())
+    auto* curr_fragment = DynamicTo<DocumentFragment>(current);
+    if (curr_fragment && curr_fragment->IsTemplateContent())
       current =
           static_cast<const TemplateContentDocumentFragment*>(current)->Host();
     else
@@ -1602,7 +1602,8 @@
 }
 
 ContainerNode* Node::ParentOrShadowHostOrTemplateHostNode() const {
-  if (IsDocumentFragment() && ToDocumentFragment(this)->IsTemplateContent())
+  auto* this_fragment = DynamicTo<DocumentFragment>(this);
+  if (this_fragment && this_fragment->IsTemplateContent())
     return static_cast<const TemplateContentDocumentFragment*>(this)->Host();
   return ParentOrShadowHostNode();
 }
diff --git a/third_party/blink/renderer/core/frame/navigator.cc b/third_party/blink/renderer/core/frame/navigator.cc
index 71b32975..45b96233 100644
--- a/third_party/blink/renderer/core/frame/navigator.cc
+++ b/third_party/blink/renderer/core/frame/navigator.cc
@@ -58,10 +58,14 @@
 }
 
 String Navigator::platform() const {
+  // TODO(955620): Consider changing devtools overrides to only allow overriding
+  // the platform with a frozen platform to distinguish between
+  // mobile and desktop when FreezeUserAgent is enabled.
   if (GetFrame() &&
       !GetFrame()->GetSettings()->GetNavigatorPlatformOverride().IsEmpty()) {
     return GetFrame()->GetSettings()->GetNavigatorPlatformOverride();
   }
+
   return NavigatorID::platform();
 }
 
diff --git a/third_party/blink/renderer/core/frame/navigator_id.cc b/third_party/blink/renderer/core/frame/navigator_id.cc
index 9b708a74..17d7854 100644
--- a/third_party/blink/renderer/core/frame/navigator_id.cc
+++ b/third_party/blink/renderer/core/frame/navigator_id.cc
@@ -31,7 +31,9 @@
 
 #include "third_party/blink/renderer/core/frame/navigator_id.h"
 
+#include "base/feature_list.h"
 #include "build/build_config.h"
+#include "third_party/blink/public/common/features.h"
 
 #if !defined(OS_MACOSX) && !defined(OS_WIN)
 #include <sys/utsname.h>
@@ -56,6 +58,19 @@
 }
 
 String NavigatorID::platform() const {
+  // If the User-Agent string is frozen, platform should be a value
+  // matching the frozen string per https://github.com/WICG/ua-client-hints. See
+  // content::frozen_user_agent_strings.
+  if (base::FeatureList::IsEnabled(features::kFreezeUserAgent)) {
+#if defined(OS_ANDROID)
+    // Matches the frozen mobile User-Agent string (arbitrary Android device).
+    return "Linux armv8l";
+#else
+    // Matches the frozen desktop User-Agent string (Windows).
+    return "Win32";
+#endif
+  }
+
 #if defined(OS_MACOSX)
   // Match Safari and Mozilla on Mac x86.
   return "MacIntel";
diff --git a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
index 562be2e..2ca0829 100644
--- a/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
+++ b/third_party/blink/renderer/core/html/parser/html_tree_builder.cc
@@ -584,7 +584,7 @@
     // a proper html element which is a quirk in Blink's implementation.
     DCHECK(!IsParsingTemplateContents());
     DCHECK(!IsParsingFragment() ||
-           ToDocumentFragment(tree_.OpenElements()->TopNode()));
+           To<DocumentFragment>(tree_.OpenElements()->TopNode()));
     DCHECK(IsParsingFragment() ||
            tree_.OpenElements()->Top() == tree_.OpenElements()->HtmlElement());
     tree_.InsertHTMLElement(token);
diff --git a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
index 5ff810d..0151bb8 100644
--- a/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
+++ b/third_party/blink/renderer/core/inspector/inspector_dom_agent.cc
@@ -62,6 +62,8 @@
 #include "third_party/blink/renderer/core/html/html_template_element.h"
 #include "third_party/blink/renderer/core/html/imports/html_import_child.h"
 #include "third_party/blink/renderer/core/html/imports/html_import_loader.h"
+#include "third_party/blink/renderer/core/html/portal/document_portals.h"
+#include "third_party/blink/renderer/core/html/portal/html_portal_element.h"
 #include "third_party/blink/renderer/core/input_type_names.h"
 #include "third_party/blink/renderer/core/inspector/dom_editor.h"
 #include "third_party/blink/renderer/core/inspector/dom_patch_support.h"
@@ -2231,6 +2233,15 @@
     if (IdentifiersFactory::FrameId(frame) == frame_id)
       break;
   }
+  if (!frame) {
+    for (HTMLPortalElement* portal :
+         DocumentPortals::From(*inspected_frames_->Root()->GetDocument())
+             .GetPortals()) {
+      frame = portal->ContentFrame();
+      if (IdentifiersFactory::FrameId(frame) == frame_id)
+        break;
+    }
+  }
   if (!frame)
     return Response::Error("Frame with the given id was not found.");
   auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(frame->Owner());
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index fa335919..e0d17c9 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -620,7 +620,7 @@
     // Location of OOF with inline container, and anonymous containing block
     // is wrt container.
     LogicalOffset container_offset =
-        container_builder_->GetChildOffset(container->Parent());
+        container_builder_->GetChildOffset(container->ContainingBlock());
     offset -= container_offset;
   }
 
diff --git a/third_party/blink/renderer/core/loader/frame_loader.cc b/third_party/blink/renderer/core/loader/frame_loader.cc
index 2fa808a..cb526e66 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.cc
+++ b/third_party/blink/renderer/core/loader/frame_loader.cc
@@ -916,7 +916,8 @@
 
   if (!CancelProvisionalLoaderForNewNavigation(
           false /* cancel_scheduled_navigations */,
-          DocumentLoader::WillLoadUrlAsEmpty(navigation_params->url))) {
+          DocumentLoader::WillLoadUrlAsEmpty(navigation_params->url),
+          false /* is_form_submission */)) {
     return;
   }
 
@@ -964,7 +965,7 @@
     std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
   if (!CancelProvisionalLoaderForNewNavigation(
           true /* cancel_scheduled_navigations */,
-          false /* is_starting_blank_navigation */)) {
+          false /* is_starting_blank_navigation */, !info.form.IsNull())) {
     return false;
   }
 
@@ -1428,7 +1429,8 @@
 
 bool FrameLoader::CancelProvisionalLoaderForNewNavigation(
     bool cancel_scheduled_navigations,
-    bool is_starting_blank_navigation) {
+    bool is_starting_blank_navigation,
+    bool is_form_submission) {
   bool had_placeholder_client_document_loader =
       provisional_document_loader_ && !provisional_document_loader_->DidStart();
 
@@ -1440,7 +1442,7 @@
   // This seems to correspond to step 9 of the specification:
   // "9. Abort the active document of browsingContext."
   // https://html.spec.whatwg.org/C/#navigate
-  frame_->GetDocument()->Abort();
+  frame_->GetDocument()->Abort(is_form_submission);
   // document.onreadystatechange can fire in Abort(), which can:
   // 1) Detach this frame.
   // 2) Stop the provisional DocumentLoader (i.e window.stop()).
diff --git a/third_party/blink/renderer/core/loader/frame_loader.h b/third_party/blink/renderer/core/loader/frame_loader.h
index 45a20a6..7b5c50c 100644
--- a/third_party/blink/renderer/core/loader/frame_loader.h
+++ b/third_party/blink/renderer/core/loader/frame_loader.h
@@ -240,7 +240,8 @@
   // Returns whether we should continue with new navigation.
   bool CancelProvisionalLoaderForNewNavigation(
       bool cancel_scheduled_navigations,
-      bool is_starting_blank_navigation);
+      bool is_starting_blank_navigation,
+      bool is_form_submission);
 
   void RestoreScrollPositionAndViewState(WebFrameLoadType,
                                          bool is_same_document,
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index 3781848..031d6d2 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -66,7 +66,7 @@
       return;
 
     visible_node = node;
-    rect_in_root_frame = NodeRectInRootFrame(node, true /* ignore border */);
+    rect_in_root_frame = NodeRectInRootFrame(node);
   }
 
   focusable_node = node;
@@ -139,27 +139,9 @@
   if (!object)
     return FloatRect();
 
-  // Get the rect in the object's own frame. We use VisualRectInDocument for
-  // legacy reasons, it has some special cases for inlines that we'd like to
-  // preserve (or at least break layout tests). Because of that, we have to
-  // manually convert into frame coordinates and then clip to the frame.
-  LayoutRect rect_in_frame =
-      object->IsLayoutView()
-          ? object->VisualRectInDocument()
-          : frame_view->DocumentToFrame(object->VisualRectInDocument());
-  LayoutRect frame_rect =
-      LayoutRect(LayoutPoint(), LayoutSize(frame_view->Size()));
-  rect_in_frame.Intersect(frame_rect);
+  LayoutRect rect_in_root_frame = NodeRectInRootFrame(&node);
 
-  // Now convert from the local frame to the root frame's coordinate space.
-  // This will already apply clipping along the way.
-  LayoutRect rect_in_root_frame = rect_in_frame;
-  const LayoutBoxModelObject* ancestor = nullptr;
-  frame_view->GetLayoutView()->MapToVisualRectInAncestorSpace(
-      ancestor, rect_in_root_frame,
-      kUseTransforms | kTraverseDocumentBoundaries, kDefaultVisualRectFlags);
-
-  // Now convert to the visual viewport which will account for pinch zoom.
+  // Convert to the visual viewport which will account for pinch zoom.
   VisualViewport& visual_viewport =
       object->GetDocument().GetPage()->GetVisualViewport();
   FloatRect rect_in_viewport =
@@ -377,33 +359,28 @@
   }
 }
 
-LayoutRect NodeRectInRootFrame(const Node* node, bool ignore_border) {
+LayoutRect NodeRectInRootFrame(const Node* node) {
   DCHECK(node);
   DCHECK(node->GetLayoutObject());
   DCHECK(!node->GetDocument().View()->NeedsLayout());
 
-  LayoutRect rect = node->GetDocument().GetFrame()->View()->ConvertToRootFrame(
-      node->BoundingBox());
+  LayoutObject* object = node->GetLayoutObject();
 
-  // Ensure the rect isn't empty. This can happen in some cases as the bounding
-  // box is made up of the corners of multiple child elements. If the first
-  // child is to the right or bottom of the last child, the bounding box will
-  // be empty. Ensure its not empty so intersections with the root frame don't
-  // lie about being off-screen.
-  rect.UniteEvenIfEmpty(LayoutRect(rect.Location(), LayoutSize(1, 1)));
+  LayoutRect rect = LayoutRect(object->LocalBoundingBoxRectForAccessibility());
 
-  // For authors that use border instead of outline in their CSS, we compensate
-  // by ignoring the border when calculating the rect of the focused element.
-  if (ignore_border) {
-    rect.Move(node->GetLayoutObject()->Style()->BorderLeftWidth(),
-              node->GetLayoutObject()->Style()->BorderTopWidth());
-    rect.SetWidth(LayoutUnit(
-        rect.Width() - node->GetLayoutObject()->Style()->BorderLeftWidth() -
-        node->GetLayoutObject()->Style()->BorderRightWidth()));
-    rect.SetHeight(LayoutUnit(
-        rect.Height() - node->GetLayoutObject()->Style()->BorderTopWidth() -
-        node->GetLayoutObject()->Style()->BorderBottomWidth()));
-  }
+  // Inset the bounding box by the border.
+  // TODO(bokan): As far as I can tell, this is to work around empty iframes
+  // that have a border. It's unclear if that's still useful.
+  rect.Move(node->GetLayoutObject()->Style()->BorderLeftWidth(),
+            node->GetLayoutObject()->Style()->BorderTopWidth());
+  rect.SetWidth(LayoutUnit(
+      rect.Width() - node->GetLayoutObject()->Style()->BorderLeftWidth() -
+      node->GetLayoutObject()->Style()->BorderRightWidth()));
+  rect.SetHeight(LayoutUnit(
+      rect.Height() - node->GetLayoutObject()->Style()->BorderTopWidth() -
+      node->GetLayoutObject()->Style()->BorderBottomWidth()));
+
+  object->MapToVisualRectInAncestorSpace(/*ancestor=*/nullptr, rect);
   return rect;
 }
 
@@ -674,7 +651,7 @@
     if (area_element)
       return StartEdgeForAreaElement(*area_element, direction);
 
-    LayoutRect box_in_root_frame = NodeRectInRootFrame(focus_node, true);
+    LayoutRect box_in_root_frame = NodeRectInRootFrame(focus_node);
     return Intersection(box_in_root_frame, viewport_rect_of_root_frame);
   }
 
@@ -682,7 +659,7 @@
   while (container) {
     if (!IsOffscreen(container)) {
       // The first scroller that encloses focus and is [partially] visible.
-      LayoutRect box_in_root_frame = NodeRectInRootFrame(container, true);
+      LayoutRect box_in_root_frame = NodeRectInRootFrame(container);
       return OppositeEdge(direction, Intersection(box_in_root_frame,
                                                   viewport_rect_of_root_frame));
     }
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.h b/third_party/blink/renderer/core/page/spatial_navigation.h
index ca7e4c8..5a6e272 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.h
+++ b/third_party/blink/renderer/core/page/spatial_navigation.h
@@ -85,8 +85,7 @@
 double ComputeDistanceDataForNode(SpatialNavigationDirection,
                                   const FocusCandidate& current_interest,
                                   const FocusCandidate& candidate);
-CORE_EXPORT LayoutRect NodeRectInRootFrame(const Node*,
-                                           bool ignore_border = false);
+CORE_EXPORT LayoutRect NodeRectInRootFrame(const Node*);
 CORE_EXPORT LayoutRect OppositeEdge(SpatialNavigationDirection side,
                                     const LayoutRect& box,
                                     LayoutUnit thickness = LayoutUnit());
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
index e912dd0..5c60e62 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_controller.cc
@@ -82,8 +82,8 @@
        candidate.rect_in_root_frame.IsEmpty()))
     return;
 
-  // Ignore off-screen focusables that are not exposed after one "scroll step"
-  // in the direction.
+  // Ignore off-screen focusables, if there's nothing in the direction we'll
+  // scroll until they come on-screen.
   if (candidate.is_offscreen)
     return;
 
@@ -177,14 +177,17 @@
     return false;
 
   if (event->type() == event_type_names::kKeydown) {
+    interest_element->SetActive(true);
+  } else if (event->type() == event_type_names::kKeyup) {
+    interest_element->SetActive(false);
     if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled()) {
       interest_element->focus(FocusParams(SelectionBehaviorOnFocus::kReset,
                                           kWebFocusTypeSpatialNavigation,
                                           nullptr));
+      // We need enter to activate links, etc. The click should be after the
+      // focus in case the site transfers focus upon clicking.
+      interest_element->DispatchSimulatedClick(event);
     }
-    interest_element->SetActive(true);
-  } else if (event->type() == event_type_names::kKeyup) {
-    interest_element->SetActive(false);
   }
 
   return true;
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
index e5b817b1..e0716b1 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_test.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -198,7 +198,7 @@
 
   EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
                          SpatialNavigationDirection::kDown),
-            NodeRectInRootFrame(b, true));
+            NodeRectInRootFrame(b));
 }
 
 TEST_F(SpatialNavigationTest, StartAtVisibleFocusedScroller) {
@@ -220,7 +220,7 @@
   Element* scroller = GetDocument().getElementById("scroller");
   EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), scroller,
                          SpatialNavigationDirection::kDown),
-            NodeRectInRootFrame(scroller, true));
+            NodeRectInRootFrame(scroller));
 }
 
 TEST_F(SpatialNavigationTest, StartAtVisibleFocusedIframe) {
@@ -241,7 +241,7 @@
   Element* iframe = GetDocument().getElementById("iframe");
   EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), iframe,
                          SpatialNavigationDirection::kDown),
-            NodeRectInRootFrame(iframe, true));
+            NodeRectInRootFrame(iframe));
 }
 
 TEST_F(SpatialNavigationTest, StartAtTopWhenGoingDownwardsWithoutFocus) {
@@ -317,7 +317,7 @@
 
   Element* b = GetDocument().getElementById("b");
   const Element* container = GetDocument().getElementById("container");
-  const LayoutRect container_box = NodeRectInRootFrame(container, true);
+  const LayoutRect container_box = NodeRectInRootFrame(container);
 
   // TODO(crbug.com/889840):
   // VisibleBoundsInVisualViewport does not (yet) take div-clipping into
@@ -433,7 +433,7 @@
 
   EXPECT_FALSE(IsOffscreen(b));  // <button> is not completely offscreen.
 
-  LayoutRect button_in_root_frame = NodeRectInRootFrame(b, true);
+  LayoutRect button_in_root_frame = NodeRectInRootFrame(b);
 
   EXPECT_EQ(SearchOrigin(RootViewport(&GetFrame()), b,
                          SpatialNavigationDirection::kUp),
@@ -442,7 +442,7 @@
   // Do some scrolling.
   ScrollableArea* root_scroller = GetDocument().View()->GetScrollableArea();
   root_scroller->SetScrollOffset(ScrollOffset(0, 600), kProgrammaticScroll);
-  LayoutRect button_after_scroll = NodeRectInRootFrame(b, true);
+  LayoutRect button_after_scroll = NodeRectInRootFrame(b);
   ASSERT_NE(button_in_root_frame,
             button_after_scroll);  // As we scrolled, the
                                    // <button>'s position in
@@ -559,7 +559,7 @@
   EXPECT_TRUE(IsOffscreen(child_element));         // Completely offscreen.
   EXPECT_FALSE(IsOffscreen(enclosing_container));  // Partially visible.
 
-  LayoutRect iframe = NodeRectInRootFrame(enclosing_container, true);
+  LayoutRect iframe = NodeRectInRootFrame(enclosing_container);
 
   // When searching downwards we start at activeElement's
   // container's (here: the iframe's) topmost visible edge.
diff --git a/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc b/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc
index ff75cab..c905828 100644
--- a/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc
+++ b/third_party/blink/renderer/core/workers/worker_animation_frame_provider.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/core/workers/worker_animation_frame_provider.h"
 
 #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
+#include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
@@ -43,7 +44,11 @@
           FROM_HERE,
           WTF::Bind(
               [](base::WeakPtr<WorkerAnimationFrameProvider> provider) {
-                double time = WTF::CurrentTimeTicksInMilliseconds();
+                ExecutionContext* context = provider->context_;
+                Performance* performance =
+                    WorkerGlobalScopePerformance::performance(
+                        *To<WorkerGlobalScope>(context));
+                double time = performance->now();
                 // We don't want to expose microseconds residues to users.
                 time = round(time * 60) / 60;
 
diff --git a/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js b/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
index 035dde1..27390a41 100644
--- a/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
+++ b/third_party/blink/renderer/devtools/front_end/elements/ElementsTreeOutline.js
@@ -1244,6 +1244,8 @@
   _hasVisibleChildren(node) {
     if (node.isIframe())
       return true;
+    if (node.isPortal())
+      return true;
     if (node.contentDocument())
       return true;
     if (node.importedDocument())
diff --git a/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js b/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js
index baef908..b93e268 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/AppManifestView.js
@@ -11,11 +11,8 @@
     this.registerRequiredCSS('resources/appManifestView.css');
 
     this._emptyView = new UI.EmptyWidget(Common.UIString('No manifest detected'));
-    const p = this._emptyView.appendParagraph();
-    const linkElement = UI.XLink.create(
-        'https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/?utm_source=devtools',
-        Common.UIString('Read more about the web manifest'));
-    p.appendChild(UI.formatLocalized('A web manifest allows you to control how your app behaves when launched and displayed to the user. %s', [linkElement]));
+    this._emptyView.appendLink(
+        'https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/?utm_source=devtools');
 
     this._emptyView.show(this.contentElement);
     this._emptyView.hideWidget();
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js b/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js
index d5692ee..05a162b 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/ApplicationPanelSidebar.js
@@ -67,25 +67,35 @@
     const storageTreeElement = this._addSidebarSection(Common.UIString('Storage'));
     this.localStorageListTreeElement =
         new Resources.StorageCategoryTreeElement(panel, Common.UIString('Local Storage'), 'LocalStorage');
+    this.localStorageListTreeElement.setLink(
+        'https://developers.google.com/web/tools/chrome-devtools/storage/localstorage?utm_source=devtools');
     const localStorageIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
     this.localStorageListTreeElement.setLeadingIcons([localStorageIcon]);
 
     storageTreeElement.appendChild(this.localStorageListTreeElement);
     this.sessionStorageListTreeElement =
         new Resources.StorageCategoryTreeElement(panel, Common.UIString('Session Storage'), 'SessionStorage');
+    this.sessionStorageListTreeElement.setLink(
+        'https://developers.google.com/web/tools/chrome-devtools/storage/sessionstorage?utm_source=devtools');
     const sessionStorageIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
     this.sessionStorageListTreeElement.setLeadingIcons([sessionStorageIcon]);
 
     storageTreeElement.appendChild(this.sessionStorageListTreeElement);
     this.indexedDBListTreeElement = new Resources.IndexedDBTreeElement(panel);
+    this.indexedDBListTreeElement.setLink(
+        'https://developers.google.com/web/tools/chrome-devtools/storage/indexeddb?utm_source=devtools');
     storageTreeElement.appendChild(this.indexedDBListTreeElement);
     this.databasesListTreeElement =
         new Resources.StorageCategoryTreeElement(panel, Common.UIString('Web SQL'), 'Databases');
+    this.databasesListTreeElement.setLink(
+        'https://developers.google.com/web/tools/chrome-devtools/storage/websql?utm_source=devtools');
     const databaseIcon = UI.Icon.create('mediumicon-database', 'resource-tree-item');
     this.databasesListTreeElement.setLeadingIcons([databaseIcon]);
 
     storageTreeElement.appendChild(this.databasesListTreeElement);
     this.cookieListTreeElement = new Resources.StorageCategoryTreeElement(panel, Common.UIString('Cookies'), 'Cookies');
+    this.cookieListTreeElement.setLink(
+        'https://developers.google.com/web/tools/chrome-devtools/storage/cookies?utm_source=devtools');
     const cookieIcon = UI.Icon.create('mediumicon-cookie', 'resource-tree-item');
     this.cookieListTreeElement.setLeadingIcons([cookieIcon]);
     storageTreeElement.appendChild(this.cookieListTreeElement);
@@ -95,6 +105,8 @@
     cacheTreeElement.appendChild(this.cacheStorageListTreeElement);
     this.applicationCacheListTreeElement =
         new Resources.StorageCategoryTreeElement(panel, Common.UIString('Application Cache'), 'ApplicationCache');
+    this.applicationCacheListTreeElement.setLink(
+        'https://developers.google.com/web/tools/chrome-devtools/storage/applicationcache?utm_source=devtools');
     const applicationCacheIcon = UI.Icon.create('mediumicon-table', 'resource-tree-item');
     this.applicationCacheListTreeElement.setLeadingIcons([applicationCacheIcon]);
 
@@ -647,20 +659,27 @@
     this._expandedSetting =
         Common.settings.createSetting('resources' + settingsKey + 'Expanded', settingsKey === 'Frames');
     this._categoryName = categoryName;
+    this._categoryLink = null;
   }
 
-
   get itemURL() {
     return 'category://' + this._categoryName;
   }
 
   /**
+   * @param {string} link
+   */
+  setLink(link) {
+    this._categoryLink = link;
+  }
+
+  /**
    * @override
    * @return {boolean}
    */
   onselect(selectedByUser) {
     super.onselect(selectedByUser);
-    this._storagePanel.showCategoryView(this._categoryName);
+    this._storagePanel.showCategoryView(this._categoryName, this._categoryLink);
     return false;
   }
 
@@ -1708,7 +1727,7 @@
    */
   onselect(selectedByUser) {
     super.onselect(selectedByUser);
-    this._storagePanel.showCategoryView(this._manifestURL);
+    this._storagePanel.showCategoryView(this._manifestURL, null);
     return false;
   }
 };
@@ -1780,10 +1799,22 @@
 
     this.element.classList.add('storage-view');
     this._emptyWidget = new UI.EmptyWidget('');
+    this._linkElement = null;
     this._emptyWidget.show(this.element);
   }
 
   setText(text) {
     this._emptyWidget.text = text;
   }
+
+  setLink(link) {
+    if (link && !this._linkElement)
+      this._linkElement = this._emptyWidget.appendLink(link);
+    if (!link && this._linkElement)
+      this._linkElement.classList.add('hidden');
+    if (link && this._linkElement) {
+      this._linkElement.setAttribute('href', link);
+      this._linkElement.classList.remove('hidden');
+    }
+  }
 };
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ResourcesPanel.js b/third_party/blink/renderer/devtools/front_end/resources/ResourcesPanel.js
index 96c091e9..9dd82a4b 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/ResourcesPanel.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/ResourcesPanel.js
@@ -118,11 +118,13 @@
 
   /**
    * @param {string} categoryName
+   * @param {string|null} categoryLink
    */
-  showCategoryView(categoryName) {
+  showCategoryView(categoryName, categoryLink) {
     if (!this._categoryView)
       this._categoryView = new Resources.StorageCategoryView();
     this._categoryView.setText(categoryName);
+    this._categoryView.setLink(categoryLink);
     this.showView(this._categoryView);
   }
 
@@ -156,17 +158,6 @@
   }
 
   /**
-   * @param {string} text
-   */
-  showEmptyWidget(text) {
-    if (!this._emptyWidget)
-      this._emptyWidget = new UI.EmptyWidget(text);
-    else
-      this._emptyWidget.text = text;
-    this.showView(this._emptyWidget);
-  }
-
-  /**
    * @param {!SDK.Target} target
    * @param {string} cookieDomain
    */
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ResourcesSection.js b/third_party/blink/renderer/devtools/front_end/resources/ResourcesSection.js
index 3187665a..d1b37fb 100644
--- a/third_party/blink/renderer/devtools/front_end/resources/ResourcesSection.js
+++ b/third_party/blink/renderer/devtools/front_end/resources/ResourcesSection.js
@@ -169,7 +169,7 @@
    */
   onselect(selectedByUser) {
     super.onselect(selectedByUser);
-    this._section._panel.showCategoryView(this.titleAsText());
+    this._section._panel.showCategoryView(this.titleAsText(), null);
 
     this.listItemElement.classList.remove('hovered');
     SDK.OverlayModel.hideDOMNodeHighlight();
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js b/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js
index 2463c54..21743af 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/ChildTargetManager.js
@@ -121,6 +121,9 @@
     let type = SDK.Target.Type.Browser;
     if (targetInfo.type === 'iframe')
       type = SDK.Target.Type.Frame;
+    // TODO(lfg): ensure proper capabilities for child pages (e.g. portals).
+    else if (targetInfo.type === 'page')
+      type = SDK.Target.Type.Frame;
     else if (targetInfo.type === 'worker')
       type = SDK.Target.Type.Worker;
     else if (targetInfo.type === 'service_worker')
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js b/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js
index 24e4386..9d91e7c3 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/DOMModel.js
@@ -115,7 +115,7 @@
       this._contentDocument = new SDK.DOMDocument(this._domModel, payload.contentDocument);
       this._contentDocument.parentNode = this;
       this._children = [];
-    } else if (payload.nodeName === 'IFRAME' && payload.frameId) {
+    } else if ((payload.nodeName === 'IFRAME' || payload.nodeName === 'PORTAL') && payload.frameId) {
       const childTarget = SDK.targetManager.targetById(payload.frameId);
       const childModel = childTarget ? childTarget.model(SDK.DOMModel) : null;
       if (childModel)
@@ -231,6 +231,13 @@
   }
 
   /**
+   * @return {boolean}
+   */
+  isPortal() {
+    return this._nodeName === 'PORTAL';
+  }
+
+  /**
    * @return {?SDK.DOMNode}
    */
   importedDocument() {
diff --git a/third_party/blink/renderer/devtools/front_end/ui/EmptyWidget.js b/third_party/blink/renderer/devtools/front_end/ui/EmptyWidget.js
index c35c254..9ac0493 100644
--- a/third_party/blink/renderer/devtools/front_end/ui/EmptyWidget.js
+++ b/third_party/blink/renderer/devtools/front_end/ui/EmptyWidget.js
@@ -52,6 +52,14 @@
   }
 
   /**
+   * @param {string} link
+   * @return {!Node}
+   */
+  appendLink(link) {
+    return this._contentElement.appendChild(UI.XLink.create(link, 'Learn more'));
+  }
+
+  /**
    * @param {string} text
    */
   set text(text) {
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc b/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
index 62e1d29..67ea539 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_key_session.cc
@@ -76,9 +76,11 @@
   if (!session_id.ContainsOnlyASCIIOrEmpty())
     return false;
 
-  // Check that the sessionId only contains alphanumeric characters.
+  // Check that |session_id| only contains non-space printable characters for
+  // easier logging. Note that checking alphanumeric is too strict because there
+  // are key systems using Base64 session IDs. See https://crbug.com/902828.
   for (unsigned i = 0; i < session_id.length(); ++i) {
-    if (!IsASCIIAlphanumeric(session_id[i]))
+    if (!IsASCIIPrintable(session_id[i]) || session_id[i] == ' ')
       return false;
   }
 
diff --git a/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc b/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
index 29ce573a9..d35156e9 100644
--- a/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
+++ b/third_party/blink/renderer/modules/installedapp/installed_app_controller.cc
@@ -4,43 +4,42 @@
 
 #include "third_party/blink/renderer/modules/installedapp/installed_app_controller.h"
 
+#include <utility>
+
 #include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/common/manifest/manifest.h"
+#include "third_party/blink/public/platform/web_string.h"
+#include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/manifest/manifest_manager.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 
-#include <utility>
-
 namespace blink {
 
 InstalledAppController::~InstalledAppController() = default;
 
 void InstalledAppController::GetInstalledRelatedApps(
     std::unique_ptr<AppInstalledCallbacks> callbacks) {
-  // When detached, the fetcher is no longer valid.
-  if (!related_apps_fetcher_) {
+  // When detached, the fetch logic is no longer valid.
+  if (context_destroyed_) {
     // TODO(mgiuca): AbortError rather than simply undefined.
     // https://crbug.com/687846
     callbacks->OnError();
     return;
   }
 
-  // Get the list of related applications from the manifest. This requires a
-  // request to the content layer (because the manifest is not a Blink concept).
+  // Get the list of related applications from the manifest.
   // Upon returning, filter the result list to those apps that are installed.
-  // TODO(mgiuca): This roundtrip to content could be eliminated if the Manifest
-  // class was moved from content into Blink.
-  related_apps_fetcher_->GetManifestRelatedApplications(
-      WTF::Bind(&InstalledAppController::OnGetRelatedAppsCallback,
-                WrapWeakPersistent(this), std::move(callbacks)));
+  ManifestManager::From(*GetSupplementable())
+      ->RequestManifest(
+          WTF::Bind(&InstalledAppController::OnGetManifestForRelatedApps,
+                    WrapPersistent(this), std::move(callbacks)));
 }
 
-void InstalledAppController::ProvideTo(
-    LocalFrame& frame,
-    WebRelatedAppsFetcher* related_apps_fetcher) {
+void InstalledAppController::ProvideTo(LocalFrame& frame) {
   Supplement<LocalFrame>::ProvideTo(
-      frame, MakeGarbageCollected<InstalledAppController>(
-                 frame, related_apps_fetcher));
+      frame, MakeGarbageCollected<InstalledAppController>(frame));
 }
 
 InstalledAppController* InstalledAppController::From(LocalFrame& frame) {
@@ -52,37 +51,31 @@
 
 const char InstalledAppController::kSupplementName[] = "InstalledAppController";
 
-InstalledAppController::InstalledAppController(
-    LocalFrame& frame,
-    WebRelatedAppsFetcher* related_apps_fetcher)
+InstalledAppController::InstalledAppController(LocalFrame& frame)
     : Supplement<LocalFrame>(frame),
-      ContextLifecycleObserver(frame.GetDocument()),
-      related_apps_fetcher_(related_apps_fetcher) {}
+      ContextLifecycleObserver(frame.GetDocument()) {}
 
 void InstalledAppController::ContextDestroyed(ExecutionContext*) {
   provider_.reset();
-  related_apps_fetcher_ = nullptr;
+  context_destroyed_ = true;
 }
 
-void InstalledAppController::OnGetRelatedAppsCallback(
+void InstalledAppController::OnGetManifestForRelatedApps(
     std::unique_ptr<AppInstalledCallbacks> callbacks,
-    const WebVector<WebRelatedApplication>& related_apps) {
-  // TODO: Fix the order of the parameters in ::FilterByInstalledApps
-  // and bound it right away as the completion callback.
-  FilterByInstalledApps(related_apps, std::move(callbacks));
-}
-
-void InstalledAppController::FilterByInstalledApps(
-    const blink::WebVector<blink::WebRelatedApplication>& related_apps,
-    std::unique_ptr<blink::AppInstalledCallbacks> callbacks) {
+    const WebURL& /*url*/,
+    const Manifest& manifest) {
   WTF::Vector<mojom::blink::RelatedApplicationPtr> mojo_related_apps;
-  for (const auto& related_application : related_apps) {
+  for (const Manifest::RelatedApplication& related_application :
+       manifest.related_applications) {
     mojom::blink::RelatedApplicationPtr converted_application(
         mojom::blink::RelatedApplication::New());
-    DCHECK(!related_application.platform.IsEmpty());
-    converted_application->platform = related_application.platform;
-    converted_application->id = related_application.id;
-    converted_application->url = related_application.url;
+    converted_application->platform =
+        WebString::FromUTF16(related_application.platform);
+    converted_application->id = WebString::FromUTF16(related_application.id);
+    if (!related_application.url.is_empty()) {
+      converted_application->url =
+          WebString::FromUTF8(related_application.url.spec());
+    }
     mojo_related_apps.push_back(std::move(converted_application));
   }
 
@@ -106,7 +99,7 @@
 void InstalledAppController::OnFilterInstalledApps(
     std::unique_ptr<blink::AppInstalledCallbacks> callbacks,
     WTF::Vector<mojom::blink::RelatedApplicationPtr> result) {
-  std::vector<blink::WebRelatedApplication> applications;
+  WTF::Vector<blink::WebRelatedApplication> applications;
   for (const auto& res : result) {
     blink::WebRelatedApplication app;
     app.platform = res->platform;
diff --git a/third_party/blink/renderer/modules/installedapp/installed_app_controller.h b/third_party/blink/renderer/modules/installedapp/installed_app_controller.h
index e449d10..c5c8516 100644
--- a/third_party/blink/renderer/modules/installedapp/installed_app_controller.h
+++ b/third_party/blink/renderer/modules/installedapp/installed_app_controller.h
@@ -12,7 +12,6 @@
 #include "third_party/blink/public/mojom/installedapp/installed_app_provider.mojom-blink.h"
 #include "third_party/blink/public/mojom/installedapp/related_application.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/installedapp/web_related_application.h"
-#include "third_party/blink/public/platform/modules/installedapp/web_related_apps_fetcher.h"
 #include "third_party/blink/public/platform/web_callbacks.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/core/execution_context/context_lifecycle_observer.h"
@@ -23,6 +22,11 @@
 
 namespace blink {
 
+class WebURL;
+template <typename T>
+class WebVector;
+struct Manifest;
+
 using AppInstalledCallbacks =
     WebCallbacks<const WebVector<WebRelatedApplication>&, void>;
 
@@ -35,35 +39,31 @@
  public:
   static const char kSupplementName[];
 
-  InstalledAppController(LocalFrame&, WebRelatedAppsFetcher*);
+  explicit InstalledAppController(LocalFrame&);
   virtual ~InstalledAppController();
 
   // Gets a list of related apps from the current page's manifest that belong
   // to the current underlying platform, and are installed.
   void GetInstalledRelatedApps(std::unique_ptr<AppInstalledCallbacks>);
 
-  static void ProvideTo(LocalFrame&, WebRelatedAppsFetcher*);
+  static void ProvideTo(LocalFrame&);
   static InstalledAppController* From(LocalFrame&);
 
   void Trace(blink::Visitor*) override;
 
  private:
-  class GetRelatedAppsCallbacks;
-
-  // Inherited from ContextLifecycleObserver.
-  void ContextDestroyed(ExecutionContext*) override;
-
-  // Callback for the result of
-  // WebRelatedAppsFetcher::getManifestRelatedApplications. Calls
-  // filterByInstalledApps upon receiving the list of related applications.
-  void OnGetRelatedAppsCallback(std::unique_ptr<AppInstalledCallbacks>,
-                                const WebVector<WebRelatedApplication>&);
-
+  // Callback for the result of GetInstalledRelatedApps.
+  //
   // Takes a set of related applications and filters them by those which belong
   // to the current underlying platform, and are actually installed and related
   // to the current page's origin. Passes the filtered list to the callback.
-  void FilterByInstalledApps(const WebVector<WebRelatedApplication>&,
-                             std::unique_ptr<AppInstalledCallbacks>);
+  void OnGetManifestForRelatedApps(
+      std::unique_ptr<AppInstalledCallbacks> callbacks,
+      const WebURL& url,
+      const Manifest& manifest);
+
+  // Inherited from ContextLifecycleObserver.
+  void ContextDestroyed(ExecutionContext*) override;
 
   // Callback from the InstalledAppProvider mojo service.
   void OnFilterInstalledApps(std::unique_ptr<blink::AppInstalledCallbacks>,
@@ -72,7 +72,7 @@
   // Handle to the InstalledApp mojo service.
   mojom::blink::InstalledAppProviderPtr provider_;
 
-  WebRelatedAppsFetcher* related_apps_fetcher_;
+  bool context_destroyed_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(InstalledAppController);
 };
diff --git a/third_party/blink/renderer/modules/manifest/manifest_manager.h b/third_party/blink/renderer/modules/manifest/manifest_manager.h
index d8844f8..3876cb0 100644
--- a/third_party/blink/renderer/modules/manifest/manifest_manager.h
+++ b/third_party/blink/renderer/modules/manifest/manifest_manager.h
@@ -49,6 +49,10 @@
   void DidChangeManifest();
   void DidCommitLoad();
 
+  // WebManifestManager
+  void RequestManifest(WebCallback callback) override;
+  bool CanFetchManifest() override;
+
   void Trace(blink::Visitor*) override;
 
  private:
@@ -58,9 +62,6 @@
       base::OnceCallback<void(const KURL&,
                               const Manifest&,
                               const mojom::blink::ManifestDebugInfo*)>;
-  // WebManifestManager
-  void RequestManifest(WebCallback callback) override;
-  bool CanFetchManifest() override;
 
   // From ContextLifecycleObserver
   void ContextDestroyed(ExecutionContext*) override;
diff --git a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
index 43189f1..830a2a0 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -653,9 +653,13 @@
 }
 
 video::-webkit-media-controls input[pseudo="-webkit-media-controls-timeline" i]:hover::-webkit-slider-thumb,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-timeline" i]:focus::-webkit-slider-thumb,
 audio::-webkit-media-controls input[pseudo="-webkit-media-controls-timeline" i]:hover::-webkit-slider-thumb,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-timeline" i]:focus::-webkit-slider-thumb,
 video::-webkit-media-controls input[pseudo="-webkit-media-controls-volume-slider" i]:hover::-webkit-slider-thumb,
-audio::-webkit-media-controls input[pseudo="-webkit-media-controls-volume-slider" i]:hover::-webkit-slider-thumb {
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-volume-slider" i]:focus::-webkit-slider-thumb,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-volume-slider" i]:hover::-webkit-slider-thumb,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-volume-slider" i]:focus::-webkit-slider-thumb {
   opacity: 1;
 }
 
diff --git a/third_party/blink/renderer/modules/modules_initializer.cc b/third_party/blink/renderer/modules/modules_initializer.cc
index 391510b..ddc179c 100644
--- a/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/third_party/blink/renderer/modules/modules_initializer.cc
@@ -193,10 +193,10 @@
   ScreenOrientationControllerImpl::ProvideTo(frame);
   if (RuntimeEnabledFeatures::PresentationEnabled())
     PresentationController::ProvideTo(frame);
-  InstalledAppController::ProvideTo(frame, client->GetRelatedAppsFetcher());
   ::blink::ProvideSpeechRecognitionTo(frame);
   InspectorAccessibilityAgent::ProvideTo(&frame);
   ManifestManager::ProvideTo(frame);
+  InstalledAppController::ProvideTo(frame);
 }
 
 void ModulesInitializer::ProvideLocalFileSystemToWorker(
diff --git a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc
index 1b3bd8e5..60ae944 100644
--- a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.cc
@@ -88,7 +88,7 @@
     bounds_geometry_.clear();
   }
 
-  DispatchEvent(*XRReferenceSpaceEvent::Create(event_type_names::kReset, this));
+  OnReset();
 }
 
 // Transforms a given pose from a "base" reference space used by the XR
@@ -122,4 +122,8 @@
   XRReferenceSpace::Trace(visitor);
 }
 
+void XRBoundedReferenceSpace::OnReset() {
+  DispatchEvent(*XRReferenceSpaceEvent::Create(event_type_names::kReset, this));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h
index 98433cf..e5bfd7a 100644
--- a/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_bounded_reference_space.h
@@ -28,6 +28,8 @@
 
   void Trace(blink::Visitor*) override;
 
+  void OnReset() override;
+
  private:
   void EnsureUpdated();
 
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
index e906a66f8..42bf378 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/xr/xr_reference_space.h"
 
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space_event.h"
 #include "third_party/blink/renderer/modules/xr/xr_rigid_transform.h"
 #include "third_party/blink/renderer/modules/xr/xr_session.h"
 
@@ -75,4 +76,6 @@
   XRSpace::Trace(visitor);
 }
 
+void XRReferenceSpace::OnReset() {}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_reference_space.h b/third_party/blink/renderer/modules/xr/xr_reference_space.h
index e0d18795..de7b49b 100644
--- a/third_party/blink/renderer/modules/xr/xr_reference_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_reference_space.h
@@ -38,6 +38,8 @@
 
   void Trace(blink::Visitor*) override;
 
+  virtual void OnReset();
+
  private:
   Member<XRRigidTransform> origin_offset_;
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index 996336b..b677287 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -305,6 +305,8 @@
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError,
                                            kUnknownReferenceSpace));
+  } else {
+    reference_spaces_.push_back(reference_space);
   }
 
   auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
@@ -864,7 +866,9 @@
 }
 
 void XRSession::OnPoseReset() {
-  DispatchEvent(*XRSessionEvent::Create(event_type_names::kResetpose, this));
+  for (const auto& reference_space : reference_spaces_) {
+    reference_space->OnReset();
+  }
 }
 
 void XRSession::UpdateInputSourceState(
@@ -1040,6 +1044,7 @@
   visitor->Trace(canvas_input_provider_);
   visitor->Trace(callback_collection_);
   visitor->Trace(hit_test_promises_);
+  visitor->Trace(reference_spaces_);
   EventTargetWithInlineData::Trace(visitor);
 }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h
index c3f47a6..88e0f9e0 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -33,6 +33,7 @@
 class XRInputSourceEvent;
 class XRPresentationContext;
 class XRRay;
+class XRReferenceSpace;
 class XRReferenceSpaceOptions;
 class XRRenderState;
 class XRRenderStateInit;
@@ -83,12 +84,11 @@
 
   DEFINE_ATTRIBUTE_EVENT_LISTENER(blur, kBlur)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(focus, kFocus)
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(resetpose, kResetpose)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(end, kEnd)
-
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(select, kSelect)
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(inputsourceschange, kInputsourceschange)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart, kSelectstart)
   DEFINE_ATTRIBUTE_EVENT_LISTENER(selectend, kSelectend)
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(select, kSelect)
 
   void updateRenderState(XRRenderStateInit*, ExceptionState&);
   void updateWorldTrackingState(XRWorldTrackingStateInit*) {}
@@ -230,6 +230,7 @@
   Member<XRCanvasInputProvider> canvas_input_provider_;
   bool environment_error_handler_subscribed_ = false;
   HeapHashSet<Member<ScriptPromiseResolver>> hit_test_promises_;
+  HeapVector<Member<XRReferenceSpace>> reference_spaces_;
 
   bool has_xr_focus_ = true;
   bool is_external_ = false;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.idl b/third_party/blink/renderer/modules/xr/xr_session.idl
index c3af2de..dc170961 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -29,8 +29,11 @@
 
   attribute EventHandler onblur;
   attribute EventHandler onfocus;
-  attribute EventHandler onresetpose;
   attribute EventHandler onend;
+  attribute EventHandler onselect;
+  attribute EventHandler oninputsourceschange;
+  attribute EventHandler onselectstart;
+  attribute EventHandler onselectend;
 
   [RaisesException] void updateRenderState(XRRenderStateInit init);
 
diff --git a/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc
index 8887caa..4b5b6942 100644
--- a/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h"
 
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space_event.h"
 #include "third_party/blink/renderer/modules/xr/xr_session.h"
 
 namespace blink {
@@ -143,4 +144,8 @@
   XRReferenceSpace::Trace(visitor);
 }
 
+void XRStationaryReferenceSpace::OnReset() {
+  DispatchEvent(*XRReferenceSpaceEvent::Create(event_type_names::kReset, this));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h b/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h
index c1f5b4a..e57f3284 100644
--- a/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_stationary_reference_space.h
@@ -34,6 +34,8 @@
 
   void Trace(blink::Visitor*) override;
 
+  void OnReset() override;
+
  private:
   void UpdateFloorLevelTransform();
 
diff --git a/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc b/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc
index c8bce50..a93dfe38 100644
--- a/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc
+++ b/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.cc
@@ -5,6 +5,7 @@
 #include "third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h"
 
 #include "device/vr/public/mojom/vr_service.mojom-blink.h"
+#include "third_party/blink/renderer/modules/xr/xr_reference_space_event.h"
 #include "third_party/blink/renderer/modules/xr/xr_session.h"
 
 namespace blink {
@@ -31,4 +32,8 @@
   XRReferenceSpace::Trace(visitor);
 }
 
+void XRUnboundedReferenceSpace::OnReset() {
+  DispatchEvent(*XRReferenceSpaceEvent::Create(event_type_names::kReset, this));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h b/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h
index 6fc1c3b..6c9768b 100644
--- a/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h
+++ b/third_party/blink/renderer/modules/xr/xr_unbounded_reference_space.h
@@ -23,6 +23,8 @@
 
   void Trace(blink::Visitor*) override;
 
+  void OnReset() override;
+
  private:
   std::unique_ptr<TransformationMatrix> pose_transform_;
 };
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 912ea0b..7d7b210 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -360,10 +360,8 @@
       transform_node.FlattensInheritedTransform();
   compositor_node.sorting_context_id = transform_node.RenderingContextId();
 
-  if (transform_node.IsAffectedByOuterViewportBoundsDelta()) {
-    compositor_node.moved_by_outer_viewport_bounds_delta_y = true;
+  if (transform_node.IsAffectedByOuterViewportBoundsDelta())
     GetTransformTree().AddNodeAffectedByOuterViewportBoundsDelta(id);
-  }
 
   compositor_node.in_subtree_of_page_scale_layer =
       transform_node.IsInSubtreeOfPageScale();
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index 99e3da7..79d784a 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -581,7 +581,9 @@
     // Return the mailbox but report that the resource is lost to prevent trying
     // to use the backing for future frames. We keep it alive with our own
     // reference to the backing via our |textureId|.
-    release_callback->Run(gpu::SyncToken(), true /* lost_resource */);
+    gpu::SyncToken sync_token;
+    gl_->GenUnverifiedSyncTokenCHROMIUM(sync_token.GetData());
+    release_callback->Run(sync_token, true /* lost_resource */);
   }
 
   // We reuse the same mailbox name from above since our texture id was consumed
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 4a5e6de..3f64039 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -2164,6 +2164,37 @@
 crbug.com/905315 external/wpt/css/css-text/overflow-wrap/overflow-wrap-min-content-size-004.html [ Skip ]
 crbug.com/905315 external/wpt/css/css-text/word-break/word-break-break-word-overflow-wrap-interactions.html [ Skip ]
 
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-000.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-001.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-002.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-003.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-004.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-005.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-006.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-007.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-008.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-014.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-016.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-017.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-018.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-020.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-021.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-022.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-023.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-024.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping-025.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/shaping/shaping_lig-000.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/text-encoding/shaping-join-003.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/text-encoding/shaping-tatweel-003.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/boundary-shaping/boundary-shaping-001.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/boundary-shaping/boundary-shaping-003.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/boundary-shaping/boundary-shaping-004.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/boundary-shaping/boundary-shaping-005.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/boundary-shaping/boundary-shaping-010.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/text-transform/text-transform-shaping-001.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/text-transform/text-transform-shaping-002.html [ Failure ]
+crbug.com/6122 external/wpt/css/css-text/text-transform/text-transform-shaping-003.html [ Failure ]
+
 
 # These are added to W3CImportExpectations as Skip, remove when next import is done.
 crbug.com/666657 external/wpt/css/css-text/hanging-punctuation [ Skip ]
@@ -2807,6 +2838,11 @@
 # Remove these from virtual tests when Network Error Logging is turned on by default
 crbug.com/748549 external/wpt/network-error-logging [ Skip ]
 
+# Remove from virtual tests when FreezeUserAgent is turned on by default.
+crbug.com/955620 http/tests/navigation/frozen-useragent.html [ Skip ]
+crbug.com/955620 virtual/outofblink-cors/http/tests/navigation/frozen-useragent.html [ Skip ]
+crbug.com/955620 virtual/stable/http/tests/navigation/frozen-useragent.html [ Skip ]
+
 crbug.com/863896 http/tests/permissions/test-query.html [ Timeout ]
 
 crbug.com/876485 fast/performance/performance-measure-null-exception.html [ Failure ]
@@ -2928,6 +2964,7 @@
 crbug.com/893490 [ Mac ] external/wpt/css/css-text/white-space/control-chars-007.html [ Failure ]
 crbug.com/893490 [ Mac ] external/wpt/css/css-text/white-space/control-chars-008.html [ Failure ]
 crbug.com/893490 [ Mac ] external/wpt/css/css-text/white-space/control-chars-00B.html [ Failure ]
+crbug.com/893490 external/wpt/css/css-text/white-space/control-chars-00C.html [ Failure ]
 crbug.com/893490 external/wpt/css/css-text/white-space/control-chars-00D.html [ Failure ]
 crbug.com/893490 [ Mac ] external/wpt/css/css-text/white-space/control-chars-00E.html [ Failure ]
 crbug.com/893490 [ Mac ] external/wpt/css/css-text/white-space/control-chars-00F.html [ Failure ]
@@ -3001,8 +3038,64 @@
 crbug.com/939181 virtual/not-site-per-process/external/wpt/html/browsers/origin/cross-origin-objects/cross-origin-objects.html [ Failure Timeout ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-align-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-margin-001.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-padding-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-margin-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html [ Failure ]
+crbug.com/626703 external/wpt/xhr/event-readystatechange-loaded.any.worker.html [ Timeout ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-017.html [ Failure ]
+crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-button-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-padding-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-align-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-lists/li-list-item-counter.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-snap-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html [ Failure ]
+crbug.com/626703 virtual/omt-worker-fetch/external/wpt/xhr/event-readystatechange-loaded.any.html [ Timeout ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-margin-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-pseudo/marker-content-011.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-align-003.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-align-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ]
+crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-015.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-lists/counter-set-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-pseudo/marker-content-009.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-align-002.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-margin-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-multiple-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-button-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-button-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-lists/li-value-counter-reset-001.html [ Failure ]
+crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/event-readystatechange-loaded.any.html [ Timeout ]
+crbug.com/626703 external/wpt/xhr/event-readystatechange-loaded.any.html [ Timeout ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-margin-002.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-padding-002.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-snap-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-multicol/multicol-span-all-button-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-snap-002.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-align-001.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-snap-002.html [ Failure ]
+crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-children-height-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-padding-001.html [ Failure ]
+crbug.com/626703 virtual/threaded/external/wpt/css/css-scroll-snap/scroll-target-padding-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-snap-003.html [ Failure ]
+crbug.com/626703 virtual/omt-worker-fetch/external/wpt/xhr/event-readystatechange-loaded.any.worker.html [ Timeout ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-snap-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-margin-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html [ Failure ]
+crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/event-readystatechange-loaded.any.worker.html [ Timeout ]
+crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-button-003.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html [ Failure ]
+crbug.com/626703 virtual/layout_ng_experimental/external/wpt/css/css-multicol/multicol-span-all-button-002.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-animations/animationevent-marker-pseudoelement.html [ Timeout ]
+crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-016.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-pseudo/marker-content-010.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-scroll-snap/scroll-target-padding-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/break-spaces-008.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/white-space/control-chars-00C.html [ Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/upgrade-insecure-requests/image-redirect-upgrade.https.html [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-atomic-005.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-atomic-008.html [ Failure ]
@@ -3012,11 +3105,6 @@
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-replaced-003.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-replaced-005.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/line-breaking/line-breaking-atomic-003.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-025.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-023.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-024.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/text-encoding/shaping-join-003.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/text-encoding/shaping-tatweel-003.html [ Failure ]
 crbug.com/626703 virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/client-navigate.https.html [ Timeout ]
 crbug.com/626703 external/wpt/service-workers/service-worker/client-navigate.https.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/service-workers/service-worker/client-navigate.https.html [ Timeout ]
@@ -3092,23 +3180,6 @@
 crbug.com/626703 virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ]
 crbug.com/626703 [ Mac10.13 ] virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/async_005.htm [ Timeout ]
 crbug.com/626703 external/wpt/webrtc/RTCPeerConnection-getStats.https.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-021.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-018.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-006.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-000.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-020.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-003.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-002.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-016.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-022.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping_lig-000.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-007.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-005.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-008.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-004.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-017.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/shaping/shaping-014.html [ Failure ]
 crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy.html [ Failure ]
 crbug.com/626703 external/wpt/infrastructure/reftest/reftest_fuzzy_1.html [ Failure ]
 crbug.com/626703 external/wpt/screen-orientation/onchange-event.html [ Timeout ]
@@ -3154,7 +3225,6 @@
 crbug.com/626703 external/wpt/reporting/bufferSize.html [ Timeout ]
 crbug.com/626703 external/wpt/reporting/order.html [ Timeout ]
 crbug.com/626703 external/wpt/reporting/nestedReport.html [ Timeout ]
-crbug.com/626703 [ Retina ] virtual/feature-policy-permissions/external/wpt/mediacapture-streams/idlharness.https.window.html [ Timeout ]
 crbug.com/626703 [ Retina ] virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaDevices-enumerateDevices.https.html [ Timeout ]
 crbug.com/626703 [ Retina ] virtual/feature-policy-permissions/external/wpt/mediacapture-streams/MediaDevices-getUserMedia.https.html [ Timeout ]
 crbug.com/626703 virtual/not-site-per-process/external/wpt/html/browsers/origin/relaxing-the-same-origin-restriction/document_domain_access_details.sub.html [ Skip ]
@@ -3203,14 +3273,11 @@
 crbug.com/626703 [ Retina ] virtual/streaming-preload/external/wpt/html/semantics/scripting-1/the-script-element/async_005.htm [ Timeout ]
 crbug.com/626703 external/wpt/css/css-text/tab-size/tab-size-spacing-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-values/vh-support-atviewport.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/boundary-shaping/boundary-shaping-005.html [ Failure ]
 crbug.com/626703 external/wpt/css/CSS2/text/white-space-nowrap-attribute-001.xht [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/boundary-shaping/boundary-shaping-010.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/white-space-intrinsic-size-004.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-1.html [ Failure ]
 crbug.com/626703 [ Linux ] external/wpt/css/CSS2/text/white-space-bidirectionality-001.xht [ Failure ]
 crbug.com/626703 [ Win ] external/wpt/css/CSS2/text/white-space-bidirectionality-001.xht [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-shaping-002.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/pre-wrap-012.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2b.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/block-size-with-min-or-max-content-1a.html [ Failure ]
@@ -3218,22 +3285,17 @@
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/vert-block-size-small-or-larger-than-container-with-min-or-max-content-2b.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/vert-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/pre-wrap-013.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-shaping-003.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/white-space/white-space-intrinsic-size-003.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-copy-paste-001-manual.html [ Skip ]
 crbug.com/626703 external/wpt/css/css-text/white-space/white-space-intrinsic-size-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/boundary-shaping/boundary-shaping-003.html [ Failure ]
 crbug.com/626703 external/wpt/html/webappapis/animation-frames/cancel-handle-manual.html [ Skip ]
 crbug.com/626703 [ Linux ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Failure ]
 crbug.com/626703 [ Mac ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Failure ]
 crbug.com/626703 [ Win10 ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Failure ]
 crbug.com/626703 [ Win7 ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Failure Crash ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/block-size-with-min-or-max-content-1b.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/text-transform/text-transform-shaping-001.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/boundary-shaping/boundary-shaping-001.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-text/text-indent/text-indent-percentage-004.html [ Failure ]
 crbug.com/626703 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/vert-block-size-small-or-larger-than-container-with-min-or-max-content-1.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-text/boundary-shaping/boundary-shaping-004.html [ Failure ]
 crbug.com/626703 external/wpt/css/css-sizing/range-percent-intrinsic-size-2.html [ Failure ]
 crbug.com/626703 external/wpt/css/filter-effects/filter-subregion-01.html [ Failure ]
 crbug.com/626703 [ Android ] external/wpt/css/css-layout-api/auto-block-size-absolute.https.html [ Failure ]
@@ -4163,7 +4225,6 @@
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/size_50.html [ Failure ]
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/too_many_cues.html [ Failure ]
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/too_many_cues_wrapped.html [ Failure ]
-crbug.com/626703 external/wpt/xhr/event-readystatechange-loaded.htm [ Failure Timeout ]
 crbug.com/626703 virtual/omt-worker-fetch/external/wpt/xhr/event-readystatechange-loaded.htm [ Failure Timeout ]
 crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/event-readystatechange-loaded.htm [ Failure Timeout ]
 crbug.com/626703 external/wpt/xhr/preserve-ua-header-on-redirect.htm [ Failure ]
@@ -4198,7 +4259,7 @@
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-composite.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-filter.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-gradient.https.html [ Failure ]
-crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/paint2d-image.https.html [ Crash ]
+crbug.com/957457 virtual/threaded/external/wpt/css/css-paint-api/paint2d-image.https.html [ Crash Timeout ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-paths.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-rects.https.html [ Failure ]
 crbug.com/957459 virtual/threaded/external/wpt/css/css-paint-api/paint2d-shadows.https.html [ Failure ]
@@ -5583,6 +5644,7 @@
 crbug.com/874162 [ Mac ] virtual/user-activation-v2/fast/events/selection-autoscroll-borderbelt.html [ Skip ]
 
 # Flaky
+crbug.com/957916 fullscreen/rendering/backdrop-object.html [ Timeout Pass ]
 crbug.com/894077 virtual/android/fullscreen/video-fixed-background.html [ Pass Failure ]
 
 # Failures on 32-bit Android when using GPU instead of software rendering
@@ -6136,8 +6198,6 @@
 crbug.com/947126 [ Mac10.13 ] virtual/video-surface-layer/media/video-played-ranges-1.html [ Pass Failure ]
 crbug.com/942411 [ Win7 Linux ] http/tests/devtools/network/network-search.js [ Pass Timeout ]
 crbug.com/947383 inspector-protocol/css/reattach-after-editing-styles.js [ Pass Timeout ]
-# Sheriff 2019-03-29
-crbug.com/947477 external/wpt/editing/run/removeformat.html [ Pass Crash Timeout ]
 
 ### external/wpt/fetch/sec-metadata/
 crbug.com/947023 external/wpt/fetch/sec-metadata/font.tentative.https.sub.html [ Pass Failure ]
@@ -6216,7 +6276,6 @@
 crbug.com/954998 [ Mac ] http/tests/devtools/tracing/timeline-js/timeline-js-line-level-profile-end-to-end.js [ Pass Timeout ]
 
 # Sheriff 2019-04-25
-crbug.com/956401 [ Win ] external/wpt/cookies/samesite/form-post-blank.html [ Pass Timeout ]
 crbug.com/956547 fast/dom/raf-throttling-out-of-view-cross-origin-page.html [ Pass Timeout ]
 crbug.com/956547 fast/dom/timer-throttling-out-of-view-cross-origin-page.html [ Pass Timeout ]
 crbug.com/956736 virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map.html [ Pass Failure ]
@@ -6226,3 +6285,5 @@
 
 # Sheriff 2019-04-30
 crbug.com/946534 [ Mac10.10 Mac10.11 ] external/wpt/animation-worklet/worklet-animation-with-scroll-timeline-root-scroller.https.html [ Pass Failure ]
+crbug.com/948785 [ Debug ] fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Pass Failure ]
+crbug.com/948785 [ Debug ] virtual/mouseevent_fractional/fast/events/pointerevents/pointer-event-consumed-touchstart-in-slop-region.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites
index dc13f4c..21d9b5f 100644
--- a/third_party/blink/web_tests/VirtualTestSuites
+++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -1059,6 +1059,16 @@
     "args": ["--enable-blink-features=BidiCaretAffinity,EditingNG"]
   },
   {
+    "prefix": "passive-fingerprinting",
+    "base": "http/tests/navigation/useragent.php",
+    "args": ["--enable-features=FreezeUserAgent"]
+  },
+  {
+    "prefix": "passive-fingerprinting",
+    "base": "http/tests/navigation/frozen-useragent.html",
+    "args": ["--enable-features=FreezeUserAgent"]
+  },
+  {
     "prefix": "insecure-device-sensor-events",
     "base": "http/tests/security/powerfulFeatureRestrictions/",
     "args": ["--disable-features=RestrictDeviceSensorEventsToSecureContexts"]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index c2f1d2130..f8029f24 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -35737,6 +35737,18 @@
      {}
     ]
    ],
+   "css/css-break/form-control.html": [
+    [
+     "css/css-break/form-control.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-break/line-after-unbreakable-float-after-padding.html": [
     [
      "css/css-break/line-after-unbreakable-float-after-padding.html",
@@ -39805,6 +39817,30 @@
      {}
     ]
    ],
+   "css/css-display/display-change-iframe.html": [
+    [
+     "css/css-display/display-change-iframe.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-display/display-change-object-iframe.html": [
+    [
+     "css/css-display/display-change-object-iframe.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-display/display-contents-alignment-001.html": [
     [
      "css/css-display/display-contents-alignment-001.html",
@@ -40369,6 +40405,18 @@
      {}
     ]
    ],
+   "css/css-display/display-contents-shadow-dom-1.html": [
+    [
+     "css/css-display/display-contents-shadow-dom-1.html",
+     [
+      [
+       "/css/css-display/display-contents-shadow-dom-1-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-display/display-contents-shadow-host-whitespace.html": [
     [
      "css/css-display/display-contents-shadow-host-whitespace.html",
@@ -46763,6 +46811,18 @@
      {}
     ]
    ],
+   "css/css-fonts/quoted-generic-ignored.html": [
+    [
+     "css/css-fonts/quoted-generic-ignored.html",
+     [
+      [
+       "/css/css-fonts/quoted-generic-ignored-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-fonts/variations/font-descriptor-range-reversed.html": [
     [
      "css/css-fonts/variations/font-descriptor-range-reversed.html",
@@ -51647,9 +51707,9 @@
      {}
     ]
    ],
-   "css/css-lists/counter-reset-increment-display-contents.html": [
+   "css/css-lists/counter-reset-increment-set-display-contents.html": [
     [
-     "css/css-lists/counter-reset-increment-display-contents.html",
+     "css/css-lists/counter-reset-increment-set-display-contents.html",
      [
       [
        "/css/css-lists/counter-7-ref.html",
@@ -51659,9 +51719,9 @@
      {}
     ]
    ],
-   "css/css-lists/counter-reset-increment-display-none.html": [
+   "css/css-lists/counter-reset-increment-set-display-none.html": [
     [
-     "css/css-lists/counter-reset-increment-display-none.html",
+     "css/css-lists/counter-reset-increment-set-display-none.html",
      [
       [
        "/css/css-lists/counter-7-ref.html",
@@ -51683,6 +51743,54 @@
      {}
     ]
    ],
+   "css/css-lists/counter-set-001.html": [
+    [
+     "css/css-lists/counter-set-001.html",
+     [
+      [
+       "/css/css-lists/counter-set-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/counter-set-002.html": [
+    [
+     "css/css-lists/counter-set-002.html",
+     [
+      [
+       "/css/css-lists/counter-set-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/li-list-item-counter.html": [
+    [
+     "css/css-lists/li-list-item-counter.html",
+     [
+      [
+       "/css/css-lists/li-list-item-counter-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-lists/li-value-counter-reset-001.html": [
+    [
+     "css/css-lists/li-value-counter-reset-001.html",
+     [
+      [
+       "/css/css-lists/li-value-counter-reset-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-lists/li-with-height-001.html": [
     [
      "css/css-lists/li-with-height-001.html",
@@ -55463,6 +55571,54 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-span-all-button-001.html": [
+    [
+     "css/css-multicol/multicol-span-all-button-001.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-button-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-multicol/multicol-span-all-button-002.html": [
+    [
+     "css/css-multicol/multicol-span-all-button-002.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-button-002-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-multicol/multicol-span-all-button-003.html": [
+    [
+     "css/css-multicol/multicol-span-all-button-003.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-button-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-multicol/multicol-span-all-children-height-001.html": [
+    [
+     "css/css-multicol/multicol-span-all-children-height-001.html",
+     [
+      [
+       "/css/css-multicol/multicol-span-all-children-height-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-span-all-dynamic-add-001.html": [
     [
      "css/css-multicol/multicol-span-all-dynamic-add-001.html",
@@ -57419,6 +57575,18 @@
      {}
     ]
    ],
+   "css/css-position/fixed-z-index-blend.html": [
+    [
+     "css/css-position/fixed-z-index-blend.html",
+     [
+      [
+       "/css/css-position/fixed-z-index-blend-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-position/hypothetical-box-scroll-parent.html": [
     [
      "css/css-position/hypothetical-box-scroll-parent.html",
@@ -57659,6 +57827,18 @@
      {}
     ]
    ],
+   "css/css-position/position-sticky-change-top.html": [
+    [
+     "css/css-position/position-sticky-change-top.html",
+     [
+      [
+       "/css/css-position/position-sticky-change-top-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-position/position-sticky-child-multicolumn.html": [
     [
      "css/css-position/position-sticky-child-multicolumn.html",
@@ -58355,6 +58535,42 @@
      {}
     ]
    ],
+   "css/css-pseudo/marker-content-009.html": [
+    [
+     "css/css-pseudo/marker-content-009.html",
+     [
+      [
+       "/css/css-pseudo/marker-content-009-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-pseudo/marker-content-010.html": [
+    [
+     "css/css-pseudo/marker-content-010.html",
+     [
+      [
+       "/css/css-pseudo/marker-content-010-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-pseudo/marker-content-011.html": [
+    [
+     "css/css-pseudo/marker-content-011.html",
+     [
+      [
+       "/css/css-pseudo/marker-content-011-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-pseudo/marker-display-dynamic-001.html": [
     [
      "css/css-pseudo/marker-display-dynamic-001.html",
@@ -59099,6 +59315,150 @@
      {}
     ]
    ],
+   "css/css-scroll-snap/scroll-target-align-001.html": [
+    [
+     "css/css-scroll-snap/scroll-target-align-001.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-align-002.html": [
+    [
+     "css/css-scroll-snap/scroll-target-align-002.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-align-003.html": [
+    [
+     "css/css-scroll-snap/scroll-target-align-003.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-margin-001.html": [
+    [
+     "css/css-scroll-snap/scroll-target-margin-001.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-margin-002.html": [
+    [
+     "css/css-scroll-snap/scroll-target-margin-002.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-margin-003.html": [
+    [
+     "css/css-scroll-snap/scroll-target-margin-003.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-padding-001.html": [
+    [
+     "css/css-scroll-snap/scroll-target-padding-001.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-padding-002.html": [
+    [
+     "css/css-scroll-snap/scroll-target-padding-002.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-padding-003.html": [
+    [
+     "css/css-scroll-snap/scroll-target-padding-003.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-snap-001.html": [
+    [
+     "css/css-scroll-snap/scroll-target-snap-001.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-snap-002.html": [
+    [
+     "css/css-scroll-snap/scroll-target-snap-002.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-snap-003.html": [
+    [
+     "css/css-scroll-snap/scroll-target-snap-003.html",
+     [
+      [
+       "/css/css-scroll-snap/scroll-target-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-scrollbars/textarea-scrollbar-width-none.html": [
     [
      "css/css-scrollbars/textarea-scrollbar-width-none.html",
@@ -60539,6 +60899,102 @@
      {}
     ]
    ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-001.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-001.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-002.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-002.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-003.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-003.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-004.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-004.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-005.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-005.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-006.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-006.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-007.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-007.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-008.html": [
+    [
+     "css/css-sizing/image-min-max-content-intrinsic-size-change-008.html",
+     [
+      [
+       "/css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-sizing/image-percentage-max-height-in-anonymous-block.html": [
     [
      "css/css-sizing/image-percentage-max-height-in-anonymous-block.html",
@@ -64451,6 +64907,42 @@
      {}
     ]
    ],
+   "css/css-text/line-breaking/line-breaking-015.html": [
+    [
+     "css/css-text/line-breaking/line-breaking-015.html",
+     [
+      [
+       "/css/css-text/line-breaking/reference/line-breaking-015-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/line-breaking/line-breaking-016.html": [
+    [
+     "css/css-text/line-breaking/line-breaking-016.html",
+     [
+      [
+       "/css/css-text/line-breaking/reference/line-breaking-016-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-text/line-breaking/line-breaking-017.html": [
+    [
+     "css/css-text/line-breaking/line-breaking-017.html",
+     [
+      [
+       "/css/css-text/line-breaking/reference/line-breaking-017-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/line-breaking/line-breaking-atomic-001.html": [
     [
      "css/css-text/line-breaking/line-breaking-atomic-001.html",
@@ -66383,6 +66875,18 @@
      {}
     ]
    ],
+   "css/css-text/text-transform/text-transform-multiple-001.html": [
+    [
+     "css/css-text/text-transform/text-transform-multiple-001.html",
+     [
+      [
+       "/css/css-text/text-transform/reference/text-transform-multiple-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-text/text-transform/text-transform-none-001.xht": [
     [
      "css/css-text/text-transform/text-transform-none-001.xht",
@@ -94045,6 +94549,18 @@
      {}
     ]
    ],
+   "css/cssom/HTMLLinkElement-disabled-alternate.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-alternate.tentative.html",
+     [
+      [
+       "/css/cssom/HTMLLinkElement-disabled-alternate-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/cssom/insertRule-from-script.html": [
     [
      "css/cssom/insertRule-from-script.html",
@@ -97405,6 +97921,18 @@
      {}
     ]
    ],
+   "css/selectors/sharing-in-svg-use.html": [
+    [
+     "css/selectors/sharing-in-svg-use.html",
+     [
+      [
+       "/css/selectors/sharing-in-svg-use-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-content-001.html": [
     [
      "css/vendor-imports/mozilla/mozilla-central-reftests/align3/flex-abspos-staticpos-align-content-001.html",
@@ -109153,6 +109681,18 @@
      {}
     ]
    ],
+   "html/semantics/grouping-content/the-li-element/grouping-li-reftest-003.html": [
+    [
+     "html/semantics/grouping-content/the-li-element/grouping-li-reftest-003.html",
+     [
+      [
+       "/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/semantics/grouping-content/the-li-element/grouping-li-reftest-display-list-item.html": [
     [
      "html/semantics/grouping-content/the-li-element/grouping-li-reftest-display-list-item.html",
@@ -109985,6 +110525,70 @@
      }
     ]
    ],
+   "infrastructure/reftest/reftest_fuzzy_no_differences.html": [
+    [
+     "infrastructure/reftest/reftest_fuzzy_no_differences.html",
+     [
+      [
+       "/infrastructure/reftest/fuzzy-ref-1.html",
+       "=="
+      ]
+     ],
+     {
+      "fuzzy": [
+       [
+        [
+         "/infrastructure/reftest/reftest_fuzzy_no_differences.html",
+         "/infrastructure/reftest/fuzzy-ref-1.html",
+         "=="
+        ],
+        [
+         [
+          128,
+          128
+         ],
+         [
+          0,
+          100
+         ]
+        ]
+       ]
+      ]
+     }
+    ]
+   ],
+   "infrastructure/reftest/reftest_fuzzy_no_differences_1.html": [
+    [
+     "infrastructure/reftest/reftest_fuzzy_no_differences_1.html",
+     [
+      [
+       "/infrastructure/reftest/fuzzy-ref-1.html",
+       "=="
+      ]
+     ],
+     {
+      "fuzzy": [
+       [
+        [
+         "/infrastructure/reftest/reftest_fuzzy_no_differences_1.html",
+         "/infrastructure/reftest/fuzzy-ref-1.html",
+         "=="
+        ],
+        [
+         [
+          0,
+          128
+         ],
+         [
+          100,
+          100
+         ]
+        ]
+       ]
+      ]
+     }
+    ]
+   ],
    "infrastructure/reftest/reftest_match.html": [
     [
      "infrastructure/reftest/reftest_match.html",
@@ -117976,6 +118580,21 @@
      {}
     ]
    ],
+   "FileAPI/reading-data-section/filereader_events.any-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "FileAPI/reading-data-section/filereader_events.any.worker-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "FileAPI/reading-data-section/filereader_result-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "FileAPI/reading-data-section/support/blue-100x100.png": [
     [
      {}
@@ -120471,6 +121090,11 @@
      {}
     ]
    ],
+   "common/security-features/resources/common.js.headers": [
+    [
+     {}
+    ]
+   ],
    "common/security-features/scope/document.py": [
     [
      {}
@@ -120481,11 +121105,21 @@
      {}
     ]
    ],
+   "common/security-features/scope/template/worker.js.template": [
+    [
+     {}
+    ]
+   ],
    "common/security-features/scope/util.py": [
     [
      {}
     ]
    ],
+   "common/security-features/scope/worker.py": [
+    [
+     {}
+    ]
+   ],
    "common/security-features/subresource/__init__.py": [
     [
      {}
@@ -120751,26 +121385,6 @@
      {}
     ]
    ],
-   "console/console-label-conversion.any-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "console/console-label-conversion.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "console/idlharness.any-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "console/idlharness.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "content-security-policy/META.yml": [
     [
      {}
@@ -131791,6 +132405,11 @@
      {}
     ]
    ],
+   "css/css-display/display-contents-shadow-dom-1-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-display/display-contents-sharing-001-ref.html": [
     [
      {}
@@ -131861,6 +132480,11 @@
      {}
     ]
    ],
+   "css/css-display/support/red-square.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-display/support/swatch-orange.png": [
     [
      {}
@@ -133921,6 +134545,11 @@
      {}
     ]
    ],
+   "css/css-fonts/quoted-generic-ignored-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-fonts/support/100x100-lime.png": [
     [
      {}
@@ -142241,6 +142870,16 @@
      {}
     ]
    ],
+   "css/css-grid/parsing/grid-auto-flow-computed-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-grid/parsing/grid-auto-flow-valid-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-grid/reference/display-grid-ref.html": [
     [
      {}
@@ -142846,6 +143485,26 @@
      {}
     ]
    ],
+   "css/css-lists/counter-set-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-lists/counter-set-002-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-lists/li-list-item-counter-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-lists/li-value-counter-reset-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-lists/li-with-height-001-ref.html": [
     [
      {}
@@ -143781,6 +144440,26 @@
      {}
     ]
    ],
+   "css/css-multicol/multicol-span-all-button-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-multicol/multicol-span-all-button-002-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-multicol/multicol-span-all-button-003-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-multicol/multicol-span-all-children-height-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-multicol/multicol-span-all-dynamic-add-001-ref.html": [
     [
      {}
@@ -144536,6 +145215,11 @@
      {}
     ]
    ],
+   "css/css-position/fixed-z-index-blend-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-position/hypothetical-box-scroll-parent-ref.html": [
     [
      {}
@@ -144586,6 +145270,11 @@
      {}
     ]
    ],
+   "css/css-position/position-sticky-change-top-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-position/position-sticky-child-multicolumn-ref.html": [
     [
      {}
@@ -144821,6 +145510,21 @@
      {}
     ]
    ],
+   "css/css-pseudo/marker-content-009-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-pseudo/marker-content-010-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-pseudo/marker-content-011-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-pseudo/marker-font-properties-ref.html": [
     [
      {}
@@ -144976,6 +145680,16 @@
      {}
     ]
    ],
+   "css/css-scroll-snap/inheritance-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/overflowing-snap-areas-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-scroll-snap/parsing/scroll-margin-block-invalid-expected.txt": [
     [
      {}
@@ -145006,11 +145720,51 @@
      {}
     ]
    ],
+   "css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-snap-type-on-root-element-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/scroll-target-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-scroll-snap/snap-inline-block-expected.txt": [
     [
      {}
     ]
    ],
+   "css/css-scroll-snap/snap-to-visible-areas-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/support/scroll-target-align-001-iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/support/scroll-target-margin-001-iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/support/scroll-target-padding-001-iframe.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-scroll-snap/support/scroll-target-snap-001-iframe.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-scrollbars/META.yml": [
     [
      {}
@@ -145636,6 +146390,26 @@
      {}
     ]
    ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-sizing/intrinsic-percent-non-replaced-001-ref.html": [
     [
      {}
@@ -147656,6 +148430,21 @@
      {}
     ]
    ],
+   "css/css-text/line-breaking/reference/line-breaking-015-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-text/line-breaking/reference/line-breaking-016-ref.html": [
+    [
+     {}
+    ]
+   ],
+   "css/css-text/line-breaking/reference/line-breaking-017-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-text/line-breaking/reference/line-breaking-atomic-003-ref.html": [
     [
      {}
@@ -148561,6 +149350,11 @@
      {}
     ]
    ],
+   "css/css-text/text-transform/reference/text-transform-multiple-001-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-text/text-transform/reference/text-transform-none-001-ref.xht": [
     [
      {}
@@ -150771,6 +151565,11 @@
      {}
     ]
    ],
+   "css/css-transitions/non-rendered-element-001-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "css/css-transitions/parsing/transition-timing-function-valid-expected.txt": [
     [
      {}
@@ -156406,6 +157205,26 @@
      {}
     ]
    ],
+   "css/cssom/HTMLLinkElement-disabled-001.tentative-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-002.tentative-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-007.tentative-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-alternate-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/cssom/META.yml": [
     [
      {}
@@ -157741,6 +158560,11 @@
      {}
     ]
    ],
+   "css/selectors/sharing-in-svg-use-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/selectors/user-invalid-expected.txt": [
     [
      {}
@@ -168111,6 +168935,26 @@
      {}
     ]
    ],
+   "html/cross-origin-opener/new_window_same_site.html.headers": [
+    [
+     {}
+    ]
+   ],
+   "html/cross-origin-opener/resources/postback.sub.html": [
+    [
+     {}
+    ]
+   ],
+   "html/cross-origin-opener/resources/window.sub.html": [
+    [
+     {}
+    ]
+   ],
+   "html/cross-origin-opener/resources/window.sub.html.headers": [
+    [
+     {}
+    ]
+   ],
    "html/dom/documents/dom-tree-accessors/OWNERS": [
     [
      {}
@@ -175336,6 +176180,11 @@
      {}
     ]
    ],
+   "html/semantics/forms/the-form-element/form-autocomplete-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/forms/the-form-element/form-indexed-element-expected.txt": [
     [
      {}
@@ -175476,6 +176325,11 @@
      {}
     ]
    ],
+   "html/semantics/grouping-content/the-li-element/grouping-li-reftest-003-ref.html": [
+    [
+     {}
+    ]
+   ],
    "html/semantics/grouping-content/the-li-element/grouping-li-reftest-display-list-item-ref.html": [
     [
      {}
@@ -180606,11 +181460,6 @@
      {}
     ]
    ],
-   "mediacapture-streams/MediaDevices-getSupportedConstraints-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "mediacapture-streams/MediaStream-MediaElement-preload-none.https-expected.txt": [
     [
      {}
@@ -180651,11 +181500,6 @@
      {}
     ]
    ],
-   "mediacapture-streams/idlharness.https.window-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "mediacapture-streams/idlharness.window-expected.txt": [
     [
      {}
@@ -182336,6 +183180,11 @@
      {}
     ]
    ],
+   "payment-handler/app-change-payment-method.js": [
+    [
+     {}
+    ]
+   ],
    "payment-handler/basic-card.js": [
     [
      {}
@@ -182356,6 +183205,11 @@
      {}
     ]
    ],
+   "payment-handler/change-payment-method.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "payment-handler/idlharness.https.any.serviceworker-expected.txt": [
     [
      {}
@@ -182591,26 +183445,6 @@
      {}
     ]
    ],
-   "performance-timeline/idlharness.any-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "performance-timeline/idlharness.any.serviceworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "performance-timeline/idlharness.any.sharedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "performance-timeline/idlharness.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "performance-timeline/performanceobservers.js": [
     [
      {}
@@ -198831,26 +199665,6 @@
      {}
     ]
    ],
-   "user-timing/idlharness.any-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "user-timing/idlharness.any.serviceworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "user-timing/idlharness.any.sharedworker-expected.txt": [
-    [
-     {}
-    ]
-   ],
-   "user-timing/idlharness.any.worker-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "user-timing/resources/user-timing-helper.js": [
     [
      {}
@@ -199256,6 +200070,11 @@
      {}
     ]
    ],
+   "web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "web-animations/animation-model/keyframe-effects/effect-value-context-filling-expected.txt": [
     [
      {}
@@ -200506,11 +201325,21 @@
      {}
     ]
    ],
+   "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt": [
     [
      {}
     ]
    ],
+   "webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webrtc-identity/identity-helper.sub.js": [
     [
      {}
@@ -200696,6 +201525,11 @@
      {}
     ]
    ],
+   "webrtc/RTCPeerConnection-removeTrack.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt": [
     [
      {}
@@ -210512,6 +211346,10 @@
        [
         "script",
         "../support/Blob.js"
+       ],
+       [
+        "script",
+        "../../streams/resources/test-utils.js"
        ]
       ]
      }
@@ -210527,6 +211365,10 @@
        [
         "script",
         "../support/Blob.js"
+       ],
+       [
+        "script",
+        "../../streams/resources/test-utils.js"
        ]
       ]
      }
@@ -210672,6 +211514,16 @@
      {}
     ]
    ],
+   "FileAPI/reading-data-section/filereader_events.any.js": [
+    [
+     "FileAPI/reading-data-section/filereader_events.any.html",
+     {}
+    ],
+    [
+     "FileAPI/reading-data-section/filereader_events.any.worker.html",
+     {}
+    ]
+   ],
    "FileAPI/reading-data-section/filereader_readAsArrayBuffer.html": [
     [
      "FileAPI/reading-data-section/filereader_readAsArrayBuffer.html",
@@ -220304,6 +221156,12 @@
      {}
     ]
    ],
+   "animation-worklet/worklet-animation-without-target.https.html": [
+    [
+     "animation-worklet/worklet-animation-without-target.https.html",
+     {}
+    ]
+   ],
    "apng/supported-in-source-type.html": [
     [
      "apng/supported-in-source-type.html",
@@ -226549,6 +227407,12 @@
      {}
     ]
    ],
+   "css/css-animations/animationevent-marker-pseudoelement.html": [
+    [
+     "css/css-animations/animationevent-marker-pseudoelement.html",
+     {}
+    ]
+   ],
    "css/css-animations/animationevent-pseudoelement.html": [
     [
      "css/css-animations/animationevent-pseudoelement.html",
@@ -230471,6 +231335,12 @@
      {}
     ]
    ],
+   "css/css-lists/li-counter-increment-computed-style.html": [
+    [
+     "css/css-lists/li-counter-increment-computed-style.html",
+     {}
+    ]
+   ],
    "css/css-lists/list-and-block-textarea-001.html": [
     [
      "css/css-lists/list-and-block-textarea-001.html",
@@ -231383,6 +232253,12 @@
      {}
     ]
    ],
+   "css/css-position/position-absolute-crash-chrome-006.html": [
+    [
+     "css/css-position/position-absolute-crash-chrome-006.html",
+     {}
+    ]
+   ],
    "css/css-position/position-absolute-dynamic-containing-block.html": [
     [
      "css/css-position/position-absolute-dynamic-containing-block.html",
@@ -232061,12 +232937,24 @@
      {}
     ]
    ],
+   "css/css-scroll-snap/scroll-padding.html": [
+    [
+     "css/css-scroll-snap/scroll-padding.html",
+     {}
+    ]
+   ],
    "css/css-scroll-snap/scroll-snap-stop-always.html": [
     [
      "css/css-scroll-snap/scroll-snap-stop-always.html",
      {}
     ]
    ],
+   "css/css-scroll-snap/scroll-snap-type-on-root-element.html": [
+    [
+     "css/css-scroll-snap/scroll-snap-type-on-root-element.html",
+     {}
+    ]
+   ],
    "css/css-scroll-snap/scroll-snap-type-proximity.html": [
     [
      "css/css-scroll-snap/scroll-snap-type-proximity.html",
@@ -232085,12 +232973,24 @@
      {}
     ]
    ],
+   "css/css-scroll-snap/snap-to-transformed-target.html": [
+    [
+     "css/css-scroll-snap/snap-to-transformed-target.html",
+     {}
+    ]
+   ],
    "css/css-scroll-snap/snap-to-visible-areas.html": [
     [
      "css/css-scroll-snap/snap-to-visible-areas.html",
      {}
     ]
    ],
+   "css/css-scroll-snap/unreachable-snap-positions.html": [
+    [
+     "css/css-scroll-snap/unreachable-snap-positions.html",
+     {}
+    ]
+   ],
    "css/css-scrollbars/auto-scrollbar-inline-children.html": [
     [
      "css/css-scrollbars/auto-scrollbar-inline-children.html",
@@ -235223,9 +236123,9 @@
      {}
     ]
    ],
-   "css/css-transitions/detached-container-001.html": [
+   "css/css-transitions/disconnected-element-001.html": [
     [
-     "css/css-transitions/detached-container-001.html",
+     "css/css-transitions/disconnected-element-001.html",
      {}
     ]
    ],
@@ -235277,12 +236177,6 @@
      {}
     ]
    ],
-   "css/css-transitions/hidden-container-001.html": [
-    [
-     "css/css-transitions/hidden-container-001.html",
-     {}
-    ]
-   ],
    "css/css-transitions/historical.html": [
     [
      "css/css-transitions/historical.html",
@@ -235301,6 +236195,18 @@
      {}
     ]
    ],
+   "css/css-transitions/non-rendered-element-001.html": [
+    [
+     "css/css-transitions/non-rendered-element-001.html",
+     {}
+    ]
+   ],
+   "css/css-transitions/non-rendered-element-002.html": [
+    [
+     "css/css-transitions/non-rendered-element-002.html",
+     {}
+    ]
+   ],
    "css/css-transitions/parsing/transition-delay-computed.html": [
     [
      "css/css-transitions/parsing/transition-delay-computed.html",
@@ -237841,6 +238747,12 @@
      {}
     ]
    ],
+   "css/css-values/calc-rgb-percent-001.html": [
+    [
+     "css/css-values/calc-rgb-percent-001.html",
+     {}
+    ]
+   ],
    "css/css-values/calc-rounding-001.html": [
     [
      "css/css-values/calc-rounding-001.html",
@@ -237877,12 +238789,24 @@
      {}
     ]
    ],
+   "css/css-values/getComputedStyle-border-radius-001.html": [
+    [
+     "css/css-values/getComputedStyle-border-radius-001.html",
+     {}
+    ]
+   ],
    "css/css-values/getComputedStyle-border-radius-002.html": [
     [
      "css/css-values/getComputedStyle-border-radius-002.html",
      {}
     ]
    ],
+   "css/css-values/getComputedStyle-border-radius-003.html": [
+    [
+     "css/css-values/getComputedStyle-border-radius-003.html",
+     {}
+    ]
+   ],
    "css/css-values/lh-rlh-on-root-001.html": [
     [
      "css/css-values/lh-rlh-on-root-001.html",
@@ -238945,6 +239869,12 @@
      {}
     ]
    ],
+   "css/cssom-view/matchMedia-display-none-iframe.html": [
+    [
+     "css/cssom-view/matchMedia-display-none-iframe.html",
+     {}
+    ]
+   ],
    "css/cssom-view/matchMedia.xht": [
     [
      "css/cssom-view/matchMedia.xht",
@@ -239013,6 +239943,12 @@
      {}
     ]
    ],
+   "css/cssom-view/resize-event-on-initial-layout.html": [
+    [
+     "css/cssom-view/resize-event-on-initial-layout.html",
+     {}
+    ]
+   ],
    "css/cssom-view/screenLeftTop.html": [
     [
      "css/cssom-view/screenLeftTop.html",
@@ -239277,6 +240213,48 @@
      {}
     ]
    ],
+   "css/cssom/HTMLLinkElement-disabled-001.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-001.tentative.html",
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-002.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-002.tentative.html",
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-003.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-003.tentative.html",
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-004.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-004.tentative.html",
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-005.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-005.tentative.html",
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-006.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-006.tentative.html",
+     {}
+    ]
+   ],
+   "css/cssom/HTMLLinkElement-disabled-007.tentative.html": [
+    [
+     "css/cssom/HTMLLinkElement-disabled-007.tentative.html",
+     {}
+    ]
+   ],
    "css/cssom/MediaList.html": [
     [
      "css/cssom/MediaList.html",
@@ -244138,6 +245116,12 @@
      {}
     ]
    ],
+   "element-timing/image-not-added.html": [
+    [
+     "element-timing/image-not-added.html",
+     {}
+    ]
+   ],
    "element-timing/image-not-fully-visible.html": [
     [
      "element-timing/image-not-fully-visible.html",
@@ -260475,6 +261459,12 @@
      {}
     ]
    ],
+   "html/cross-origin-opener/new_window_same_site.html": [
+    [
+     "html/cross-origin-opener/new_window_same_site.html",
+     {}
+    ]
+   ],
    "html/dom/documents/dom-tree-accessors/Document.body.html": [
     [
      "html/dom/documents/dom-tree-accessors/Document.body.html",
@@ -261603,6 +262593,12 @@
      }
     ]
    ],
+   "html/interaction/focus/focus-file-input.html": [
+    [
+     "html/interaction/focus/focus-file-input.html",
+     {}
+    ]
+   ],
    "html/interaction/focus/focus-management/focus-event-targets-simple.html": [
     [
      "html/interaction/focus/focus-management/focus-event-targets-simple.html",
@@ -264137,6 +265133,12 @@
      {}
     ]
    ],
+   "html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html": [
+    [
+     "html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html",
+     {}
+    ]
+   ],
    "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html": [
     [
      "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html",
@@ -265729,6 +266731,12 @@
      {}
     ]
    ],
+   "html/semantics/forms/textfieldselection/textarea-selection-while-parsing.xhtml": [
+    [
+     "html/semantics/forms/textfieldselection/textarea-selection-while-parsing.xhtml",
+     {}
+    ]
+   ],
    "html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html": [
     [
      "html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html",
@@ -273004,6 +274012,12 @@
      {}
     ]
    ],
+   "intersection-observer/v2/inline-occlusion.html": [
+    [
+     "intersection-observer/v2/inline-occlusion.html",
+     {}
+    ]
+   ],
    "intersection-observer/v2/scaled-target.html": [
     [
      "intersection-observer/v2/scaled-target.html",
@@ -273028,6 +274042,12 @@
      {}
     ]
    ],
+   "intersection-observer/v2/text-editor-occlusion.html": [
+    [
+     "intersection-observer/v2/text-editor-occlusion.html",
+     {}
+    ]
+   ],
    "intersection-observer/v2/text-shadow.html": [
     [
      "intersection-observer/v2/text-shadow.html",
@@ -273250,6 +274270,12 @@
      {}
     ]
    ],
+   "lifecycle/child-out-of-viewport.tentative.html": [
+    [
+     "lifecycle/child-out-of-viewport.tentative.html",
+     {}
+    ]
+   ],
    "lifecycle/freeze.html": [
     [
      "lifecycle/freeze.html",
@@ -273460,6 +274486,18 @@
      {}
     ]
    ],
+   "mathml/presentation-markup/mrow/inferred-mrow-baseline.html": [
+    [
+     "mathml/presentation-markup/mrow/inferred-mrow-baseline.html",
+     {}
+    ]
+   ],
+   "mathml/presentation-markup/mrow/inferred-mrow-stretchy.html": [
+    [
+     "mathml/presentation-markup/mrow/inferred-mrow-stretchy.html",
+     {}
+    ]
+   ],
    "mathml/presentation-markup/operators/mo-axis-height-1.html": [
     [
      "mathml/presentation-markup/operators/mo-axis-height-1.html",
@@ -274409,9 +275447,9 @@
      {}
     ]
    ],
-   "mediacapture-streams/MediaDevices-getSupportedConstraints.html": [
+   "mediacapture-streams/MediaDevices-getSupportedConstraints.https.html": [
     [
-     "mediacapture-streams/MediaDevices-getSupportedConstraints.html",
+     "mediacapture-streams/MediaDevices-getSupportedConstraints.https.html",
      {}
     ]
    ],
@@ -287741,6 +288779,14 @@
      {}
     ]
    ],
+   "payment-handler/change-payment-method.https.html": [
+    [
+     "payment-handler/change-payment-method.https.html",
+     {
+      "testdriver": true
+     }
+    ]
+   ],
    "payment-handler/idlharness.https.any.js": [
     [
      "payment-handler/idlharness.https.any.html",
@@ -299882,9 +300928,25 @@
      }
     ]
    ],
-   "resource-timing/nested-context-navigations.html": [
+   "resource-timing/nested-context-navigations-embed.html": [
     [
-     "resource-timing/nested-context-navigations.html",
+     "resource-timing/nested-context-navigations-embed.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "resource-timing/nested-context-navigations-iframe.html": [
+    [
+     "resource-timing/nested-context-navigations-iframe.html",
+     {
+      "timeout": "long"
+     }
+    ]
+   ],
+   "resource-timing/nested-context-navigations-object.html": [
+    [
+     "resource-timing/nested-context-navigations-object.html",
      {
       "timeout": "long"
      }
@@ -311033,6 +312095,12 @@
      {}
     ]
    ],
+   "user-timing/mark-entry-constructor.html": [
+    [
+     "user-timing/mark-entry-constructor.html",
+     {}
+    ]
+   ],
    "user-timing/mark-errors.html": [
     [
      "user-timing/mark-errors.html",
@@ -311079,6 +312147,12 @@
      {}
     ]
    ],
+   "user-timing/measure-exceptions.html": [
+    [
+     "user-timing/measure-exceptions.html",
+     {}
+    ]
+   ],
    "user-timing/measure-l3.html": [
     [
      "user-timing/measure-l3.html",
@@ -313514,6 +314588,12 @@
      {}
     ]
    ],
+   "web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html": [
+    [
+     "web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html",
+     {}
+    ]
+   ],
    "web-animations/animation-model/keyframe-effects/effect-value-context-filling.html": [
     [
      "web-animations/animation-model/keyframe-effects/effect-value-context-filling.html",
@@ -315879,6 +316959,12 @@
      {}
     ]
    ],
+   "webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html": [
+    [
+     "webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html",
+     {}
+    ]
+   ],
    "webaudio/the-audio-api/the-delaynode-interface/ctor-delay.html": [
     [
      "webaudio/the-audio-api/the-delaynode-interface/ctor-delay.html",
@@ -316017,6 +317103,12 @@
      {}
     ]
    ],
+   "webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/ctor-mediastreamaudiodestination.html": [
+    [
+     "webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/ctor-mediastreamaudiodestination.html",
+     {}
+    ]
+   ],
    "webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html": [
     [
      "webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html",
@@ -316549,6 +317641,12 @@
      {}
     ]
    ],
+   "webmessaging/message-channels/worker-post-after-close.html": [
+    [
+     "webmessaging/message-channels/worker-post-after-close.html",
+     {}
+    ]
+   ],
    "webmessaging/message-channels/worker.html": [
     [
      "webmessaging/message-channels/worker.html",
@@ -317046,15 +318144,15 @@
      {}
     ]
    ],
-   "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html": [
+   "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html": [
     [
-     "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html",
+     "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html",
      {}
     ]
    ],
-   "webrtc-identity/RTCPeerConnection-peerIdentity.html": [
+   "webrtc-identity/RTCPeerConnection-peerIdentity.https.html": [
     [
-     "webrtc-identity/RTCPeerConnection-peerIdentity.html",
+     "webrtc-identity/RTCPeerConnection-peerIdentity.https.html",
      {}
     ]
    ],
@@ -317172,7 +318270,9 @@
    "webrtc/RTCDataChannel-send.html": [
     [
      "webrtc/RTCDataChannel-send.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "webrtc/RTCDataChannelEvent-constructor.html": [
@@ -317592,7 +318692,9 @@
    "webrtc/RTCRtpTransceiver.https.html": [
     [
      "webrtc/RTCRtpTransceiver.https.html",
-     {}
+     {
+      "timeout": "long"
+     }
     ]
    ],
    "webrtc/RTCSctpTransport-constructor.html": [
@@ -324865,10 +325967,28 @@
      {}
     ]
    ],
-   "xhr/event-abort.htm": [
+   "xhr/event-abort.any.js": [
     [
-     "xhr/event-abort.htm",
-     {}
+     "xhr/event-abort.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: abort event"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-abort.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: abort event"
+       ]
+      ]
+     }
     ]
    ],
    "xhr/event-error-order.sub.html": [
@@ -324877,80 +325997,326 @@
      {}
     ]
    ],
-   "xhr/event-error.sub.html": [
+   "xhr/event-error.sub.any.js": [
     [
-     "xhr/event-error.sub.html",
-     {}
-    ]
-   ],
-   "xhr/event-load.htm": [
-    [
-     "xhr/event-load.htm",
-     {}
-    ]
-   ],
-   "xhr/event-loadend.htm": [
-    [
-     "xhr/event-loadend.htm",
-     {}
-    ]
-   ],
-   "xhr/event-loadstart-upload.htm": [
-    [
-     "xhr/event-loadstart-upload.htm",
-     {}
-    ]
-   ],
-   "xhr/event-loadstart.htm": [
-    [
-     "xhr/event-loadstart.htm",
-     {}
-    ]
-   ],
-   "xhr/event-progress.htm": [
-    [
-     "xhr/event-progress.htm",
+     "xhr/event-error.sub.any.html",
      {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest Test: event - error"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-error.sub.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest Test: event - error"
+       ]
+      ]
+     }
+    ]
+   ],
+   "xhr/event-load.any.js": [
+    [
+     "xhr/event-load.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: The send() method: Fire an event named load (synchronous flag is unset)"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-load.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: The send() method: Fire an event named load (synchronous flag is unset)"
+       ]
+      ]
+     }
+    ]
+   ],
+   "xhr/event-loadend.any.js": [
+    [
+     "xhr/event-loadend.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: loadend event"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-loadend.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: loadend event"
+       ]
+      ]
+     }
+    ]
+   ],
+   "xhr/event-loadstart-upload.any.js": [
+    [
+     "xhr/event-loadstart-upload.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: The send() method: Fire a progress event named loadstart on upload object (synchronous flag is unset)"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-loadstart-upload.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: The send() method: Fire a progress event named loadstart on upload object (synchronous flag is unset)"
+       ]
+      ]
+     }
+    ]
+   ],
+   "xhr/event-loadstart.any.js": [
+    [
+     "xhr/event-loadstart.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: loadstart event"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-loadstart.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: loadstart event"
+       ]
+      ]
+     }
+    ]
+   ],
+   "xhr/event-progress.any.js": [
+    [
+     "xhr/event-progress.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: The send() method: Fire a progress event named progress (synchronous flag is unset)"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
+      "timeout": "long"
+     }
+    ],
+    [
+     "xhr/event-progress.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: The send() method: Fire a progress event named progress (synchronous flag is unset)"
+       ],
+       [
+        "timeout",
+        "long"
+       ]
+      ],
       "timeout": "long"
      }
     ]
    ],
-   "xhr/event-readystate-sync-open.htm": [
+   "xhr/event-readystate-sync-open.any.js": [
     [
-     "xhr/event-readystate-sync-open.htm",
-     {}
-    ]
-   ],
-   "xhr/event-readystatechange-loaded.htm": [
-    [
-     "xhr/event-readystatechange-loaded.htm",
+     "xhr/event-readystate-sync-open.any.html",
      {
-      "timeout": "long"
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: open() call fires sync readystate event"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-readystate-sync-open.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: open() call fires sync readystate event"
+       ]
+      ]
      }
     ]
    ],
-   "xhr/event-timeout-order.htm": [
+   "xhr/event-readystatechange-loaded.any.js": [
     [
-     "xhr/event-timeout-order.htm",
-     {}
+     "xhr/event-readystatechange-loaded.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: the LOADING state change may be emitted multiple times"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-readystatechange-loaded.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: the LOADING state change may be emitted multiple times"
+       ]
+      ]
+     }
     ]
    ],
-   "xhr/event-timeout.htm": [
+   "xhr/event-timeout-order.any.js": [
     [
-     "xhr/event-timeout.htm",
-     {}
+     "xhr/event-timeout-order.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: event - timeout (order of events)"
+       ],
+       [
+        "script",
+        "resources/xmlhttprequest-event-order.js"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-timeout-order.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: event - timeout (order of events)"
+       ],
+       [
+        "script",
+        "resources/xmlhttprequest-event-order.js"
+       ]
+      ]
+     }
     ]
    ],
-   "xhr/event-upload-progress-crossorigin.htm": [
+   "xhr/event-timeout.any.js": [
     [
-     "xhr/event-upload-progress-crossorigin.htm",
-     {}
+     "xhr/event-timeout.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: timeout event"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-timeout.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: timeout event"
+       ]
+      ]
+     }
     ]
    ],
-   "xhr/event-upload-progress.htm": [
+   "xhr/event-upload-progress-crossorigin.any.js": [
     [
-     "xhr/event-upload-progress.htm",
-     {}
+     "xhr/event-upload-progress-crossorigin.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: upload progress event for cross-origin requests"
+       ],
+       [
+        "script",
+        "/common/get-host-info.sub.js"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-upload-progress-crossorigin.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: upload progress event for cross-origin requests"
+       ],
+       [
+        "script",
+        "/common/get-host-info.sub.js"
+       ]
+      ]
+     }
+    ]
+   ],
+   "xhr/event-upload-progress.any.js": [
+    [
+     "xhr/event-upload-progress.any.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: upload progress event"
+       ],
+       [
+        "script",
+        "/common/get-host-info.sub.js"
+       ]
+      ]
+     }
+    ],
+    [
+     "xhr/event-upload-progress.any.worker.html",
+     {
+      "script_metadata": [
+       [
+        "title",
+        "XMLHttpRequest: upload progress event"
+       ],
+       [
+        "script",
+        "/common/get-host-info.sub.js"
+       ]
+      ]
+     }
     ]
    ],
    "xhr/firing-events-http-content-length.html": [
@@ -333693,7 +335059,7 @@
    "support"
   ],
   ".well-known/idp-proxy/mock-idp.js": [
-   "242b4ef56f60a3472899939426246e764e842a65",
+   "e73ca22bb2ae79a6ceec2ebbf407ed22b1d0b435",
    "support"
   ],
   ".well-known/origin-policy/policy-csp-1": [
@@ -336201,7 +337567,7 @@
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-origin.sub.html": [
-   "ae8c70f9c0799c8834f0167a47e7040a5927514c",
+   "9f19f6ae66b58f93c23ba8aeb095838d9a6cc5c9",
    "testharness"
   ],
   "2dcontext/imagebitmap/createImageBitmap-sizeOverflow.html": [
@@ -338153,7 +339519,7 @@
    "support"
   ],
   "FileAPI/blob/Blob-array-buffer.any.js": [
-   "b72427fd5cfaf60ab665eb30e31a4654c4169d01",
+   "2310646e5fdeab300bcea66e4035adbdf3651685",
    "testharness"
   ],
   "FileAPI/blob/Blob-constructor-endings.html": [
@@ -338181,11 +339547,11 @@
    "testharness"
   ],
   "FileAPI/blob/Blob-stream.any.js": [
-   "894f09f8ece47cab1301b8b474285204a4b7c4f1",
+   "bd4f8dc40bca12eb10a2f471dee417d3e31075a0",
    "testharness"
   ],
   "FileAPI/blob/Blob-text.any.js": [
-   "960c96054627fce66631f7bf59516cc6797d8521",
+   "d04fa97cffe6a3d81f520f7ac92ac44e699fa004",
    "testharness"
   ],
   "FileAPI/file/File-constructor-endings.html": [
@@ -338276,6 +339642,18 @@
    "cf4524825b80cac569b63b71b4ace474a0e66c24",
    "testharness"
   ],
+  "FileAPI/reading-data-section/filereader_events.any-expected.txt": [
+   "11edeb423152e509b947fac72358bbab6277e499",
+   "support"
+  ],
+  "FileAPI/reading-data-section/filereader_events.any.js": [
+   "ac692907d119f7c8cc9c6e028df4819f27a5112e",
+   "testharness"
+  ],
+  "FileAPI/reading-data-section/filereader_events.any.worker-expected.txt": [
+   "11edeb423152e509b947fac72358bbab6277e499",
+   "support"
+  ],
   "FileAPI/reading-data-section/filereader_readAsArrayBuffer.html": [
    "31001a51a0727fbd4d1876f3aa4b6e6c860a6874",
    "testharness"
@@ -338296,8 +339674,12 @@
    "1586b8995059f7f0ee86aeca0f303345bf861bdb",
    "testharness"
   ],
+  "FileAPI/reading-data-section/filereader_result-expected.txt": [
+   "844743c0ab8cdef1dc8158870e51e7964bff240e",
+   "support"
+  ],
   "FileAPI/reading-data-section/filereader_result.html": [
-   "957d0337a752b8bccbde271c1d864de6ef33e765",
+   "b80322ed424f83edfe5470654a241844c0b12ed7",
    "testharness"
   ],
   "FileAPI/reading-data-section/support/blue-100x100.png": [
@@ -341629,7 +343011,7 @@
    "reftest"
   ],
   "animation-worklet/worklet-animation-creation.https.html": [
-   "02886c444dc6c1d68afed9ee6c130b2f85b25240",
+   "5d033b30099dc34017f54d0a3afd10278bbb31a6",
    "testharness"
   ],
   "animation-worklet/worklet-animation-duration.https.html": [
@@ -341740,6 +343122,10 @@
    "000517162af20406e39831afc0b6cefa0b367f2c",
    "reftest"
   ],
+  "animation-worklet/worklet-animation-without-target.https.html": [
+   "bfb6b4faee4ea6db233c1ca825e786bc9eafc4bf",
+   "testharness"
+  ],
   "apng/META.yml": [
    "a660c7e19ebdcb13e7457ea0bb5729e18bfe2e0e",
    "support"
@@ -343201,7 +344587,7 @@
    "support"
   ],
   "common/canvas-tests.js": [
-   "732f2a435b8194e06c7b5d89d5d6aa58b0aca2e2",
+   "2d0397b42d2e74225099155d59d62adff9d74b2d",
    "support"
   ],
   "common/canvas-tests.js.headers": [
@@ -343297,7 +344683,11 @@
    "support"
   ],
   "common/security-features/resources/common.js": [
-   "2b4349d24e56c6e8ae325aae2a18b874a7006db8",
+   "10a3190767f264cc8ec6e332ea11f3bbead59614",
+   "support"
+  ],
+  "common/security-features/resources/common.js.headers": [
+   "cb762eff806849df46dc758ef7b98b63f27f54c9",
    "support"
   ],
   "common/security-features/scope/document.py": [
@@ -343308,10 +344698,18 @@
    "feccb69e9de4cd001fd7446ffd3fa4875a906fe2",
    "support"
   ],
+  "common/security-features/scope/template/worker.js.template": [
+   "ac3fc672d1911f91daaf5141ed576053daf91d64",
+   "support"
+  ],
   "common/security-features/scope/util.py": [
    "42f8326b36aab10751cf2052354925a7ad0ca867",
    "support"
   ],
+  "common/security-features/scope/worker.py": [
+   "40817f6a3a91e202598a5f93098d0b8585a926a8",
+   "support"
+  ],
   "common/security-features/subresource/__init__.py": [
    "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
    "support"
@@ -343608,18 +345006,10 @@
    "a4aae7ffce8ac81947ab092089aefb80b117c86e",
    "testharness"
   ],
-  "console/console-label-conversion.any-expected.txt": [
-   "1fde3cad9bdf9b8817ae1af6c7b823edb00f0dc5",
-   "support"
-  ],
   "console/console-label-conversion.any.js": [
    "1fb269d4061c61112f4c3cbe609dafd80a4e0591",
    "testharness"
   ],
-  "console/console-label-conversion.any.worker-expected.txt": [
-   "1fde3cad9bdf9b8817ae1af6c7b823edb00f0dc5",
-   "support"
-  ],
   "console/console-number-format-specifiers-symbol-manual.html": [
    "f77b84e51595f3c0d7613072e82c8476caa322da",
    "manual"
@@ -343636,18 +345026,10 @@
    "3b9e5cea21da8e98a2bb8306ed9d5e642134ee5c",
    "manual"
   ],
-  "console/idlharness.any-expected.txt": [
-   "3b3bae18dfea489adf03e139283fce6ae117edf2",
-   "support"
-  ],
   "console/idlharness.any.js": [
    "1e7ba76ecddca2ad707784a7ff6edfc270428c26",
    "testharness"
   ],
-  "console/idlharness.any.worker-expected.txt": [
-   "3b3bae18dfea489adf03e139283fce6ae117edf2",
-   "support"
-  ],
   "content-security-policy/META.yml": [
    "ee8f1ea7e07b94711ddc65e43a6c32dbc5983612",
    "support"
@@ -363693,7 +365075,7 @@
    "testharness"
   ],
   "css/css-animations/CSSAnimation-canceling.tentative-expected.txt": [
-   "63c0e59118c10fdf8e246b4f93bed98e15529270",
+   "113de1a8d9a99786cb47bd118c31d95661070e9a",
    "support"
   ],
   "css/css-animations/CSSAnimation-canceling.tentative.html": [
@@ -363753,11 +365135,11 @@
    "testharness"
   ],
   "css/css-animations/Document-getAnimations.tentative-expected.txt": [
-   "b3260fa4e38696099f8749395e72403120b011bb",
+   "70dfff0455d0f221dbb6e9b638621c9edda14473",
    "support"
   ],
   "css/css-animations/Document-getAnimations.tentative.html": [
-   "c11b0a908760f4a365fb6f82e92b98341e94fb4c",
+   "175acf8424688c29e2b433226c6c4af11d176eb3",
    "testharness"
   ],
   "css/css-animations/Element-getAnimations-dynamic-changes.tentative.html": [
@@ -364096,6 +365478,10 @@
    "e35b7fcb0f98656cdeff41d8d7f4a7620fa52eea",
    "support"
   ],
+  "css/css-animations/animationevent-marker-pseudoelement.html": [
+   "90c7b86ab9d7060b5cda29158001a119944e69c0",
+   "testharness"
+  ],
   "css/css-animations/animationevent-pseudoelement.html": [
    "8de41cc613b00728ebc4642ab2fc83c73df82bc0",
    "testharness"
@@ -364117,11 +365503,11 @@
    "testharness"
   ],
   "css/css-animations/event-order.tentative-expected.txt": [
-   "8db81795fc94541163f9b8596d34e9eec08c6714",
+   "8aee80eee14a618c6f570a7cf0439f93befc6f88",
    "support"
   ],
   "css/css-animations/event-order.tentative.html": [
-   "93d452ace07163b10af18245d6799d9823448e1e",
+   "f4f9e29a3c859daaa9727fe3009f837a7ddeb1be",
    "testharness"
   ],
   "css/css-animations/historical.html": [
@@ -367964,6 +369350,10 @@
    "e2e7297d1532fba60d2074aa2701600dc7441742",
    "visual"
   ],
+  "css/css-break/form-control.html": [
+   "8ef6eedae252f36de3bfeef8c3a6db23bf6f3d89",
+   "reftest"
+  ],
   "css/css-break/hit-test-inline-fragmentation-with-border-radius.html": [
    "4d0fc7eccc45e44480b4305632ceac2068c59919",
    "testharness"
@@ -369721,7 +371111,7 @@
    "reftest"
   ],
   "css/css-contain/contain-size-grid-002.html": [
-   "1e7771e7c12b9c5c879e52071f9f566bd6e2b7d7",
+   "43361c298343117362f35596611a9faf854cea47",
    "reftest"
   ],
   "css/css-contain/contain-size-monolithic-001.html": [
@@ -370196,6 +371586,14 @@
    "16fcd21f52e486b3b08a31db15e57a7e9f032738",
    "support"
   ],
+  "css/css-display/display-change-iframe.html": [
+   "c12c413d5390aaf4ea4c71c689952bbdb62069df",
+   "reftest"
+  ],
+  "css/css-display/display-change-object-iframe.html": [
+   "8b56aff95909d88ccc9797a8fd6aa42b35c9dd4f",
+   "reftest"
+  ],
   "css/css-display/display-contents-alignment-001-ref.html": [
    "595aa7f7e5b9bb3d0c2da3afc6ae7d6ae733e241",
    "support"
@@ -370456,6 +371854,14 @@
    "82321b9c07edaf471f64829f0f0efa232aeb99c0",
    "support"
   ],
+  "css/css-display/display-contents-shadow-dom-1-ref.html": [
+   "df3aaf3374000bc08032374bc1f6d171b94d3778",
+   "support"
+  ],
+  "css/css-display/display-contents-shadow-dom-1.html": [
+   "1f391163da043cb664558beb686a2b195c067899",
+   "reftest"
+  ],
   "css/css-display/display-contents-shadow-host-whitespace.html": [
    "84b04dba1013af9091f3d943ca106ab655676842",
    "reftest"
@@ -370604,6 +372010,10 @@
    "62d1aca2e5147cb849f8a36d616cf7143e9cf055",
    "support"
   ],
+  "css/css-display/support/red-square.html": [
+   "e4e48ccfdc5356431c5b3bccf8481e207ac02283",
+   "support"
+  ],
   "css/css-display/support/swatch-orange.png": [
    "d3cd498b52bd88ea6c991f050f1ecb1cfdd136bb",
    "support"
@@ -375204,6 +376614,14 @@
    "5cb21495ac523ee796e7b246831fd2d5bdcae798",
    "reftest"
   ],
+  "css/css-fonts/quoted-generic-ignored-ref.html": [
+   "70e2d50cd83f61017f0f22da14065c7afa76e1d1",
+   "support"
+  ],
+  "css/css-fonts/quoted-generic-ignored.html": [
+   "4207ad5cf43e6b6db198fb14b0d00f6c3c2d4e97",
+   "reftest"
+  ],
   "css/css-fonts/support/100x100-lime.png": [
    "1b947700808585e8c224cee096247eb5d30a1ded",
    "support"
@@ -383881,7 +385299,7 @@
    "reftest"
   ],
   "css/css-grid/grid-layout-properties.html": [
-   "fcc2ce3b88d7a7aa45afcba9cdef9fdcd293ba63",
+   "b1b0bd87d494e0045c9a56501011428ac1af3ab8",
    "testharness"
   ],
   "css/css-grid/grid-model/display-grid.html": [
@@ -384232,16 +385650,24 @@
    "ba1f5f60d657ebd2629c94b90c971bb081ea7917",
    "testharness"
   ],
+  "css/css-grid/parsing/grid-auto-flow-computed-expected.txt": [
+   "7610e495527b65df9f0850f53703cc3bdcd306f1",
+   "support"
+  ],
   "css/css-grid/parsing/grid-auto-flow-computed.html": [
-   "7484f62ddb6ea6b878245c3567f62fc908428f8c",
+   "a91593efc1bbc4cc6bb49b161b9b143d04daa3d0",
    "testharness"
   ],
   "css/css-grid/parsing/grid-auto-flow-invalid.html": [
    "a261e8eba11fd295eb33c9288a7e30f589374331",
    "testharness"
   ],
+  "css/css-grid/parsing/grid-auto-flow-valid-expected.txt": [
+   "d2139ff1d2d99747d7bbd0fc6ceb09f9c7c07549",
+   "support"
+  ],
   "css/css-grid/parsing/grid-auto-flow-valid.html": [
-   "4270a3df933f372792139cae7c39344ff69482dc",
+   "7db8b189a28e5bbd06fd11fbb856f0a727269933",
    "testharness"
   ],
   "css/css-grid/parsing/grid-auto-rows-computed.html": [
@@ -385396,22 +386822,58 @@
    "938015937025272c14a52b5839d65784ccb757bc",
    "reftest"
   ],
-  "css/css-lists/counter-reset-increment-display-contents.html": [
-   "a59576b25345032b80580a64d4775969e824f999",
+  "css/css-lists/counter-reset-increment-set-display-contents.html": [
+   "6508df0da150a92e42032c546f2cf4ac6c171859",
    "reftest"
   ],
-  "css/css-lists/counter-reset-increment-display-none.html": [
-   "3b344a751c1da2d3c15feab1cdba078cc3c4590a",
+  "css/css-lists/counter-reset-increment-set-display-none.html": [
+   "510fd8b6482be5a9007c111c6f8478bb659d72b0",
    "reftest"
   ],
   "css/css-lists/counter-reset-inside-display-contents.html": [
    "85c137e675e55a54c4ab3834469ab3d13aa32725",
    "reftest"
   ],
+  "css/css-lists/counter-set-001-ref.html": [
+   "be06ea1dc948b4f4cc9331f494dc90a5787170de",
+   "support"
+  ],
+  "css/css-lists/counter-set-001.html": [
+   "3be4c737c2ba0cc9af542413b7df7d682486efff",
+   "reftest"
+  ],
+  "css/css-lists/counter-set-002-ref.html": [
+   "5ee2e30a9dda7c1ee5f468d6df994e9e8c971355",
+   "support"
+  ],
+  "css/css-lists/counter-set-002.html": [
+   "a4792599826cf13bb40a70c36d850e6593fbce55",
+   "reftest"
+  ],
   "css/css-lists/inheritance.html": [
    "590319d63fd09466f4d5fffe6943b4ff0430fcee",
    "testharness"
   ],
+  "css/css-lists/li-counter-increment-computed-style.html": [
+   "0fae6e3f6036c46b8f658304787da5879913296f",
+   "testharness"
+  ],
+  "css/css-lists/li-list-item-counter-ref.html": [
+   "8340d6d7f65aebaee0cebf0317092050bb33b4e2",
+   "support"
+  ],
+  "css/css-lists/li-list-item-counter.html": [
+   "b9a1196cabce1924b74bbd66d84917f02a4186a9",
+   "reftest"
+  ],
+  "css/css-lists/li-value-counter-reset-001-ref.html": [
+   "9afb1ecfa059dda219c63d6e4d6381ac5c251d4e",
+   "support"
+  ],
+  "css/css-lists/li-value-counter-reset-001.html": [
+   "0e91c3a03d618a9d17194c883f80fd90899d4459",
+   "reftest"
+  ],
   "css/css-lists/li-with-height-001-ref.html": [
    "486009d5604ab7a2cb66df735efff3c11c00b685",
    "support"
@@ -385457,11 +386919,11 @@
    "testharness"
   ],
   "css/css-lists/list-item-definition-ref.html": [
-   "72a4c90f4ada6a889fa71a27aea20146ea07bc9b",
+   "2d49bc4cb972803c45f701667d68d13028c4abc2",
    "support"
   ],
   "css/css-lists/list-item-definition.html": [
-   "edae4b96bd98876170145cf9bc9c834d188b5640",
+   "14e351f9ecd34356087fc5ec7361d8e4d9b542e0",
    "reftest"
   ],
   "css/css-lists/list-marker-with-lineheight-and-overflow-hidden-001-ref.html": [
@@ -387664,6 +389126,38 @@
    "83debd12d20b9f78d5beaf338ae7f068ed6bf693",
    "support"
   ],
+  "css/css-multicol/multicol-span-all-button-001-ref.html": [
+   "d25ecd08c85978ff34c964d2c95f339d7c69b6ae",
+   "support"
+  ],
+  "css/css-multicol/multicol-span-all-button-001.html": [
+   "14833091c8f1bd7804e4ad1a082d3cc0f039d0d9",
+   "reftest"
+  ],
+  "css/css-multicol/multicol-span-all-button-002-ref.html": [
+   "c9ec677335e4969ff10e10d98a43ce680dc5dbce",
+   "support"
+  ],
+  "css/css-multicol/multicol-span-all-button-002.html": [
+   "874cb130dee2ab8ba00e8beb29a4eae07138ddcf",
+   "reftest"
+  ],
+  "css/css-multicol/multicol-span-all-button-003-ref.html": [
+   "337f9c763aadb85c440f9811cab90ac8bccf8ffd",
+   "support"
+  ],
+  "css/css-multicol/multicol-span-all-button-003.html": [
+   "fc15c94a306f406bcf8e232a3021cf568a878a43",
+   "reftest"
+  ],
+  "css/css-multicol/multicol-span-all-children-height-001-ref.html": [
+   "e95210fed257c34d8c265259c7694497c1ff712d",
+   "support"
+  ],
+  "css/css-multicol/multicol-span-all-children-height-001.html": [
+   "55bdef427880b59bfd532eee6fce006d22c1cbb8",
+   "reftest"
+  ],
   "css/css-multicol/multicol-span-all-dynamic-add-001-ref.html": [
    "9f76ea15a0daa7753e76ad9b9a99948988c702d3",
    "support"
@@ -389148,6 +390642,14 @@
    "8f03d3c62fd0cefb11a22b1a4a8d2c06fed97308",
    "support"
   ],
+  "css/css-position/fixed-z-index-blend-ref.html": [
+   "2675401b4092996c2b3c3b80426f2730dc7bbf5f",
+   "support"
+  ],
+  "css/css-position/fixed-z-index-blend.html": [
+   "5558228614060aad3ecfd48f474cdc1a878ea897",
+   "reftest"
+  ],
   "css/css-position/hypothetical-box-scroll-parent-ref.html": [
    "86956adf1def0ce5ac4ef7e198033c46484da7e9",
    "support"
@@ -389336,6 +390838,10 @@
    "e1b469d46c93710c9ee2725be76a28e4f2e5fa61",
    "testharness"
   ],
+  "css/css-position/position-absolute-crash-chrome-006.html": [
+   "94b2469b0e692f00c281d02dfbceb59c0a04d5e4",
+   "testharness"
+  ],
   "css/css-position/position-absolute-dynamic-containing-block.html": [
    "3968f685849663574ca213fcb90dc5fb3eaffaa3",
    "testharness"
@@ -389448,6 +390954,14 @@
    "ba23f0145cf497c4d21b36f387d2017acf45bf34",
    "testharness"
   ],
+  "css/css-position/position-sticky-change-top-ref.html": [
+   "8ccc1548ef6abcd82b04e242a747228e47cffd75",
+   "support"
+  ],
+  "css/css-position/position-sticky-change-top.html": [
+   "054a8a610d968a6743bd3c2634b2f7226bdaec0e",
+   "reftest"
+  ],
   "css/css-position/position-sticky-child-multicolumn-ref.html": [
    "c44f9f43eb51df8a8499a53db3d7c47d76f38829",
    "support"
@@ -390012,6 +391526,30 @@
    "d45c76696eca826456988d7884adcaa52bfad9cd",
    "reftest"
   ],
+  "css/css-pseudo/marker-content-009-ref.html": [
+   "a3db09f078148cdfe8105bc0d12186e15cf33d48",
+   "support"
+  ],
+  "css/css-pseudo/marker-content-009.html": [
+   "b3627cca7554076f85d59869eec7bc80e39b82be",
+   "reftest"
+  ],
+  "css/css-pseudo/marker-content-010-ref.html": [
+   "5bee9bb17943d7efd06a82656bd6881204cbf24a",
+   "support"
+  ],
+  "css/css-pseudo/marker-content-010.html": [
+   "ccd377d523d55a1eac4f0f05ab7d378357488838",
+   "reftest"
+  ],
+  "css/css-pseudo/marker-content-011-ref.html": [
+   "62a64a1e5e16ac7d90ada265317235cfb6dbe64f",
+   "support"
+  ],
+  "css/css-pseudo/marker-content-011.html": [
+   "0cc20b0cdcd242021bc37b9e2d3500ed21c5b35f",
+   "reftest"
+  ],
   "css/css-pseudo/marker-display-dynamic-001.html": [
    "c06da7ca803455559a7a12b915d9083b32106cd1",
    "reftest"
@@ -390592,16 +392130,24 @@
    "df776353a31f1cef3abe9bc9d195da9be5da2510",
    "support"
   ],
+  "css/css-scroll-snap/inheritance-expected.txt": [
+   "8289641f347644b8caef7ced5053cc2a0e659fb1",
+   "support"
+  ],
   "css/css-scroll-snap/inheritance.html": [
-   "b380cb400f2c291832fdfeeab72e9b5561b3c847",
+   "2569cf3d8bfbf46f1d9217642afbf637ff4600ca",
    "testharness"
   ],
   "css/css-scroll-snap/nested-scrollIntoView-snaps.html": [
    "b335de2c7f40dbcf07416c0a1283e20039ebb058",
    "testharness"
   ],
+  "css/css-scroll-snap/overflowing-snap-areas-expected.txt": [
+   "fd979042a2ff91cd9f0befb9e23a1d5564ce3df8",
+   "support"
+  ],
   "css/css-scroll-snap/overflowing-snap-areas.html": [
-   "8f6698d02064a05709c91b63a5905ca0f9dd992f",
+   "ee31847fddd16ec9d4a5b1e799c73461009f9e1a",
    "testharness"
   ],
   "css/css-scroll-snap/parsing/scroll-margin-block-invalid-expected.txt": [
@@ -390688,20 +392234,88 @@
    "72306dc090828a191aab7c93567f2418c1b0b3f2",
    "testharness"
   ],
+  "css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt": [
+   "3c91974ba9b54222c406cc87516b3f7537827187",
+   "support"
+  ],
   "css/css-scroll-snap/parsing/scroll-snap-type-valid.html": [
-   "fde2211f9253467544376643d2e842c61adfe8be",
+   "59a0cb9ab203b5ec44e46286594c7f77700c66f8",
+   "testharness"
+  ],
+  "css/css-scroll-snap/scroll-padding.html": [
+   "0c637ed6db24ad9283c9ac28c7f377e28688674d",
    "testharness"
   ],
   "css/css-scroll-snap/scroll-snap-stop-always.html": [
    "7d2a228688fc2011662b659803cc615dac14f350",
    "testharness"
   ],
+  "css/css-scroll-snap/scroll-snap-type-on-root-element-expected.txt": [
+   "2694ce2a7ba671991d17777d6c5ff7007c129911",
+   "support"
+  ],
+  "css/css-scroll-snap/scroll-snap-type-on-root-element.html": [
+   "c2c413d04bde1a419c346fbc1d47c19825de9365",
+   "testharness"
+  ],
   "css/css-scroll-snap/scroll-snap-type-proximity.html": [
    "cfe990c4fcab85898899039f71fa353484558789",
    "testharness"
   ],
+  "css/css-scroll-snap/scroll-target-001-ref.html": [
+   "28b00184c2ef5f33f6a2e8927233f6f7f42b1973",
+   "support"
+  ],
+  "css/css-scroll-snap/scroll-target-align-001.html": [
+   "eeda674e07c591cb1d17cce1c8f8bb460c45fbdf",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-align-002.html": [
+   "7e82f030e4c3a47e84475ad440a80b907ffbe99f",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-align-003.html": [
+   "1d6fbebbcd7f652746ece943a240ba2540a10710",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-margin-001.html": [
+   "8ddbbcec5f0b7992ba366c5f638b548327eb9fb2",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-margin-002.html": [
+   "a02cf7db17517cb9bcfd56173c4b6f94cb5f1283",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-margin-003.html": [
+   "d0434db515a68bb7b280edaebe8428dd705d4fc3",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-padding-001.html": [
+   "5cd4fddcc53637b6f7e005574398d88c48bed8b1",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-padding-002.html": [
+   "3a0ca3b8519e8dc73ed9a3b19c7af0312c5d69a6",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-padding-003.html": [
+   "1e92e9be72fa17d718a6e121c5e18edf8bbcae3d",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-snap-001.html": [
+   "76d3222a0bf34750c90b236348694580c42ea94e",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-snap-002.html": [
+   "89df44cba28443c015032301df4c0088ed9fe228",
+   "reftest"
+  ],
+  "css/css-scroll-snap/scroll-target-snap-003.html": [
+   "3e90347a4dc9ee07e04350a6436309c673a13569",
+   "reftest"
+  ],
   "css/css-scroll-snap/scrollTo-scrollBy-snaps.html": [
-   "fba38cb703ba2d70a0fb83e69ae816942a1fbea5",
+   "48bfb51c2d9e838d6ed78fbda636b3657607abc0",
    "testharness"
   ],
   "css/css-scroll-snap/snap-at-user-scroll-end-manual.html": [
@@ -390709,15 +392323,43 @@
    "manual"
   ],
   "css/css-scroll-snap/snap-inline-block-expected.txt": [
-   "21a849e3495762a2acf59e2fba1e25142ba345a8",
+   "4819c39d75fa15b3e4cd7e9f2faadbf259d85362",
    "support"
   ],
   "css/css-scroll-snap/snap-inline-block.html": [
-   "9f9da8f648bfc0f873b339639bd18aba1e25b4c3",
+   "377039c3843fcc26f09e32343a09cdc6f7eb6ec6",
    "testharness"
   ],
+  "css/css-scroll-snap/snap-to-transformed-target.html": [
+   "2a4402579cf06ffb2f5611dfd6207fabcb8bdafe",
+   "testharness"
+  ],
+  "css/css-scroll-snap/snap-to-visible-areas-expected.txt": [
+   "029b8eee7c4f3e31ae37474196f9591718e999d6",
+   "support"
+  ],
   "css/css-scroll-snap/snap-to-visible-areas.html": [
-   "822743445263368eb2c26c0004b25fe4b1aeaa5f",
+   "3e822db02e675a3a8799f69f86d2bc93507c7547",
+   "testharness"
+  ],
+  "css/css-scroll-snap/support/scroll-target-align-001-iframe.html": [
+   "20922ea18ea104bd613a27fcce58a1f0e9ba70ad",
+   "support"
+  ],
+  "css/css-scroll-snap/support/scroll-target-margin-001-iframe.html": [
+   "8eb5b9c863853a29eeaefa33caa89ae237278071",
+   "support"
+  ],
+  "css/css-scroll-snap/support/scroll-target-padding-001-iframe.html": [
+   "b9467e4347fe3dd005123f7c76e6cda1596e79d8",
+   "support"
+  ],
+  "css/css-scroll-snap/support/scroll-target-snap-001-iframe.html": [
+   "1a598fa72384b40ee0331c6a3aaeaaa0fac3ae02",
+   "support"
+  ],
+  "css/css-scroll-snap/unreachable-snap-positions.html": [
+   "ca4f6033cece748bb1b4b39c755569174a75ecb5",
    "testharness"
   ],
   "css/css-scrollbars/META.yml": [
@@ -392220,6 +393862,54 @@
    "4ff3f786c6c6ea263c97771635bfb9f3c8076320",
    "testharness"
   ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html": [
+   "160914c3e840a031f861f5701c444b57aed4819b",
+   "support"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-001.html": [
+   "7dcf1102fb9cbf6a9495d6ef11ba8de111c4f12d",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-002.html": [
+   "54470925dd5ab28238e5919a6d5fdc7f5c5fe46a",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html": [
+   "56b71a0ffe475e27d37d6d81de28d4ab12cdfabe",
+   "support"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-003.html": [
+   "8da6b4c853baf2eb5c90b911fad9abce3d394b78",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-004.html": [
+   "b9955af2fcaa1cad54da055c005a47ffe2358395",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html": [
+   "9964f07cfa5834824f5a81b0cf77ee60f92744d5",
+   "support"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-005.html": [
+   "86a2a72f6bfb89b6d77ff0e2339968dac9e436b7",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-006.html": [
+   "ddb89242a93a9dbd7cbc485bcba3d8c7528ac127",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html": [
+   "8b9da1c9bf6e895ab3084bb1748f80968b916ff8",
+   "support"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-007.html": [
+   "150052fa5116c469f4730638cd25a8ac47c6d2c9",
+   "reftest"
+  ],
+  "css/css-sizing/image-min-max-content-intrinsic-size-change-008.html": [
+   "259e2f3fc004ede6ee107b041875f9842a166a08",
+   "reftest"
+  ],
   "css/css-sizing/image-percentage-max-height-in-anonymous-block.html": [
    "5b1713975eb21e96a558933f81412a7bb0007d19",
    "reftest"
@@ -396556,6 +398246,18 @@
    "ea9956362beecb2da890dbef24362a6e9a8be905",
    "reftest"
   ],
+  "css/css-text/line-breaking/line-breaking-015.html": [
+   "aaa1c2ba87b122114ad6b56c40808910d082ae82",
+   "reftest"
+  ],
+  "css/css-text/line-breaking/line-breaking-016.html": [
+   "c600504b4c244d590f896e26fd6e7e6d7a396800",
+   "reftest"
+  ],
+  "css/css-text/line-breaking/line-breaking-017.html": [
+   "36af931b1dc95ecd0d91b5d9637257370e246a72",
+   "reftest"
+  ],
   "css/css-text/line-breaking/line-breaking-atomic-001.html": [
    "03666417ca40e9f6efeb6c2e6be6a78ff0f477fa",
    "reftest"
@@ -396632,6 +398334,18 @@
    "816015adeab54895037530b8e4d410f81082931f",
    "support"
   ],
+  "css/css-text/line-breaking/reference/line-breaking-015-ref.html": [
+   "2837ce0cd7c394737f8e45e7e557fc381dcc0cf3",
+   "support"
+  ],
+  "css/css-text/line-breaking/reference/line-breaking-016-ref.html": [
+   "e4d30e01158294fe784cd29211afb95fa7f8f68c",
+   "support"
+  ],
+  "css/css-text/line-breaking/reference/line-breaking-017-ref.html": [
+   "6f94b129d294bfc2527c5d2aa800fb6ebadb526e",
+   "support"
+  ],
   "css/css-text/line-breaking/reference/line-breaking-atomic-003-ref.html": [
    "93a6d491c2336467ee8dc48ea37c10203ab05863",
    "support"
@@ -396997,7 +398711,7 @@
    "support"
   ],
   "css/css-text/parsing/text-transform-valid.html": [
-   "a40166c37ef69074b00de8662fe250dbd7877693",
+   "fead45c8b8e45da70d4c14d12e4eba38348aed41",
    "testharness"
   ],
   "css/css-text/parsing/white-space-invalid.html": [
@@ -398132,6 +399846,10 @@
    "3d6eb4af8ac5aeb7fd54e1b2e2aec325886ddca0",
    "support"
   ],
+  "css/css-text/text-transform/reference/text-transform-multiple-001-ref.html": [
+   "694ae87877dd7bebde76a1134ed7d1d1947988ca",
+   "support"
+  ],
   "css/css-text/text-transform/reference/text-transform-none-001-ref.xht": [
    "8f822c62df79ac90de8602a6dd8266211c2cece8",
    "support"
@@ -398480,6 +400198,10 @@
    "42deb58b1bb08474f754adf8f8b492d04e9b6613",
    "reftest"
   ],
+  "css/css-text/text-transform/text-transform-multiple-001.html": [
+   "946aa9c93dbf6de0548a35ad5594ee23ac707756",
+   "reftest"
+  ],
   "css/css-text/text-transform/text-transform-none-001.xht": [
    "40d7373e87e85fddfc6b349a13ea66572b27a5cb",
    "reftest"
@@ -405369,11 +407091,11 @@
    "testharness"
   ],
   "css/css-transitions/Document-getAnimations.tentative-expected.txt": [
-   "12d92cd8c159f70102d6143d30e8b5952ae65250",
+   "d859a1c5cc07b7351dd4833027dd05977a2fdc0d",
    "support"
   ],
   "css/css-transitions/Document-getAnimations.tentative.html": [
-   "bffc05f205fbc80ee9d27ee4ca8d3fefe00ffd63",
+   "98b91e04ee9dde4602da0519f4923712cd6a3fac",
    "testharness"
   ],
   "css/css-transitions/Element-getAnimations.tentative-expected.txt": [
@@ -405428,8 +407150,8 @@
    "bcc7991a828ada651764f740d6e2f05f24f8d332",
    "testharness"
   ],
-  "css/css-transitions/detached-container-001.html": [
-   "545324b0bd74d7ca398581666babf3ec04798b88",
+  "css/css-transitions/disconnected-element-001.html": [
+   "b883ce8d18d2bc14264b5c38b43a633840d0a070",
    "testharness"
   ],
   "css/css-transitions/event-dispatch.tentative-expected.txt": [
@@ -405468,10 +407190,6 @@
    "610df6e85d0d74caae7205ee6832b812c766ff1e",
    "testharness"
   ],
-  "css/css-transitions/hidden-container-001.html": [
-   "567ae61e328726cd36a2e0f9f7aef934935ff845",
-   "testharness"
-  ],
   "css/css-transitions/historical.html": [
    "8d0360a8ecf7a37b81acb10917b63abc7c9543cc",
    "testharness"
@@ -405488,6 +407206,18 @@
    "986436950e419a1670c75a45ab5eb39b7db6edca",
    "testharness"
   ],
+  "css/css-transitions/non-rendered-element-001-expected.txt": [
+   "81c73cb9df214ca9f425c70951b2ed561dfb7911",
+   "support"
+  ],
+  "css/css-transitions/non-rendered-element-001.html": [
+   "10419b94677bbfeedf84c5c348d2285338f6ea11",
+   "testharness"
+  ],
+  "css/css-transitions/non-rendered-element-002.html": [
+   "f26a04895781b389d7bad5aee80122b1e1d878a9",
+   "testharness"
+  ],
   "css/css-transitions/parsing/transition-delay-computed.html": [
    "e1aa9894077bf7958f2cfc459520f8999adc0df0",
    "testharness"
@@ -405669,7 +407399,7 @@
    "support"
   ],
   "css/css-transitions/support/helper.js": [
-   "aa3efe8012268115734bd91bff8f82ceb8d26eea",
+   "d5fa61b15eff12f48d0a76df51595b104579f757",
    "support"
   ],
   "css/css-transitions/support/import-green.css": [
@@ -410504,6 +412234,10 @@
    "3994efc003b5a17bc1346aa77719d928a5d3ef79",
    "reftest"
   ],
+  "css/css-values/calc-rgb-percent-001.html": [
+   "1446c28d389a2087c8d61c7894b4a2dd19994c93",
+   "testharness"
+  ],
   "css/css-values/calc-rounding-001.html": [
    "dfd03a695305e0721154bf26f68a5912216d9862",
    "testharness"
@@ -410584,10 +412318,18 @@
    "4eab829697f87606a64d60f360a04639e61ccabb",
    "reftest"
   ],
+  "css/css-values/getComputedStyle-border-radius-001.html": [
+   "6f3ba3ac4776045c94603b647d0a1ba134f5caf6",
+   "testharness"
+  ],
   "css/css-values/getComputedStyle-border-radius-002.html": [
    "8dec53f3f0ef4b3c1844fe019e76b25f5f374e38",
    "testharness"
   ],
+  "css/css-values/getComputedStyle-border-radius-003.html": [
+   "98d320bca287b869a752c97de1a1be0f706642a9",
+   "testharness"
+  ],
   "css/css-values/ic-unit-001.html": [
    "b969278da90130eecf2c73c5accc945dda39d912",
    "reftest"
@@ -417700,6 +419442,10 @@
    "aa91023c1ac456902f34ccf6a4df0fed1e852bf2",
    "reftest"
   ],
+  "css/cssom-view/matchMedia-display-none-iframe.html": [
+   "08fcb3c5386228b167cc76e9cd02a34903c86912",
+   "testharness"
+  ],
   "css/cssom-view/matchMedia.xht": [
    "202a3b738dd0d7c83ed9b4cdff8c7212ae09f61e",
    "testharness"
@@ -417748,6 +419494,10 @@
    "3b062c7548f1485269b4b74570975beab4d0760f",
    "testharness"
   ],
+  "css/cssom-view/resize-event-on-initial-layout.html": [
+   "dc2f04bcced73dffc16d0c439ea029469da2017d",
+   "testharness"
+  ],
   "css/cssom-view/resources/elementsFromPoint.js": [
    "ba986ef3f568d4971eb4e84c4faaeae6e276b975",
    "support"
@@ -418152,6 +419902,54 @@
    "86016ef5a3db6636bf97edc58992f30f909c13a2",
    "testharness"
   ],
+  "css/cssom/HTMLLinkElement-disabled-001.tentative-expected.txt": [
+   "b078ddb22ee2fcb6815eeac6a5146a2ddef104c8",
+   "support"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-001.tentative.html": [
+   "877356f924de995aca09579739c6120af2caab1e",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-002.tentative-expected.txt": [
+   "176385c5078ade77d21160f0987f07c07433b485",
+   "support"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-002.tentative.html": [
+   "9c46f60a6214538168b48cd06b16fda0ce52ec63",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-003.tentative.html": [
+   "fc86e6ba1f052231c4de47cbcece07c85a6f68b9",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-004.tentative.html": [
+   "7e6c34ee40d97319e4b2ac39262bba9935fd7d3b",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-005.tentative.html": [
+   "0233f8c746ed83c1b912df3c0e8ba489d9bd4325",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-006.tentative.html": [
+   "5828e1ce14217384fd9445297ddffbfcfc4e4c7e",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-007.tentative-expected.txt": [
+   "4fac01798a1627557110ff1df67ab2fa0f96b6b6",
+   "support"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-007.tentative.html": [
+   "451fc3d591f2c8e12964282eb1314d4962429923",
+   "testharness"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-alternate-ref.html": [
+   "5d87bfdaf5b0533f2ea7088a870ca45474d065f4",
+   "support"
+  ],
+  "css/cssom/HTMLLinkElement-disabled-alternate.tentative.html": [
+   "5b020a172b175ac21d76052cfd44139d376f6605",
+   "reftest"
+  ],
   "css/cssom/META.yml": [
    "3250801f64b5d6b4d430083bdc06c09aa0844370",
    "support"
@@ -422048,6 +423846,14 @@
    "d46f13413346098dbd65b1e9ceff5fb8368e863e",
    "reftest"
   ],
+  "css/selectors/sharing-in-svg-use-ref.html": [
+   "703cc99bb863b7a1bb79dd6a7a218308892c66ca",
+   "support"
+  ],
+  "css/selectors/sharing-in-svg-use.html": [
+   "08a038ca8b4ccb367220a467053b1155da51f2fb",
+   "reftest"
+  ],
   "css/selectors/user-invalid-expected.txt": [
    "9fac2eedfc9b864285498c698ca7b58c162d77a8",
    "support"
@@ -429549,7 +431355,7 @@
    "support"
   ],
   "editing/data/removeformat.js": [
-   "cfc355d88541152ac53ff1317a6a0f6a7052b6c3",
+   "db5c05508336a3d57f0486390d4eb80b4d25c0fd",
    "support"
   ],
   "editing/data/strikethrough.js": [
@@ -430101,7 +431907,7 @@
    "support"
   ],
   "editing/run/removeformat-expected.txt": [
-   "e078b46f83ebe6e8faf3bb925aa1ad344789da0b",
+   "bd2809ffb843e9065bd6a96dcd1c3c95d3da56c0",
    "support"
   ],
   "editing/run/removeformat.html": [
@@ -430180,6 +431986,10 @@
    "22ff91189b1370b703f89f55d83cde014b6d367d",
    "testharness"
   ],
+  "element-timing/image-not-added.html": [
+   "59a254e9f179b19bdfe878b49f1300fc0bda56d1",
+   "testharness"
+  ],
   "element-timing/image-not-fully-visible.html": [
    "279fa03cc2b42029ed01a68f670829c13b282a5c",
    "testharness"
@@ -434493,7 +436303,7 @@
    "testharness"
   ],
   "fetch/api/request/request-keepalive.html": [
-   "c9e1a6acdd30ad85c8a60ae434b2a71f601e50a2",
+   "602fabc4db347139980d21f955cb20e59826739f",
    "testharness"
   ],
   "fetch/api/request/request-reset-attributes.https-expected.txt": [
@@ -435481,7 +437291,7 @@
    "support"
   ],
   "fetch/stale-while-revalidate/fetch-sw.https.tentative.html": [
-   "2286739ecf27966d1efedad7c4d4031475693988",
+   "f6ece2cfe3e1f8f85b89d9f6402641104f6085d4",
    "testharness"
   ],
   "fetch/stale-while-revalidate/fetch.tentative.html": [
@@ -439676,6 +441486,26 @@
    "7407248ffe9fe3da977275c2192e31e3db9fc8a9",
    "testharness"
   ],
+  "html/cross-origin-opener/new_window_same_site.html": [
+   "b75f7ff7a646addffca73e7fc47539e88293d2ed",
+   "testharness"
+  ],
+  "html/cross-origin-opener/new_window_same_site.html.headers": [
+   "34bd099a302f893f92586241ea38aac812bf28d0",
+   "support"
+  ],
+  "html/cross-origin-opener/resources/postback.sub.html": [
+   "ee08bab4d55ed45523ae862f65a41b29046fba69",
+   "support"
+  ],
+  "html/cross-origin-opener/resources/window.sub.html": [
+   "7c72f87c3ddd8996991a87721076a95a85c272d9",
+   "support"
+  ],
+  "html/cross-origin-opener/resources/window.sub.html.headers": [
+   "34bd099a302f893f92586241ea38aac812bf28d0",
+   "support"
+  ],
   "html/dom/documents/dom-tree-accessors/Document.body.html": [
    "f42125029568476b4076603a1b982a4989b65d35",
    "testharness"
@@ -444852,6 +446682,10 @@
    "2e765ca152327bc0b20db0e3b8e79f5da08b9fa9",
    "testharness"
   ],
+  "html/interaction/focus/focus-file-input.html": [
+   "d3007112ffb9419e7774d869c53e353ebe2cec8f",
+   "testharness"
+  ],
   "html/interaction/focus/focus-management/focus-event-targets-simple.html": [
    "ab7bcfe6d0e636552746def160715bc47e63fb85",
    "testharness"
@@ -448304,6 +450138,10 @@
    "a65ffb58aade9d962dd0986c62d0e7688dc92317",
    "testharness"
   ],
+  "html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html": [
+   "debe014170dbd452ce994a6286ca11ab0e72adb1",
+   "testharness"
+  ],
   "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html": [
    "cdba44b666c66b5a647c5780a2bfaccf7aa76887",
    "testharness"
@@ -449837,7 +451675,7 @@
    "testharness"
   ],
   "html/semantics/forms/constraints/form-validation-validate.html": [
-   "47b41ffeb23afb895f7956103f901ae0beaf1a8f",
+   "e32fd90330cd05d03373a07d1d8b5b2a4081fb66",
    "testharness"
   ],
   "html/semantics/forms/constraints/form-validation-validity-badInput.html": [
@@ -449849,7 +451687,7 @@
    "testharness"
   ],
   "html/semantics/forms/constraints/form-validation-validity-patternMismatch.html": [
-   "5a0012b0eb37d9bc584d53fb0ad18e9f33257860",
+   "d8677898ff135a7db42bc050d2d1dad582477af4",
    "testharness"
   ],
   "html/semantics/forms/constraints/form-validation-validity-rangeOverflow.html": [
@@ -450144,6 +451982,10 @@
    "bdf52a77f873069e2e49972e4ea484555f59975b",
    "testharness"
   ],
+  "html/semantics/forms/textfieldselection/textarea-selection-while-parsing.xhtml": [
+   "57326bb4a80d26ac109db1fbef9015fda1b31b54",
+   "testharness"
+  ],
   "html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html": [
    "66b5e30a04e7734c211ee2df391d44b678e8ecf1",
    "testharness"
@@ -450372,8 +452214,12 @@
    "14717c5e6aa12e582746c917fcfe68d07cf8ace2",
    "testharness"
   ],
+  "html/semantics/forms/the-form-element/form-autocomplete-expected.txt": [
+   "25900f613e24a8146e00cfe68f4fd11d481ca2a9",
+   "support"
+  ],
   "html/semantics/forms/the-form-element/form-autocomplete.html": [
-   "618aa0a6c4793701fb1c16fe5924482c94a99e46",
+   "ec79bac73d1a27f53fc3c79627dae1f7ca9fcf5a",
    "testharness"
   ],
   "html/semantics/forms/the-form-element/form-checkvalidity.html": [
@@ -451008,6 +452854,14 @@
    "3c0a464255d1df735459b261ca284640699aaa0f",
    "reftest"
   ],
+  "html/semantics/grouping-content/the-li-element/grouping-li-reftest-003-ref.html": [
+   "dbe4c05bad65080aae5edbf055bff2b5f4a72bc7",
+   "support"
+  ],
+  "html/semantics/grouping-content/the-li-element/grouping-li-reftest-003.html": [
+   "bad3819604f70183a5ba434260ff6212caa6aa8a",
+   "reftest"
+  ],
   "html/semantics/grouping-content/the-li-element/grouping-li-reftest-display-list-item-ref.html": [
    "fb142f84b8308914946775874d4b8cbaef641a09",
    "support"
@@ -454665,7 +456519,7 @@
    "testharness"
   ],
   "html/syntax/parsing/unclosed-svg-script.html": [
-   "80f662a3f787daa62c2ae0284f95e7d65b78e8f4",
+   "e4048615072a828299f9222f94b9a01dcb2df4e8",
    "testharness"
   ],
   "html/syntax/serializing-html-fragments/OWNERS": [
@@ -457024,6 +458878,14 @@
    "1930fe0ae8fb1aee30e91e691fe6a73ccfc87d0e",
    "reftest"
   ],
+  "infrastructure/reftest/reftest_fuzzy_no_differences.html": [
+   "324873a8ccf70bed77a328a75ae8e2de08d1ba32",
+   "reftest"
+  ],
+  "infrastructure/reftest/reftest_fuzzy_no_differences_1.html": [
+   "6bf85ceebedc63c0cefc7dce044739c46a08f350",
+   "reftest"
+  ],
   "infrastructure/reftest/reftest_match.html": [
    "333cc6c1ecdf2000e4b118565661761b876a7299",
    "reftest"
@@ -457545,7 +459407,7 @@
    "support"
   ],
   "interfaces/mediacapture-streams.idl": [
-   "0feea37802d9facb70978684b4faaf5780dbd0bb",
+   "427aa92dd1f750f305bccb0b9514820f5bc1d29b",
    "support"
   ],
   "interfaces/mediasession.idl": [
@@ -457717,7 +459579,7 @@
    "support"
   ],
   "interfaces/user-timing.idl": [
-   "cd2e1446b89ef6bb2e03caadda707f141476c9b7",
+   "13ad7f8730d3cd269fa231a40ba490780bef476c",
    "support"
   ],
   "interfaces/vibration.idl": [
@@ -458004,6 +459866,10 @@
    "3e53ee5f5814e8ef69d8454011ceafabfe8d1f17",
    "testharness"
   ],
+  "intersection-observer/v2/inline-occlusion.html": [
+   "e4b097e62ae3902cb971dba751d496685c566bf6",
+   "testharness"
+  ],
   "intersection-observer/v2/scaled-target.html": [
    "f48f0792d0fab626101f8a612a8c1108401134c7",
    "testharness"
@@ -458020,6 +459886,10 @@
    "ea1ee31ebe4519f9563987934c1a9db7fac77136",
    "testharness"
   ],
+  "intersection-observer/v2/text-editor-occlusion.html": [
+   "2edb7bbbe65ab2d09ae13b38b98d66a2d790b1ff",
+   "testharness"
+  ],
   "intersection-observer/v2/text-shadow.html": [
    "c6445c514eecaf978e95d75f5d37a1387939c5e2",
    "testharness"
@@ -458197,7 +460067,11 @@
    "support"
   ],
   "lifecycle/child-display-none.tentative.html": [
-   "f76b4e7b608d3e4e97dfac100bee6fa63602e0bb",
+   "d4ca6dab1e068703c1b5e94e22b8cb31f786879f",
+   "testharness"
+  ],
+  "lifecycle/child-out-of-viewport.tentative.html": [
+   "4d8f868bfb55043b4b65a93cd7f8e282dcf12f79",
    "testharness"
   ],
   "lifecycle/freeze.html": [
@@ -458225,7 +460099,7 @@
    "reftest"
   ],
   "lint.whitelist": [
-   "846c75fd698444672fb6ad446a36397cf45caba2",
+   "a7a4600d9cdceb5df65422ca08404d44df7c9989",
    "support"
   ],
   "loading/preloader-css-import-no-quote.tentative.html": [
@@ -458552,6 +460426,14 @@
    "8fbf5ac806e61e400214b2157180e8aac4fd2d31",
    "reftest"
   ],
+  "mathml/presentation-markup/mrow/inferred-mrow-baseline.html": [
+   "0904d9f17ed2ed1e5af5134ea1ccfcb17674581b",
+   "testharness"
+  ],
+  "mathml/presentation-markup/mrow/inferred-mrow-stretchy.html": [
+   "f75726c11d09d488e81041f4da79e30edc752895",
+   "testharness"
+  ],
   "mathml/presentation-markup/operators/mo-axis-height-1.html": [
    "c88484b9d59a7811f6cfde7065de4facbdf1f74a",
    "testharness"
@@ -459996,11 +461878,7 @@
    "76ca435cf588881ba90a73663fd0708fb9e27dd2",
    "testharness"
   ],
-  "mediacapture-streams/MediaDevices-getSupportedConstraints-expected.txt": [
-   "73ce1c5c8385439eb514c9eedce5586d7ad7cdb0",
-   "support"
-  ],
-  "mediacapture-streams/MediaDevices-getSupportedConstraints.html": [
+  "mediacapture-streams/MediaDevices-getSupportedConstraints.https.html": [
    "fff4f349e1ccc01481be36c0ab0ff7c174fea681",
    "testharness"
   ],
@@ -460121,7 +461999,7 @@
    "testharness"
   ],
   "mediacapture-streams/OWNERS": [
-   "bffa2b19b5f16da89733c6453f61c3e7d3c72552",
+   "31acf6290ddaf2e282a7aa6ef5879332d6af00f4",
    "support"
   ],
   "mediacapture-streams/historical.https-expected.txt": [
@@ -460132,10 +462010,6 @@
    "74efc75842113284ad07ef87c54d4001dcbd9b8b",
    "testharness"
   ],
-  "mediacapture-streams/idlharness.https.window-expected.txt": [
-   "2720255440e5406c8144308f6b93c579c39a266b",
-   "support"
-  ],
   "mediacapture-streams/idlharness.https.window.js": [
    "441a64e3a0c84d6b0da5010ecb65e431f2763942",
    "testharness"
@@ -460661,7 +462535,7 @@
    "testharness"
   ],
   "mixed-content/generic/mixed-content-test-case.js": [
-   "221210814c52af5afa3bb65e174d6e527dff31a7",
+   "eb9fc13f7c0fc5af0ade3df58a942fde5ae6d823",
    "support"
   ],
   "mixed-content/generic/sanity-checker.js": [
@@ -470216,6 +472090,10 @@
    "0bb949047359c004359b7f030f6d5d12a6015f9b",
    "support"
   ],
+  "payment-handler/app-change-payment-method.js": [
+   "7a9f7a7fa7538fd234c5930cb96b2e6fdf970a77",
+   "support"
+  ],
   "payment-handler/basic-card.js": [
    "2db5d4b719fac4dbcfa65f4166c16a5b8d253097",
    "support"
@@ -470248,6 +472126,14 @@
    "7c09f5d407e890c0ed02df1217d85f2f36d722bc",
    "testharness"
   ],
+  "payment-handler/change-payment-method.https-expected.txt": [
+   "046d3aeabd1e74af4410653470a2ba1e7728474a",
+   "support"
+  ],
+  "payment-handler/change-payment-method.https.html": [
+   "b85dad642d8490406347bbf39aef83641bfefa5f",
+   "testharness"
+  ],
   "payment-handler/idlharness.https.any.js": [
    "878114ec7ed878d3e754341cbffa138092fee129",
    "testharness"
@@ -470824,26 +472710,10 @@
    "33d6589e275e265180e0571ca3103dbf9aa179b8",
    "testharness"
   ],
-  "performance-timeline/idlharness.any-expected.txt": [
-   "7d03cc1c92e43122223b32d6e059dbbef3ad7df8",
-   "support"
-  ],
   "performance-timeline/idlharness.any.js": [
    "585bda92dced217354f93fb5beebe6d930890c0e",
    "testharness"
   ],
-  "performance-timeline/idlharness.any.serviceworker-expected.txt": [
-   "7d03cc1c92e43122223b32d6e059dbbef3ad7df8",
-   "support"
-  ],
-  "performance-timeline/idlharness.any.sharedworker-expected.txt": [
-   "7d03cc1c92e43122223b32d6e059dbbef3ad7df8",
-   "support"
-  ],
-  "performance-timeline/idlharness.any.worker-expected.txt": [
-   "7d03cc1c92e43122223b32d6e059dbbef3ad7df8",
-   "support"
-  ],
   "performance-timeline/performanceentry-tojson.any.js": [
    "44f0156eec19241970028c28e5897be4d6f1cb81",
    "testharness"
@@ -470881,7 +472751,7 @@
    "testharness"
   ],
   "performance-timeline/po-observe.html": [
-   "6cc3f1ecf56202917bc8b6a340befb6b0a61d949",
+   "a48f0f3764bda4ceb88b2a8be4d65f168362627a",
    "testharness"
   ],
   "performance-timeline/po-resource.html": [
@@ -470981,7 +472851,7 @@
    "support"
   ],
   "picture-in-picture/shadow-dom.html": [
-   "e2335cd5ddc77123340bc5f0767bd686a08dd032",
+   "adcd659762813e05ed1012768f98d8f196b974f4",
    "testharness"
   ],
   "pointerevents/META.yml": [
@@ -471345,7 +473215,7 @@
    "testharness"
   ],
   "pointerevents/pointerlock/pointerevent_coordinates_when_locked.html": [
-   "9dfd5e1764d33dfd1af7ee62af20b1e0424ac64b",
+   "a79327252277d3b27e416e885b27ff6cb0b0bf5d",
    "testharness"
   ],
   "pointerevents/pointerlock/pointerevent_movementxy-manual.html": [
@@ -481352,8 +483222,16 @@
    "a7542f191c10ea7b42110b5fc80e7abf43174bb5",
    "testharness"
   ],
-  "resource-timing/nested-context-navigations.html": [
-   "483cc5b82d5debf942dd0013a340f9d5f550834c",
+  "resource-timing/nested-context-navigations-embed.html": [
+   "bbba46c50edf21f50b49099c779dd5a8792faa0f",
+   "testharness"
+  ],
+  "resource-timing/nested-context-navigations-iframe.html": [
+   "86a83285288a79d014905aa909014f9e7116fa29",
+   "testharness"
+  ],
+  "resource-timing/nested-context-navigations-object.html": [
+   "20cceea38d6ff278b4e4e1f6f8760bbf38721226",
    "testharness"
   ],
   "resource-timing/no-entries-for-cross-origin-css-fetched.sub-expected.txt": [
@@ -481365,7 +483243,7 @@
    "testharness"
   ],
   "resource-timing/redirects.sub.html": [
-   "0e3f405e14b7af9f0b2a4fe5ce916ed1e47534de",
+   "d3d4f75c817dea1f61e27660949ec327d3a7a61a",
    "testharness"
   ],
   "resource-timing/resource-reload-TAO.sub.html": [
@@ -481601,11 +483479,11 @@
    "support"
   ],
   "resource-timing/resources/fake_responses_https.sub.html": [
-   "cf49fb914bebe0c18d8af19a1a1362ae64217eb5",
+   "21f1f02a6747f12becfe14dfcbdff7263b32bacd",
    "support"
   ],
   "resource-timing/resources/fake_responses_https_redirect.sub.html": [
-   "c55e037d1dc15c1247c1a0ad2396c1416b577800",
+   "2ee92b2a5511c0d43359e0db7ee3b64ae5f9115c",
    "support"
   ],
   "resource-timing/resources/green_frame.htm": [
@@ -482077,7 +483955,7 @@
    "support"
   ],
   "screen-capture/OWNERS": [
-   "a1ef42657ad76cac417ccd52d68b9eafda283478",
+   "db41c4e489b574e9032cb1f9921ce92a01785131",
    "support"
   ],
   "screen-capture/feature-policy.https-expected.txt": [
@@ -487797,7 +489675,7 @@
    "support"
   ],
   "streams/resources/test-utils.js": [
-   "871ab49fa81dbf674efcda94de57bba936f4f87b",
+   "5a9e2479faadf6bacfd95849f4eb6b013d45a8af",
    "support"
   ],
   "streams/transform-streams/backpressure.any.js": [
@@ -490081,7 +491959,7 @@
    "support"
   ],
   "tools/ci/ci_wptrunner_infrastructure.sh": [
-   "f3ce3e73ea796479529da554c17f61293d138d3a",
+   "e5b485dbff8040d797af4d9ce6b0681c6b3d9574",
    "support"
   ],
   "tools/ci/commands.json": [
@@ -490185,7 +492063,7 @@
    "support"
   ],
   "tools/manifest/item.py": [
-   "1556bfafdafb47d9a44629b33a3e376e85c4af6c",
+   "f18e5ba6c9de2c82dab3be03f07fb470204785a3",
    "support"
   ],
   "tools/manifest/log.py": [
@@ -490193,7 +492071,7 @@
    "support"
   ],
   "tools/manifest/manifest.py": [
-   "dd2e3627f478bbabdad532185b17cf6769381086",
+   "5dde9374642381c42527289addf8d7687b08a245",
    "support"
   ],
   "tools/manifest/sourcefile.py": [
@@ -490485,7 +492363,7 @@
    "support"
   ],
   "tools/requirements_mypy.txt": [
-   "0654986be4f9ba06b1d8089ab18af5d72afc5370",
+   "8caf51e9a168044b496f8343049567f10cddfcd9",
    "support"
   ],
   "tools/runner/css/bootstrap-theme.min.css": [
@@ -494365,7 +496243,7 @@
    "support"
   ],
   "tools/wpt/browser.py": [
-   "3f578c09481c8e323baf2dc146be922e19c301cd",
+   "66ad8b50e8c00cce6aa49c28ec8dbfa07a2db31e",
    "support"
   ],
   "tools/wpt/commands.json": [
@@ -494393,7 +496271,7 @@
    "support"
   ],
   "tools/wpt/run.py": [
-   "c54d5aaba01c66095760541be766e8e673a02a47",
+   "c0cfa58950edfdf8a814624b5e0a232c995cdd0f",
    "support"
   ],
   "tools/wpt/testfiles.py": [
@@ -494525,7 +496403,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/browsers/fennec.py": [
-   "45c83d9b816cc2b4bca26da896868408de7f273c",
+   "9414ff230d47cf5075b08089c11a395b7eb1f0be",
    "support"
   ],
   "tools/wptrunner/wptrunner/browsers/firefox.py": [
@@ -494573,7 +496451,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/base.py": [
-   "f35c03a30e8f222b3cf33a4bda66e73e33853cdd",
+   "d1c123a3ef39c016fb32475e5255c119f306a828",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorchrome.py": [
@@ -494589,7 +496467,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executormarionette.py": [
-   "0b0068f8c5bc9716e1988bc3cb7ea103459699ac",
+   "8ceb99261e28d7142b16ab736ba453d849065f89",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executoropera.py": [
@@ -495985,11 +497863,11 @@
    "support"
   ],
   "user-timing/clearMarks.html": [
-   "22d67262c3d76698862e46756a793267423cb5b1",
+   "92c60a3bbb856bd05bf13f12bde09dac7eefb6e6",
    "testharness"
   ],
   "user-timing/clearMeasures.html": [
-   "488bece373365ba78246b33bed4e8869370abdbd",
+   "54d41005698305844088b347c11982c626947504",
    "testharness"
   ],
   "user-timing/clear_all_marks.any.js": [
@@ -495997,7 +497875,7 @@
    "testharness"
   ],
   "user-timing/clear_all_measures.any.js": [
-   "5fd2a29a8c08c4f51430c2036ae978bba8cfbda8",
+   "32c993f2827a301feb7bcb69c11317d4020f12f2",
    "testharness"
   ],
   "user-timing/clear_non_existent_mark.any.js": [
@@ -496005,7 +497883,7 @@
    "testharness"
   ],
   "user-timing/clear_non_existent_measure.any.js": [
-   "5e2c7ed1d6411c98b699eb47d6d5f6dcfff978ec",
+   "9de0b5f266d4e2815f28fb29468ea571ba7a1bad",
    "testharness"
   ],
   "user-timing/clear_one_mark.any.js": [
@@ -496013,33 +497891,17 @@
    "testharness"
   ],
   "user-timing/clear_one_measure.any.js": [
-   "a4db264d1887b80f517b75c4e984ab4b2420fb2e",
+   "a5e663772c8bbe9ce9f845ac471fbf10dd5a2867",
    "testharness"
   ],
   "user-timing/entry_type.any.js": [
    "1e37453d09d42ea9c530bc2902cccb8f66fd6efd",
    "testharness"
   ],
-  "user-timing/idlharness.any-expected.txt": [
-   "0990fccc9a59a13150f62c92114c986d9fdcb7c5",
-   "support"
-  ],
   "user-timing/idlharness.any.js": [
    "d1cb9b57a780143296a70c98579e3c816bfaad81",
    "testharness"
   ],
-  "user-timing/idlharness.any.serviceworker-expected.txt": [
-   "0990fccc9a59a13150f62c92114c986d9fdcb7c5",
-   "support"
-  ],
-  "user-timing/idlharness.any.sharedworker-expected.txt": [
-   "0990fccc9a59a13150f62c92114c986d9fdcb7c5",
-   "support"
-  ],
-  "user-timing/idlharness.any.worker-expected.txt": [
-   "0990fccc9a59a13150f62c92114c986d9fdcb7c5",
-   "support"
-  ],
   "user-timing/invoke_with_timing_attributes.html": [
    "6c06f5e9d527b2a0cf3d7d2c02b334a24c9d4f25",
    "testharness"
@@ -496052,12 +497914,16 @@
    "e47a3ba7a981e978cdf015f8fc6bfbae6762dba9",
    "testharness"
   ],
+  "user-timing/mark-entry-constructor.html": [
+   "47c9a644118a5f52dd46fc5dfd1d275ce2e6f52d",
+   "testharness"
+  ],
   "user-timing/mark-errors.html": [
    "c182a39c65e12a4a697e4c42fb2bd7e3aa3c874d",
    "testharness"
   ],
   "user-timing/mark-l3.html": [
-   "429768d5557dbe04d6cddc20f526ab33ae8c9b44",
+   "bb4b22510c760940d4c8886b79401400a3fe8c6d",
    "testharness"
   ],
   "user-timing/mark-measure-feature-detection.html": [
@@ -496073,19 +497939,23 @@
    "testharness"
   ],
   "user-timing/mark.html": [
-   "a7074f1efdb261298bd9260d944e51db02a42e93",
+   "e03e9e6247adabb186783e06a493dcc3a7ecb464",
    "testharness"
   ],
   "user-timing/mark_exceptions.html": [
    "e1f4c4e0f49484cedd8b6025bbe854c0503c94c1",
    "testharness"
   ],
+  "user-timing/measure-exceptions.html": [
+   "0c532e79390e81393fdb71ea5dd59bbed1e65c38",
+   "testharness"
+  ],
   "user-timing/measure-l3.html": [
    "0e8dacfef2bb71897bb5fe6872c783d71f8c36ef",
    "testharness"
   ],
   "user-timing/measure-with-dict.html": [
-   "83990a6c33314e4a7f6b965e21f0eafe2a2d92fb",
+   "47a4f3f520af930e246f8195ee43294e13ebfa36",
    "testharness"
   ],
   "user-timing/measure.html": [
@@ -496093,7 +497963,7 @@
    "testharness"
   ],
   "user-timing/measure_associated_with_navigation_timing.html": [
-   "9fd4664b9e9a5f1e974b469d6e67ff6dc0194bea",
+   "702e3d5f87f39e3b188f0190d7e5f3339f1ac704",
    "testharness"
   ],
   "user-timing/measure_exception.html": [
@@ -496113,7 +497983,7 @@
    "testharness"
   ],
   "user-timing/measures.html": [
-   "d0ab11e39aeff5b51f9294396c037744682b4bf9",
+   "0de68965ddb9c7a53ca5595874bb20a3d7d2ca71",
    "testharness"
   ],
   "user-timing/resources/user-timing-helper.js": [
@@ -496337,7 +498207,7 @@
    "manual"
   ],
   "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html": [
-   "75064767ceebeb3abfad31f9dc9a8a2b91e10e44",
+   "ad7eeb075f44430dbe4f9ed7a55c2ce3f155d0c0",
    "testharness"
   ],
   "wake-lock/wakelock-disabled-by-feature-policy.https.sub.html.headers": [
@@ -496873,7 +498743,7 @@
    "testharness"
   ],
   "web-animations/animation-model/animation-types/property-list.js": [
-   "8d9b296ff74fdd907f94da417bfce1d9021eca48",
+   "3ac142e6278544917bc96073beb9d024f278fe9b",
    "support"
   ],
   "web-animations/animation-model/animation-types/property-types.js": [
@@ -496896,6 +498766,14 @@
    "78f46c9e4684b4d7a7144ca071451069101c8a55",
    "testharness"
   ],
+  "web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands-expected.txt": [
+   "03400ec387856e7c7a2a1d30508bc5e52a08bf20",
+   "support"
+  ],
+  "web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html": [
+   "ff62a23bce00900ddaac1a5249524bc2cc827968",
+   "testharness"
+  ],
   "web-animations/animation-model/keyframe-effects/effect-value-context-filling-expected.txt": [
    "c0b9a11f5fddb67be4329324c72683917757b1d6",
    "support"
@@ -496929,7 +498807,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animatable/animate-expected.txt": [
-   "665e3cb5c286a7a353dea4433aa48414d65e4ebb",
+   "6606b51d9868a1e85458ba8af7f85d6afae7e727",
    "support"
   ],
   "web-animations/interfaces/Animatable/animate-no-browsing-context-expected.txt": [
@@ -496941,7 +498819,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animatable/animate.html": [
-   "b7c590e67a03d6ae81cbfeb1a80db0e0613f710d",
+   "fcf753baef30bbde608d2debfb43b3212b02fa21",
    "testharness"
   ],
   "web-animations/interfaces/Animatable/getAnimations-expected.txt": [
@@ -497173,7 +499051,7 @@
    "support"
   ],
   "web-animations/testcommon.js": [
-   "889cab8bd31e7d356b413fd1e58ea032f00a2fc6",
+   "82b7053232146e3475f1db4c21d9b28e587d2f31",
    "support"
   ],
   "web-animations/timing-model/animation-effects/active-time.html": [
@@ -497261,7 +499139,7 @@
    "support"
   ],
   "web-animations/timing-model/animations/setting-the-current-time-of-an-animation-expected.txt": [
-   "79fae9f7d5df3be7ac054571bd3ad242043dc683",
+   "a5269f2d7764383c6d2059a6438e4bccb5110e7e",
    "support"
   ],
   "web-animations/timing-model/animations/setting-the-current-time-of-an-animation.html": [
@@ -498005,7 +499883,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audionode-interface/audionode-connect-method-chaining.html": [
-   "4163a8439cd08c1f8cdcb587c569653c2618e021",
+   "5703a2a6c7f565f8705a5630d0b9e2b67394985c",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audionode-interface/audionode-connect-order.html": [
@@ -498093,7 +499971,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/event-insertion.html": [
-   "07a54c3bbf68a7af3d651140df5ddcc99ac0f823",
+   "2eef895c8e8750bc25c45ba67c8c67c60e2f17bc",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/k-rate-audioworklet.https.html": [
@@ -498293,7 +500171,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-getFrequencyResponse.html": [
-   "2389b334fb86b71ac38f3c6f60f917175caf8c28",
+   "23222e4df9698d408b886ea108cc4c732a7d61fe",
    "testharness"
   ],
   "webaudio/the-audio-api/the-biquadfilternode-interface/biquad-highpass.html": [
@@ -498424,6 +500302,10 @@
    "935ceeb715edd2ffdeb7979d6824736fa82b6d2f",
    "testharness"
   ],
+  "webaudio/the-audio-api/the-convolvernode-interface/realtime-conv.html": [
+   "c1686da964532db87b51d0cdb79081b14046c5cb",
+   "testharness"
+  ],
   "webaudio/the-audio-api/the-delaynode-interface/ctor-delay.html": [
    "e7ccefc655364d20bb240beacc81a4f7a10806dd",
    "testharness"
@@ -498520,6 +500402,10 @@
    "38324a9f67a67f50f134fb78af43117e2ec9b8c8",
    "testharness"
   ],
+  "webaudio/the-audio-api/the-mediastreamaudiodestinationnode-interface/ctor-mediastreamaudiodestination.html": [
+   "5d3fd0c26f4aa0347e2682b303d9bedbcc2b7600",
+   "testharness"
+  ],
   "webaudio/the-audio-api/the-offlineaudiocontext-interface/ctor-offlineaudiocontext.html": [
    "4b6863103622c5fb248dee3e3eb20d955275d037",
    "testharness"
@@ -499852,6 +501738,10 @@
    "2c79be8a298aa73ae20bb7898d8dd34d0d56b000",
    "testharness"
   ],
+  "webmessaging/message-channels/worker-post-after-close.html": [
+   "a2f6d92e9cc9ca67a4f42384a0a00e1497f98db8",
+   "testharness"
+  ],
   "webmessaging/message-channels/worker.html": [
    "0502021fff138a29b5bd815c589d0f556922db9b",
    "testharness"
@@ -500224,16 +502114,24 @@
    "f3902089fe1c9958c8dd3ee598efb73a5b7ed4c4",
    "support"
   ],
-  "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html": [
-   "2bd860d901ded78c9635da65413ac63e7dbf4460",
+  "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https-expected.txt": [
+   "5ce0b60e996a73ac2ab01f6b761648d3e780648c",
+   "support"
+  ],
+  "webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html": [
+   "901789109f017a74ba11675d13cd33d12e73e2d1",
    "testharness"
   ],
   "webrtc-identity/RTCPeerConnection-peerIdentity-expected.txt": [
    "76951f17b1cb799f48035501a0ae4d57db7a1d61",
    "support"
   ],
-  "webrtc-identity/RTCPeerConnection-peerIdentity.html": [
-   "64ad212a5ba4e0c6bf5589f4cda3a4c7a508cdc2",
+  "webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt": [
+   "36044e3bec02381b5105dfabffe91aabe08d5e1b",
+   "support"
+  ],
+  "webrtc-identity/RTCPeerConnection-peerIdentity.https.html": [
+   "518d57777aa79cd2c74ac1820f3538c4afb2732b",
    "testharness"
   ],
   "webrtc-identity/identity-helper.sub.js": [
@@ -500381,7 +502279,7 @@
    "support"
   ],
   "webrtc/RTCDataChannel-send.html": [
-   "4b8d0c2f2048d68283a55de7b19eb2e95b166fc8",
+   "76d3524d6ebc85306ceffcbe4a59a5e8928fd192",
    "testharness"
   ],
   "webrtc/RTCDataChannelEvent-constructor.html": [
@@ -500572,8 +502470,12 @@
    "c4c6b4fd0410dd45e99d8ae313ede42ae7593e49",
    "testharness"
   ],
+  "webrtc/RTCPeerConnection-removeTrack.https-expected.txt": [
+   "a0ef9ca77b5173d022151c19bd9ac693cc7c144f",
+   "support"
+  ],
   "webrtc/RTCPeerConnection-removeTrack.https.html": [
-   "ffb3fececc48ddff3869ea728b00b94c76380334",
+   "f2add7f0d34bada5c156cafeac399e104b2a414a",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setDescription-transceiver-expected.txt": [
@@ -500585,11 +502487,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setLocalDescription-answer-expected.txt": [
-   "07801b919327be5a277027581a9c07977dcad101",
+   "4b0e913baf98740d42554cf5903454dc76cb8985",
    "support"
   ],
   "webrtc/RTCPeerConnection-setLocalDescription-answer.html": [
-   "e8b3ef5071e480941cc5b4c6f3117ebfa519ac9e",
+   "c97021b0fabb455ecd8575276a355e9b9d79bc9b",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setLocalDescription-offer-expected.txt": [
@@ -500649,11 +502551,11 @@
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt": [
-   "f338dbc85b6f273ef885e4e04db67870e7526051",
+   "a6fe1caff8539b2efc14f61aad51087033c64627",
    "support"
   ],
   "webrtc/RTCPeerConnection-setRemoteDescription-rollback.html": [
-   "f2dbf0b96f3c670a219a2f07a85e77f0d231a5b8",
+   "255419258a35d88ae5970e9ec4edeb70f203da0f",
    "testharness"
   ],
   "webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html": [
@@ -500809,7 +502711,7 @@
    "testharness"
   ],
   "webrtc/RTCRtpTransceiver.https.html": [
-   "b5f3c55ee5810f30ee8439e0b33df84b379d975c",
+   "0b560d2f26e34db31d19ad51a87d3690a61e5947",
    "testharness"
   ],
   "webrtc/RTCSctpTransport-constructor.html": [
@@ -505625,7 +507527,7 @@
    "testharness"
   ],
   "webxr/xrRigidTransform_inverse.https.html": [
-   "da34fec60f00c15fe814e64b918e4a30d9716f70",
+   "706f72102ad3e7e6d9daaf30e6a98c888fbdbcba",
    "testharness"
   ],
   "webxr/xrRigidTransform_matrix.https.html": [
@@ -507920,60 +509822,60 @@
    "88a7d78fc5953bc89b45503f1792f3a1d1dfe789",
    "testharness"
   ],
-  "xhr/event-abort.htm": [
-   "2f80d1b60780a4c274a4ade882555e6e7a1b8845",
+  "xhr/event-abort.any.js": [
+   "9b38ccf9c9e19765111b96df595abf780f6bfeb8",
    "testharness"
   ],
   "xhr/event-error-order.sub.html": [
    "f03707eb98d7f5737c6aec44d0de4c043deb3731",
    "testharness"
   ],
-  "xhr/event-error.sub.html": [
-   "5f275600006360c3d61377507be9ecda3f3ee002",
+  "xhr/event-error.sub.any.js": [
+   "df63dc05bfa41cc4da9679d020b4cbdbb4e906a4",
    "testharness"
   ],
-  "xhr/event-load.htm": [
-   "cdd0c5bb8ad1876a3a96797f5f64a7437eecae5d",
+  "xhr/event-load.any.js": [
+   "72e46a5cea81ec06a981d973c564db4c7d9f3cb7",
    "testharness"
   ],
-  "xhr/event-loadend.htm": [
-   "b17d9b9134ea8669fd440433c0d0d9ffc1a729db",
+  "xhr/event-loadend.any.js": [
+   "7bd1844b378c0f63da44a896e398e8b1edcd9cf5",
    "testharness"
   ],
-  "xhr/event-loadstart-upload.htm": [
-   "275d418a7e090e11e20a60acac31e87978fe64c5",
+  "xhr/event-loadstart-upload.any.js": [
+   "0f41cd1286b74a7c0f0def2fc9b16f4a81dc3c97",
    "testharness"
   ],
-  "xhr/event-loadstart.htm": [
-   "442be938dc7f95760da4e7df345cac1b1d1497b3",
+  "xhr/event-loadstart.any.js": [
+   "4778404a00ef5fa2302d0b93776e1c5039a1a5a1",
    "testharness"
   ],
-  "xhr/event-progress.htm": [
-   "5e9090e3dfc1327405bad25710ce386d95c57637",
+  "xhr/event-progress.any.js": [
+   "0e7c3a42c7df6872d9e23a39f2164a185bf251fc",
    "testharness"
   ],
-  "xhr/event-readystate-sync-open.htm": [
-   "ae9697ea13a94fb230a31b61e11cf76593f7bf61",
+  "xhr/event-readystate-sync-open.any.js": [
+   "321635e7dea40c28d43490c7846ebfdf97993af2",
    "testharness"
   ],
-  "xhr/event-readystatechange-loaded.htm": [
-   "6cbcc22a3308a1d1f7921a47f27cf57722dfabc2",
+  "xhr/event-readystatechange-loaded.any.js": [
+   "1e4467aaebdaf9bf192b16d679ee9f92488dba25",
    "testharness"
   ],
-  "xhr/event-timeout-order.htm": [
-   "d4dc78010a74df528fae081beb270a51b25e94d3",
+  "xhr/event-timeout-order.any.js": [
+   "b35e908a9d8c102aa9019649fad6c591779d60c6",
    "testharness"
   ],
-  "xhr/event-timeout.htm": [
-   "c40213562b57ad56f8bf06a7a89f0453d53a1fd1",
+  "xhr/event-timeout.any.js": [
+   "d114b08b3e124eef560a3fd7bce1247cf43a347e",
    "testharness"
   ],
-  "xhr/event-upload-progress-crossorigin.htm": [
-   "5e558a27b78b1879e0ad3e352037db3434b9fb6a",
+  "xhr/event-upload-progress-crossorigin.any.js": [
+   "1036f2b14f0a39744d5b92ea95c6f2c5bf0c67b7",
    "testharness"
   ],
-  "xhr/event-upload-progress.htm": [
-   "697d4cbd3f61cd223ea7b295306474c77b1de2dd",
+  "xhr/event-upload-progress.any.js": [
+   "5d1546757ba424c6bce0c14412deb81494198e8a",
    "testharness"
   ],
   "xhr/firing-events-http-content-length.html": [
diff --git a/third_party/blink/web_tests/external/wpt/.well-known/idp-proxy/mock-idp.js b/third_party/blink/web_tests/external/wpt/.well-known/idp-proxy/mock-idp.js
index 242b4ef..e73ca22 100644
--- a/third_party/blink/web_tests/external/wpt/.well-known/idp-proxy/mock-idp.js
+++ b/third_party/blink/web_tests/external/wpt/.well-known/idp-proxy/mock-idp.js
@@ -55,9 +55,7 @@
     };
  */
 
-// In RTCIdentityProviderGlobalScope, global is self
-const global = self;
-const query = parseQueryString(global.location);
+const query = parseQueryString(location);
 
 // Generate a naive identity assertion. The result assertion
 // is a JSON string that report the various parameters
@@ -73,8 +71,8 @@
   };
 
   const env = {
-    origin: global.origin,
-    location: global.location
+    origin,
+    location
   };
 
   const assertion = {
@@ -84,11 +82,6 @@
     query
   };
 
-  const idp = {
-    domain: global.location.host,
-    protocol: 'mock-idp.js'
-  };
-
   const assertionStr = JSON.stringify(assertion);
 
   const { generatorAction } = query;
@@ -100,7 +93,7 @@
 
   } else if(generatorAction === 'require-login') {
     const err = new RTCError('idp-need-login');
-    err.idpLoginUrl = `${self.origin}/login`;
+    err.idpLoginUrl = `${origin}/login`;
     err.idpErrorInfo = 'login required';
     throw err;
 
@@ -120,7 +113,10 @@
 
   } else {
     return {
-      idp,
+      idp: {
+        domain: location.host,
+        protocol: 'mock-idp.js'
+      },
       assertion: assertionStr
     };
   }
@@ -141,8 +137,8 @@
 function validateAssertion(assertionStr, origin) {
   const assertion = JSON.parse(assertionStr);
 
-  const { param, query } = assertion;
-  const { contents, options } = param;
+  const { args, query } = assertion;
+  const { contents, options } = args;
 
   const identity = options.usernameHint;
 
@@ -188,10 +184,10 @@
     };
  */
 
-// if global.rtcIdentityProvider is defined, and the caller do not ask
+// if rtcIdentityProvider is defined, and the caller do not ask
 // to not register through query string, register our assertion callbacks.
-if(global.rtcIdentityProvider && query.action !== 'do-not-register') {
-  global.rtcIdentityProvider.register({
+if(rtcIdentityProvider && query.action !== 'do-not-register') {
+  rtcIdentityProvider.register({
     generateAssertion,
     validateAssertion
   });
diff --git a/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-origin.sub.html b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-origin.sub.html
index ae8c70f9..9f19f6a 100644
--- a/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-origin.sub.html
+++ b/third_party/blink/web_tests/external/wpt/2dcontext/imagebitmap/createImageBitmap-origin.sub.html
@@ -5,9 +5,9 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="/common/media.js"></script>
 <script src="/common/namespaces.js"></script>
+<script src="/common/canvas-tests.js"></script>
 <div id=log></div>
 <script>
-const crossOriginImageUrl = "http://{{domains[www1]}}:{{ports[http][0]}}/images/red.png";
 
 function assert_origin_unclean_getImageData(bitmap) {
   const context = document.createElement("canvas").getContext("2d");
@@ -31,92 +31,9 @@
   assert_throws('SecurityError', () => canvas.toDataURL());
 }
 
-function makeImage() {
-  return new Promise((resolve, reject) => {
-    const image = new Image();
-    image.onload = () => resolve(image);
-    image.onerror = reject;
-    image.src = crossOriginImageUrl;
-  });
-}
-
-const arguments = [
-  {
-    name: "cross-origin HTMLImageElement",
-    factory: makeImage,
-  },
-
-  {
-    name: "cross-origin SVGImageElement",
-    factory: () => {
-      return new Promise((resolve, reject) => {
-        const image = document.createElementNS(NAMESPACES.svg, "image");
-        image.onload = () => resolve(image);
-        image.onerror = reject;
-        image.setAttribute("externalResourcesRequired", "true");
-        image.setAttributeNS(NAMESPACES.xlink, 'xlink:href', crossOriginImageUrl);
-        document.body.appendChild(image);
-      });
-    },
-  },
-
-  {
-    name: "cross-origin HTMLVideoElement",
-    factory: () => {
-      return new Promise((resolve, reject) => {
-        const video = document.createElement("video");
-        video.oncanplaythrough = () => resolve(video);
-        video.onerror = reject;
-        video.src = getVideoURI("http://{{domains[www1]}}:{{ports[http][0]}}/media/movie_300");
-      });
-    },
-  },
-
-  {
-    name: "redirected to cross-origin HTMLVideoElement",
-    factory: () => {
-      return new Promise((resolve, reject) => {
-        const video = document.createElement("video");
-        video.oncanplaythrough = () => resolve(video);
-        video.onerror = reject;
-        video.src = "/common/redirect.py?location=" + getVideoURI("http://{{domains[www1]}}:{{ports[http][0]}}/media/movie_300");
-      });
-    },
-  },
-
-  {
-    name: "redirected to same-origin HTMLVideoElement",
-    factory: () => {
-      return new Promise((resolve, reject) => {
-        const video = document.createElement("video");
-        video.oncanplaythrough = () => resolve(video);
-        video.onerror = reject;
-        video.src = "http://{{domains[www1]}}:{{ports[http][0]}}/common/redirect.py?location=" + getVideoURI("http://{{domains[]}}:{{ports[http][0]}}/media/movie_300");
-      });
-    },
-  },
-
-  {
-    name: "unclean HTMLCanvasElement",
-    factory: () => {
-      return makeImage().then(image => {
-        const canvas = document.createElement("canvas");
-        const context = canvas.getContext("2d");
-        context.drawImage(image, 0, 0);
-        return canvas;
-      });
-    },
-  },
-
-  {
-    name: "unclean ImageBitmap",
-    factory: () => {
-      return makeImage().then(createImageBitmap);
-    },
-  },
-];
-
-for (let { name, factory } of arguments) {
+forEachCanvasSource("http://{{domains[www1]}}:{{ports[http][0]}}",
+                    "http://{{domains[]}}:{{ports[http][0]}}",
+                    (name, factory) => {
   promise_test(function() {
     return factory().then(createImageBitmap).then(assert_origin_unclean_getImageData);
   }, `${name}: origin unclear getImageData`);
@@ -126,5 +43,5 @@
   promise_test(function() {
     return factory().then(createImageBitmap).then(assert_origin_unclean_transferFromImageBitmap);
   }, `${name}: origin unclear bitmaprenderer.transferFromImageBitmap`);
-}
+});
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any-expected.txt b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any-expected.txt
new file mode 100644
index 0000000..11edeb4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL events are dispatched in the correct order for an empty blob assert_equals: Expected load event, but got progress event instead expected "load" but got "progress"
+PASS events are dispatched in the correct order for a non-empty blob
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any.js b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any.js
new file mode 100644
index 0000000..ac692907
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any.js
@@ -0,0 +1,19 @@
+promise_test(async t => {
+  var reader = new FileReader();
+  var eventWatcher = new EventWatcher(t, reader, ['loadstart', 'progress', 'abort', 'error', 'load', 'loadend']);
+  reader.readAsText(new Blob([]));
+  await eventWatcher.wait_for('loadstart');
+  // No progress event for an empty blob, as no data is loaded.
+  await eventWatcher.wait_for('load');
+  await eventWatcher.wait_for('loadend');
+}, 'events are dispatched in the correct order for an empty blob');
+
+promise_test(async t => {
+  var reader = new FileReader();
+  var eventWatcher = new EventWatcher(t, reader, ['loadstart', 'progress', 'abort', 'error', 'load', 'loadend']);
+  reader.readAsText(new Blob(['a']));
+  await eventWatcher.wait_for('loadstart');
+  await eventWatcher.wait_for('progress');
+  await eventWatcher.wait_for('load');
+  await eventWatcher.wait_for('loadend');
+}, 'events are dispatched in the correct order for a non-empty blob');
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any.worker-expected.txt b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any.worker-expected.txt
new file mode 100644
index 0000000..11edeb4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_events.any.worker-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL events are dispatched in the correct order for an empty blob assert_equals: Expected load event, but got progress event instead expected "load" but got "progress"
+PASS events are dispatched in the correct order for a non-empty blob
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result-expected.txt b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result-expected.txt
new file mode 100644
index 0000000..844743c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+PASS readAsText
+PASS readAsDataURL
+PASS readAsArrayBuffer
+PASS readAsBinaryString
+FAIL result is null during "loadstart" event for readAsText assert_equals: result is null after first read call expected (object) null but got (string) ""
+FAIL result is null during "loadstart" event for readAsDataURL assert_equals: result is null after first read call expected (object) null but got (string) ""
+FAIL result is null during "loadstart" event for readAsArrayBuffer assert_equals: result is null during event expected null but got object "[object ArrayBuffer]"
+FAIL result is null during "loadstart" event for readAsBinaryString assert_equals: result is null after first read call expected (object) null but got (string) ""
+FAIL result is null during "progress" event for readAsText assert_equals: result is null after first read call expected (object) null but got (string) ""
+FAIL result is null during "progress" event for readAsDataURL assert_equals: result is null after first read call expected (object) null but got (string) ""
+FAIL result is null during "progress" event for readAsArrayBuffer assert_equals: result is null during event expected null but got object "[object ArrayBuffer]"
+FAIL result is null during "progress" event for readAsBinaryString assert_equals: result is null after first read call expected (object) null but got (string) ""
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result.html b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result.html
index 957d033..b80322e 100644
--- a/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result.html
+++ b/third_party/blink/web_tests/external/wpt/FileAPI/reading-data-section/filereader_result.html
@@ -12,9 +12,10 @@
     <div id="log"></div>
 
     <script>
-    var blob;
+    var blob, blob2;
     setup(function() {
       blob = new Blob(["This test the result attribute"]);
+      blob2 = new Blob(["This is a second blob"]);
     });
 
     async_test(function() {
@@ -54,6 +55,43 @@
 
       readArrayBuffer.readAsArrayBuffer(blob);
     }, "readAsArrayBuffer");
+
+    async_test(function() {
+      var readBinaryString = new FileReader();
+      assert_equals(readBinaryString.result, null);
+
+      readBinaryString.onloadend = this.step_func(function(evt) {
+        assert_equals(typeof readBinaryString.result, "string", "The result type is string");
+        assert_equals(readBinaryString.result, "This test the result attribute", "The result is correct");
+        this.done();
+      });
+
+      readBinaryString.readAsBinaryString(blob);
+    }, "readAsBinaryString");
+
+
+    for (let event of ['loadstart', 'progress']) {
+      for (let method of ['readAsText', 'readAsDataURL', 'readAsArrayBuffer', 'readAsBinaryString']) {
+        promise_test(async function(t) {
+          var reader = new FileReader();
+          assert_equals(reader.result, null, 'result is null before read');
+
+          var eventWatcher = new EventWatcher(t, reader,
+              [event, 'loadend']);
+
+          reader[method](blob);
+          assert_equals(reader.result, null, 'result is null after first read call');
+          await eventWatcher.wait_for(event);
+          assert_equals(reader.result, null, 'result is null during event');
+          await eventWatcher.wait_for('loadend');
+          assert_not_equals(reader.result, null);
+          reader[method](blob);
+          assert_equals(reader.result, null, 'result is null after second read call');
+          await eventWatcher.wait_for(event);
+          assert_equals(reader.result, null, 'result is null during second read event');
+        }, 'result is null during "' + event + '" event for ' + method);
+      }
+    }
     </script>
   </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/common/canvas-tests.js b/third_party/blink/web_tests/external/wpt/common/canvas-tests.js
index 732f2a43..2d0397b4 100644
--- a/third_party/blink/web_tests/external/wpt/common/canvas-tests.js
+++ b/third_party/blink/web_tests/external/wpt/common/canvas-tests.js
@@ -107,3 +107,94 @@
         get_host_info().HTTP_REMOTE_ORIGIN + "/images/yellow.png";
     document.body.appendChild(img);
 }
+
+function forEachCanvasSource(crossOriginUrl, sameOriginUrl, callback) {
+  function makeImage() {
+    return new Promise((resolve, reject) => {
+      const image = new Image();
+      image.onload = () => resolve(image);
+      image.onerror = reject;
+      image.src = crossOriginUrl + "/images/red.png";
+    });
+  }
+
+  const arguments = [
+    {
+      name: "cross-origin HTMLImageElement",
+      factory: makeImage,
+    },
+
+    {
+      name: "cross-origin SVGImageElement",
+      factory: () => {
+        return new Promise((resolve, reject) => {
+          const image = document.createElementNS(NAMESPACES.svg, "image");
+          image.onload = () => resolve(image);
+          image.onerror = reject;
+          image.setAttribute("externalResourcesRequired", "true");
+          image.setAttributeNS(NAMESPACES.xlink, 'xlink:href', crossOriginUrl + "/images/red.png");
+          document.body.appendChild(image);
+        });
+      },
+    },
+
+    {
+      name: "cross-origin HTMLVideoElement",
+      factory: () => {
+        return new Promise((resolve, reject) => {
+          const video = document.createElement("video");
+          video.oncanplaythrough = () => resolve(video);
+          video.onerror = reject;
+          video.src = getVideoURI(crossOriginUrl + "/media/movie_300");
+        });
+      },
+    },
+
+    {
+      name: "redirected to cross-origin HTMLVideoElement",
+      factory: () => {
+        return new Promise((resolve, reject) => {
+          const video = document.createElement("video");
+          video.oncanplaythrough = () => resolve(video);
+          video.onerror = reject;
+          video.src = "/common/redirect.py?location=" + getVideoURI(crossOriginUrl + "/media/movie_300");
+        });
+      },
+    },
+
+    {
+      name: "redirected to same-origin HTMLVideoElement",
+      factory: () => {
+        return new Promise((resolve, reject) => {
+          const video = document.createElement("video");
+          video.oncanplaythrough = () => resolve(video);
+          video.onerror = reject;
+          video.src = crossOriginUrl + "/common/redirect.py?location=" + getVideoURI(sameOriginUrl + "/media/movie_300");
+        });
+      },
+    },
+
+    {
+      name: "unclean HTMLCanvasElement",
+      factory: () => {
+        return makeImage().then(image => {
+          const canvas = document.createElement("canvas");
+          const context = canvas.getContext("2d");
+          context.drawImage(image, 0, 0);
+          return canvas;
+        });
+      },
+    },
+
+    {
+      name: "unclean ImageBitmap",
+      factory: () => {
+        return makeImage().then(createImageBitmap);
+      },
+    },
+  ];
+
+  for (let { name, factory } of arguments) {
+    callback(name, factory);
+  }
+}
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/fetch.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/fetch.html
index 734462a3..3a2d5bf 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/fetch.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/fetch.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8"/>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/form-get-blank.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/form-get-blank.html
index a86f34b..b7351702 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/form-get-blank.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/form-get-blank.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8"/>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/form-post-blank.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/form-post-blank.html
index 115c6a1..f2bb0cac 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/form-post-blank.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/form-post-blank.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8"/>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe-reload.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe-reload.html
index 759fc7b0..c4c3598 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe-reload.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe-reload.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8"/>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe.html
index 38a7701..e511128f 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/iframe.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8"/>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/cookies/samesite/img.html b/third_party/blink/web_tests/external/wpt/cookies/samesite/img.html
index b1b04340..bca84cb 100644
--- a/third_party/blink/web_tests/external/wpt/cookies/samesite/img.html
+++ b/third_party/blink/web_tests/external/wpt/cookies/samesite/img.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8"/>
+<meta name="timeout" content="long">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt
index b3260fa..70dfff0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative-expected.txt
@@ -12,6 +12,6 @@
 PASS Yet-to-start CSS Animations are returned
 PASS CSS Animations canceled via the API are not returned
 PASS CSS Animations canceled and restarted via the API are returned
-FAIL CSS Animations targetting (pseudo-)elements should have correct order after sorting assert_equals: The animation targeting the ::before element comes second expected (string) "::before" but got (undefined) undefined
+FAIL CSS Animations targetting (pseudo-)elements should have correct order after sorting assert_equals: Animation #2 has expected target expected (object) Element node <div id="parent" style="animation: animBottom 100s"><div ... but got (undefined) undefined
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative.html
index c11b0a9..175acf84 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/Document-getAnimations.tentative.html
@@ -18,12 +18,6 @@
 @keyframes animRight {
   to { right: 100px }
 }
-::before {
-  content: ''
-}
-::after {
-  content: ''
-}
 </style>
 <div id="log"></div>
 <script>
@@ -251,34 +245,77 @@
 }, 'CSS Animations canceled and restarted via the API are returned');
 
 test(t => {
-  addStyle(t, { '#parent::after': 'animation: animLeft 10s;',
-                '#parent::before': 'animation: animRight 10s;' });
-  // create two divs with these arrangement:
+  // Create two divs with the following arrangement:
+  //
   //       parent
+  //    (::marker,)
   //     ::before,
   //     ::after
   //        |
   //       child
-  const parent = addDiv(t, { 'id': 'parent' });
+
+  addStyle(t, {
+    '#parent::after': "content: ''; animation: animLeft 100s;",
+    '#parent::before': "content: ''; animation: animRight 100s;",
+  });
+
+  const supportsMarkerPseudos = CSS.supports('selector(::marker)');
+  if (supportsMarkerPseudos) {
+    addStyle(t, {
+      '#parent': 'display: list-item;',
+      '#parent::marker': "content: ''; animation: animLeft 100s;",
+    });
+  }
+
+  const parent = addDiv(t, { id: 'parent' });
   const child = addDiv(t);
   parent.appendChild(child);
   for (const div of [parent, child]) {
-    div.setAttribute('style', 'animation: animBottom 10s');
+    div.setAttribute('style', 'animation: animBottom 100s');
   }
 
-  const anims = document.getAnimations();
-  assert_equals(anims.length, 4,
-                'CSS animations on both pseudo-elements and elements ' +
-                'are returned');
-  assert_equals(anims[0].effect.target, parent,
-                'The animation targeting the parent element comes first');
-  assert_equals(anims[1].effect.target.type, '::before',
-                'The animation targeting the ::before element comes second');
-  assert_equals(anims[2].effect.target.type, '::after',
-                'The animation targeting the ::after element comes third');
-  assert_equals(anims[3].effect.target, child,
-                'The animation targeting the child element comes last');
-}, 'CSS Animations targetting (pseudo-)elements should have correct order ' +
-   'after sorting');
+  const expectedAnimations = [
+    [parent, undefined],
+    [parent, '::marker'],
+    [parent, '::before'],
+    [parent, '::after'],
+    [child, undefined],
+  ];
+  if (!supportsMarkerPseudos) {
+    expectedAnimations.splice(1, 1);
+  }
+
+  const animations = document.getAnimations();
+  assert_equals(
+    animations.length,
+    expectedAnimations.length,
+    'CSS animations on both pseudo-elements and elements are returned'
+  );
+
+  for (const [index, expected] of expectedAnimations.entries()) {
+    const [element, pseudo] = expected;
+    const actual = animations[index];
+
+    if (pseudo) {
+      assert_equals(
+        actual.effect.target.element,
+        element,
+        `Animation #${index + 1} has expected target`
+      );
+      assert_equals(
+        actual.effect.target.type,
+        pseudo,
+        `Animation #${index + 1} has expected pseudo type`
+      );
+    } else {
+      assert_equals(
+        actual.effect.target,
+        element,
+        `Animation #${index + 1} has expected target`
+      );
+    }
+  }
+}, 'CSS Animations targetting (pseudo-)elements should have correct order '
+   + 'after sorting');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/animationevent-marker-pseudoelement.html b/third_party/blink/web_tests/external/wpt/css/css-animations/animationevent-marker-pseudoelement.html
new file mode 100644
index 0000000..90c7b86
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/animationevent-marker-pseudoelement.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Animations Test: AnimationEvent pseudoElement</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="help" href="https://drafts.csswg.org/css-animations/#interface-animationevent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  #target::marker {
+    content: "";
+    animation: move 1s;
+  }
+
+  @keyframes move {
+    to { transform: translate(100px); }
+  }
+
+  #target {
+    display: list-item;
+    list-style-position: inside;
+  }
+</style>
+<div id='target'></div>
+<script>
+  async_test(function(t) {
+    var target = document.getElementById('target');
+    target.addEventListener("animationstart", t.step_func(function(evt) {
+      assert_true(evt instanceof window.AnimationEvent);
+      assert_equals(evt.pseudoElement, "::marker");
+
+      t.done();
+    }), true);
+  }, "AnimationEvent should have the correct pseudoElement memeber");
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt
index 8db8179..8aee80ee 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative-expected.txt
@@ -1,7 +1,8 @@
 This is a testharness.js-based test.
-FAIL Test same events are ordered by elements. assert_equals: Number of actual events (0: ) should match expected events (, ) expected 2 but got 0
-FAIL Test start and iteration events are ordered by time. assert_equals: Number of actual events (0: ) should match expected events (, ) expected 2 but got 0
-FAIL Test iteration and end events are ordered by time. assert_equals: Number of actual events (0: ) should match expected events (, ) expected 2 but got 0
-FAIL Test start and end events are sorted correctly when fired simultaneously assert_equals: Number of actual events (0: ) should match expected events (, , , ) expected 4 but got 0
+FAIL Same events are ordered by elements assert_equals: Number of events received (0) should match expected number (2) (expected: animationstart, animationstart, actual: ) expected 2 but got 0
+FAIL Same events on pseudo-elements follow the prescribed order assert_equals: Number of events received (0) should match expected number (4) (expected: animationstart, animationstart, animationstart, animationstart, actual: ) expected 4 but got 0
+FAIL Start and iteration events are ordered by time assert_equals: Number of events received (0) should match expected number (2) (expected: animationiteration, animationstart, actual: ) expected 2 but got 0
+FAIL Iteration and end events are ordered by time assert_equals: Number of events received (0) should match expected number (2) (expected: animationiteration, animationend, actual: ) expected 2 but got 0
+FAIL Start and end events are sorted correctly when fired simultaneously assert_equals: Number of events received (0) should match expected number (4) (expected: animationstart, animationstart, animationend, animationend, actual: ) expected 4 but got 0
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative.html
index 93d452a..f4f9e29a 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/event-order.tentative.html
@@ -6,10 +6,14 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="support/testcommon.js"></script>
 <style>
-  @keyframes anim {
-    from { margin-left: 0px; }
-    to { margin-left: 100px; }
-  }
+@keyframes anim {
+  from { margin-left: 0px; }
+  to { margin-left: 100px; }
+}
+@keyframes color-anim {
+  from { color: red; }
+  to { color: green; }
+}
 </style>
 <div id="log"></div>
 <script type='text/javascript'>
@@ -20,38 +24,69 @@
  * @param actualEvents   An array of the received AnimationEvent objects.
  * @param expectedEvents A series of array objects representing the expected
  *        events, each having the form:
- *          [ event type, target element, elapsed time ]
+ *          [ event type, target element, [pseudo type], elapsed time ]
  */
 const checkEvents = (actualEvents, ...expectedEvents) => {
-  assert_equals(actualEvents.length, expectedEvents.length,
-                `Number of actual events (${actualEvents.length}: \
-${actualEvents.map(event => event.type).join(', ')}) should match expected \
-events (${expectedEvents.map(event => event.type).join(', ')})`);
+  const actualTypeSummary = actualEvents.map(event => event.type).join(', ');
+  const expectedTypeSummary = expectedEvents.map(event => event[0]).join(', ');
 
-  actualEvents.forEach((actualEvent, i) => {
-    assert_equals(expectedEvents[i][0], actualEvent.type,
-                  'Event type should match');
-    assert_equals(expectedEvents[i][1], actualEvent.target,
-                  'Event target should match');
-    assert_equals(expectedEvents[i][2], actualEvent.elapsedTime,
-                  'Event\'s elapsed time should match');
-  });
+  assert_equals(
+    actualEvents.length,
+    expectedEvents.length,
+    `Number of events received (${actualEvents.length}) \
+should match expected number (${expectedEvents.length}) \
+(expected: ${expectedTypeSummary}, actual: ${actualTypeSummary})`
+  );
+
+  for (const [index, actualEvent] of actualEvents.entries()) {
+    const expectedEvent = expectedEvents[index];
+    const [type, target] = expectedEvent;
+    const pseudoElement = expectedEvent.length === 4 ? expectedEvent[2] : '';
+    const elapsedTime = expectedEvent[expectedEvent.length - 1];
+
+    assert_equals(
+      actualEvent.type,
+      type,
+      `Event #${index + 1} types should match \
+(expected: ${expectedTypeSummary}, actual: ${actualTypeSummary})`
+    );
+    assert_equals(
+      actualEvent.target,
+      target,
+      `Event #${index + 1} targets should match`
+    );
+    assert_equals(
+      actualEvent.pseudoElement,
+      pseudoElement,
+      `Event #${index + 1} pseudoElements should match`
+    );
+    assert_equals(
+      actualEvent.elapsedTime,
+      elapsedTime,
+      `Event #${index + 1} elapsedTimes should match`
+    );
+  }
 };
 
 const setupAnimation = (t, animationStyle, receiveEvents) => {
-  const div = addDiv(t, { style: "animation: " + animationStyle });
+  const div = addDiv(t, { style: 'animation: ' + animationStyle });
 
   for (const name of ['start', 'iteration', 'end']) {
     div['onanimation' + name] = evt => {
-    receiveEvents.push({ type:        evt.type,
-                         target:      evt.target,
-                         elapsedTime: evt.elapsedTime });
+      receiveEvents.push({
+        type: evt.type,
+        target: evt.target,
+        pseudoElement: evt.pseudoElement,
+        elapsedTime: evt.elapsedTime,
+      });
     };
   }
 
-  const watcher = new EventWatcher(t, div, [ 'animationstart',
-                                             'animationiteration',
-                                             'animationend' ]);
+  const watcher = new EventWatcher(t, div, [
+    'animationstart',
+    'animationiteration',
+    'animationend',
+  ]);
 
   const animation = div.getAnimations()[0];
 
@@ -92,7 +127,64 @@
 
   checkEvents(events, ['animationend', div1, 200],
                       ['animationend', div2, 200]);
-}, 'Test same events are ordered by elements.');
+}, 'Same events are ordered by elements');
+
+promise_test(async t => {
+  // Setup a hierarchy as follows:
+  //
+  //              parent
+  //                |
+  //  (::marker, ::before, ::after)
+  //                |
+  //              child
+  const parentDiv = addDiv(t, { style: 'animation: anim 100s' });
+
+  parentDiv.id = 'parent-div';
+  addStyle(t, {
+    '#parent-div::after': "content: ''; animation: anim 100s",
+    '#parent-div::before': "content: ''; animation: anim 100s",
+  });
+
+  if (CSS.supports('selector(::marker)')) {
+    parentDiv.style.display = 'list-item';
+    addStyle(t, {
+      '#parent-div::marker': "content: ''; animation: color-anim 100s",
+    });
+  }
+
+  const childDiv = addDiv(t, { style: 'animation: anim 100s' });
+  parentDiv.append(childDiv);
+
+  // Setup event handlers
+  let events = [];
+  for (const name of ['start', 'iteration', 'end', 'cancel']) {
+    parentDiv['onanimation' + name] = evt => {
+      events.push({
+        type: evt.type,
+        target: evt.target,
+        pseudoElement: evt.pseudoElement,
+        elapsedTime: evt.elapsedTime,
+      });
+    };
+  }
+
+  // Wait a couple of frames for the events to be dispatched
+  await waitForFrame();
+  await waitForFrame();
+
+  const expectedEvents = [
+    ['animationstart', parentDiv, 0],
+    ['animationstart', parentDiv, '::marker', 0],
+    ['animationstart', parentDiv, '::before', 0],
+    ['animationstart', parentDiv, '::after', 0],
+    ['animationstart', childDiv, 0],
+  ];
+  if (!CSS.supports('selector(::marker)')) {
+    expectedEvents.splice(1, 1);
+  }
+
+  checkEvents(events, ...expectedEvents);
+}, 'Same events on pseudo-elements follow the prescribed order');
 
 promise_test(async t => {
   let events = [];
@@ -113,7 +205,7 @@
 
   checkEvents(events, ['animationiteration', div2, 300],
                       ['animationstart',     div1, 0]);
-}, 'Test start and iteration events are ordered by time.');
+}, 'Start and iteration events are ordered by time');
 
 promise_test(async t => {
   let events = [];
@@ -135,7 +227,7 @@
 
   checkEvents(events, ['animationiteration', div2, 100],
                       ['animationend',       div1, 150]);
-}, 'Test iteration and end events are ordered by time.');
+}, 'Iteration and end events are ordered by time');
 
 promise_test(async t => {
   let events = [];
@@ -156,6 +248,6 @@
                       ['animationstart', div1, 0],
                       ['animationend',   div1, 100],
                       ['animationend',   div2, 200]);
-}, 'Test start and end events are sorted correctly when fired simultaneously');
+}, 'Start and end events are sorted correctly when fired simultaneously');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-grid-002.html b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-grid-002.html
index 1e7771e7..43361c29 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-grid-002.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-contain/contain-size-grid-002.html
@@ -7,6 +7,9 @@
 <link rel="match" href="../reference/ref-filled-green-100px-square.xht">
 
 <style>
+body {
+  overflow: hidden;
+}
 div {
   position: absolute;
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-contents-shadow-dom-1-ref.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-contents-shadow-dom-1-ref.html
new file mode 100644
index 0000000..df3aaf33
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-contents-shadow-dom-1-ref.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+  <head>
+  <title>Reference: CSS display:contents; in Shadow DOM</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=907396">
+<style>
+html,body {
+  color:black; background-color:white; font:12px/1 monospace; padding:0; margin:0;
+}
+
+span { color:blue; }
+</style>
+  </head>
+  <body>
+    <div>X 1 c</div>
+    <div>a 2 c</div>
+    <div>a 3 Y</div>
+    <div>X 4 Y</div>
+    <div>a 5 Y</div>
+    <div>X <span>6</span> c</div>
+    <div>a <span>7</span> c</div>
+    <div>a <span>8</span> Y</div>
+    <div>X <span>9</span> Y</div>
+    <div>a <span>A</span> Y</div>
+    <div>a <span>1 2</span> B</div>
+    <div>A <span>a 1 2 c</span> B</div>
+    <div>A <span>a 1 a 2 ca 3 c</span> B</div>
+    <div>A <span>a 1 c a 2 c</span> B</div>
+    <div>X <span>a 1 c a 2 c</span> B</div>
+    <div><span>1a 2 c</span></div>
+    <div><span>a 1 c2</span></div>
+    <div>A<span>b</span>c</div>
+    <div>A<span>b</span>c</div>
+    <div><span>b c</span>d</div>
+    <div><span>a </span>b</div>
+    <div><b>One</b><i>Two</i></div>
+    <div><b>One</b><i>Two</i></div>
+    <div><b>One</b><i>Two</i></div>
+    <div><b>One</b><i>Two</i></div>
+    <b style="color:blue">One</b><i style="color:blue">Two</i>Three
+    <div></div>
+    <b style="color:green">V</b>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-display/display-contents-shadow-dom-1.html b/third_party/blink/web_tests/external/wpt/css/css-display/display-contents-shadow-dom-1.html
new file mode 100644
index 0000000..1f391163
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-display/display-contents-shadow-dom-1.html
@@ -0,0 +1,221 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html class="reftest-wait" lang="en-US">
+  <head>
+  <meta charset="utf-8">
+  <title>CSS Test: CSS display:contents; in Shadow DOM</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=907396">
+  <link rel="help" href="https://drafts.csswg.org/css-display/">
+  <link rel="match" href="display-contents-shadow-dom-1-ref.html">
+<style>
+html,body {
+  color:black; background-color:white; font:12px/1 monospace; padding:0; margin:0;
+}
+.before::before, ::slotted(.before)::before {content: "a ";}
+.after::after, ::slotted(.after)::after {content: " c";}
+div.before::before {content: "X ";}
+div.after::after {content: " Y";}
+.b, .c, ::slotted(.b), ::slotted(.c) { display:contents; }
+</style>
+  </head>
+  <body>
+    <div id="host1" class="before"></div>
+    <span id="host2"></span>
+    <div id="host3" class="after"></div>
+    <div id="host4" class="before after"></div>
+    <div id="host5" class="after"></div>
+    <div id="host6" class="before"></div>
+    <div id="host7"></div>
+    <div id="host8" class="after"></div>
+    <div id="host9" class="before after"></div>
+    <div id="hostA" class="after"></div>
+    <div id="hostB"></div>
+    <div id="hostC"></div>
+    <div id="hostD"></div>
+    <div id="hostE"></div>
+    <div id="hostF" class="before"></div>
+    <div id="hostG"></div>
+    <span id="hostH"></span>
+    <div id="hostI"></div>
+    <div id="hostJ"></div>
+    <span id="hostK"></span>
+    <div id="hostL"></div>
+    <div id="hostM"><i slot=i>Two</i><b slot=b>One</b></div>
+    <div id="hostN"><i slot=i class="c">Two</i><b slot=b>One</b></div>
+    <div id="hostO"><i slot=i>Two</i><b slot=b class="c">One</b></div>
+    <div id="hostP"><i slot=i class="c">Two</i><b slot=b class="c">One</b></div>
+    <div id="hostQ" class="c" style="color:blue"><i slot=i class="c">Two</i><b slot=b class="c">One</b></div>Three
+    <div id="hostS" class="c"><span class="c">S</span></div>
+    <div id="hostT" class="c">T</div>
+    <div id="hostU"><span slot="c">U</span></div>
+    <div id="hostV" class="c" style="color:red"><b slot="b" class="c" style="color:inherit">V</b></div>
+
+   <script>
+      function shadow(id) {
+        return document.getElementById(id).attachShadow({mode:"open"});
+      }
+      function span(s) {
+        var e = document.createElement("span");
+        var t = document.createTextNode(s);
+        e.appendChild(t);
+        return e;
+      }
+      function text(s) {
+        return document.createTextNode(s);
+      }
+      function contents(n, slotName) {
+        var e = document.createElement("z");
+        e.style.display = "contents";
+        e.style.color = "blue";
+        if (n) e.appendChild(n);
+        if (slotName) e.setAttribute("slot", slotName);
+        return e;
+      }
+
+      function run() {
+        document.body.offsetHeight;
+
+        shadow("host1").innerHTML = '<slot style="display:inline"></slot> c';
+        shadow("host2").innerHTML = 'a <slot style="display:contents"></slot> c';
+        shadow("host3").innerHTML = 'a <slot style="display:contents"></slot>';
+        shadow("host4").innerHTML = '<slot style="display:contents"></slot>';
+        shadow("host5").innerHTML = 'a <slot style="display:contents"></slot>';
+        shadow("host6").innerHTML = '<z style="color:blue; display:contents"><slot style="display:inline"></slot></z> c';
+        shadow("host7").innerHTML = 'a <slot style="display:contents"></slot> c';
+        shadow("host8").innerHTML = 'a <z style="color:blue; display:contents"><slot style="display:contents"></z></slot>';
+        shadow("host9").innerHTML = '<slot style="display:contents"></slot>';
+        shadow("hostA").innerHTML = 'a <slot style="display:contents"></slot>';
+        shadow("hostB").innerHTML = 'a <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
+        shadow("hostC").innerHTML = 'A <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
+        shadow("hostD").innerHTML = 'A <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B <slot name="b"></slot>';
+        shadow("hostE").innerHTML = 'A <slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
+        shadow("hostF").innerHTML = '<slot name="c" style="display:contents"></slot> <slot name="b" style="display:contents"></slot> B';
+        shadow("hostG").innerHTML = '<slot name="b" style="display:contents"></slot>';
+        shadow("hostH").innerHTML = '<slot name="b" style="display:contents"></slot>';
+        shadow("hostI").innerHTML = 'A<slot name="b" style="display:contents"></slot>';
+        shadow("hostJ").innerHTML = 'A<slot name="b" style="display:contents"></slot>';
+        shadow("hostK").innerHTML = '<slot name="b" style="display:contents"></slot>';
+        shadow("hostL").innerHTML = '<slot name="b" style="display:contents"></slot>';
+        shadow("hostM").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
+        shadow("hostN").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
+        shadow("hostO").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
+        shadow("hostP").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
+        shadow("hostQ").innerHTML = '<slot name="b" style="display:contents"></slot><slot name="i" style="display:inline"></slot>';
+      }
+
+      function tweak() {
+        document.body.offsetHeight;
+
+        host1.appendChild(span("1"));
+        host2.appendChild(text("2"));
+        host3.appendChild(span("3"));
+        host4.appendChild(text("4"));
+
+        var e = span("5");
+        e.style.display = "contents";
+        host5.appendChild(e);
+
+        host6.appendChild(span("6"));
+        host7.appendChild(contents(text("7")));
+        host8.appendChild(contents(span("8")));
+        host9.appendChild(contents(text("9")));
+
+        var e = contents(span("A"));
+        hostA.appendChild(e);
+
+        var e = contents(text("2"), "b");
+        hostB.appendChild(e);
+        var e = contents(text("1"), "c");
+        hostB.appendChild(e);
+
+        var e = contents(text("2"), "b");
+        e.className = "after";
+        hostC.appendChild(e);
+        var e = contents(text("1"), "c");
+        e.className = "before";
+        hostC.appendChild(e);
+
+        var e = contents(text("2"), "b");
+        e.className = "before after";
+        hostD.appendChild(e);
+        var e = contents(text(" 3"), "b");
+        e.className = "before after";
+        hostD.appendChild(e);
+        var e = contents(text("1"), "c");
+        e.className = "before";
+        hostD.appendChild(e);
+
+        var e = contents(contents(text("2")), "b");
+        e.className = "before after";
+        hostE.appendChild(e);
+        var e2 = contents(text("1"), "c");
+        e2.className = "before after";
+        hostE.insertBefore(e2, e);
+
+        var e = contents(text("2"), "b");
+        e.className = "before after";
+        hostF.appendChild(e);
+        var e2 = contents(text("1"), "c");
+        e2.className = "before after";
+        hostF.insertBefore(e2, e);
+
+        var e = contents(contents(text("1")), "b");
+        hostG.appendChild(e);
+        var e = contents(text("2"), "b");
+        e.className = "before after";
+        hostG.appendChild(e);
+
+        var e = contents(contents(text("2")), "b");
+        hostH.appendChild(e);
+        var e2 = contents(text("1"), "b");
+        e2.className = "before after";
+        hostH.insertBefore(e2, e);
+
+        var e = contents(text("b"), "b");
+        hostI.appendChild(e);
+        var e = span("c");
+        e.setAttribute("slot", "b");
+        hostI.appendChild(e);
+
+        var e = contents(contents(text("b")), "b");
+        hostJ.appendChild(e);
+        var e = span("c");
+        e.setAttribute("slot", "b");
+        hostJ.appendChild(e);
+
+        var inner = span("b");
+        inner.className = "after";
+        var e = contents(contents(inner), "b");
+        hostK.appendChild(e);
+        var e = span("d");
+        e.setAttribute("slot", "b");
+        hostK.appendChild(e);
+
+        var inner = contents(null);
+        inner.className = "before";
+        var e = contents(inner, "b");
+        hostL.appendChild(e);
+        var e = span("b");
+        e.setAttribute("slot", "b");
+        hostL.appendChild(e);
+
+        document.body.offsetHeight;
+        setTimeout(function() {
+            shadow("hostS");
+            shadow("hostT");
+            shadow("hostU");
+            shadow("hostV").innerHTML = '<z style="color:green"><slot name="b"></slot></z>';
+
+            document.body.offsetHeight;
+            document.documentElement.removeAttribute("class");
+          },0);
+      }
+
+      run();
+      setTimeout(tweak, 0);
+    </script>
+  </body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/quoted-generic-ignored-ref.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/quoted-generic-ignored-ref.html
new file mode 100644
index 0000000..70e2d50
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/quoted-generic-ignored-ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<meta charset=utf-8>
+<title>CSS Reference: quoted font-family names must not be treated as generics</title>
+<link rel="author" title="Jonathan Kew" href="mailto:jfkthame@gmail.com"/>
+<style>
+body { font-size: 36px; }
+.test1 { font-family: serif; }
+.test2 { font-family: sans-serif; }
+.test3 { font-family: monospace; }
+</style>
+<body>
+<p>The following lines should be rendered with the generic font-families as named:</p>
+<div class="test1">serif</div>
+<div class="test2">sans-serif</div>
+<div class="test3">monospace</div>
+<div class="test1">serif</div>
+<div class="test2">sans-serif</div>
+<div class="test3">monospace</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-fonts/quoted-generic-ignored.html b/third_party/blink/web_tests/external/wpt/css/css-fonts/quoted-generic-ignored.html
new file mode 100644
index 0000000..4207ad5c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-fonts/quoted-generic-ignored.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+<meta charset=utf-8>
+<title>CSS Test: quoted font-family names must not be treated as generics</title>
+<link rel="author" title="Jonathan Kew" href="mailto:jfkthame@gmail.com"/>
+<link rel="help" href="https://www.w3.org/TR/css-fonts-3/#font-family-prop"/>
+<link rel="match" href="quoted-generic-ignored-ref.html"/>
+<meta name="assert" content="Font family names that happen to be the same as keyword value must be quoted to prevent confusion with the keywords with the same names"/>
+<style>
+body { font-size: 36px; }
+/* Note that this test assumes that the system does not have an actual
+   font named "Fantasy" or "Cursive" installed! */
+.fantasy-test1 { font-family: "fantasy", serif; }
+.fantasy-test2 { font-family: "fantasy", sans-serif; }
+.fantasy-test3 { font-family: "fantasy", monospace; }
+.cursive-test1 { font-family: "cursive", serif; }
+.cursive-test2 { font-family: "cursive", sans-serif; }
+.cursive-test3 { font-family: "cursive", monospace; }
+</style>
+</head>
+<body>
+<p>The following lines should be rendered with the generic font-families as named:</p>
+<div class="fantasy-test1">serif</div>
+<div class="fantasy-test2">sans-serif</div>
+<div class="fantasy-test3">monospace</div>
+<div class="cursive-test1">serif</div>
+<div class="cursive-test2">sans-serif</div>
+<div class="cursive-test3">monospace</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-layout-properties.html b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-layout-properties.html
index fcc2ce3b..b1b0bd87 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/grid-layout-properties.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/grid-layout-properties.html
@@ -142,8 +142,8 @@
         initial: 'row',
         'row': ['row', 'row'],
         'column': ['column', 'column'],
-        'dense': ['dense', 'row dense'],
-        'row dense': ['row dense', 'row dense'],
+        'dense': ['dense', 'dense'],
+        'row dense': ['dense', 'dense'],
         'column dense': ['column dense', 'column dense'],
         'reset': ['row', 'row'],
       },
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed-expected.txt
new file mode 100644
index 0000000..7610e495
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+PASS Property grid-auto-flow value 'row' computes to 'row'
+PASS Property grid-auto-flow value 'column' computes to 'column'
+FAIL Property grid-auto-flow value 'row dense' computes to 'dense' assert_equals: expected "dense" but got "row dense"
+PASS Property grid-auto-flow value 'column dense' computes to 'column dense'
+FAIL Property grid-auto-flow value 'dense row' computes to 'dense' assert_equals: expected "dense" but got "row dense"
+PASS Property grid-auto-flow value 'dense column' computes to 'column dense'
+FAIL Property grid-auto-flow value 'dense' computes to 'dense' assert_equals: expected "dense" but got "row dense"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed.html
index 7484f62d..a91593e 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-computed.html
@@ -13,13 +13,13 @@
 <script>
 test_computed_value("grid-auto-flow", "row");
 test_computed_value("grid-auto-flow", "column");
-test_computed_value("grid-auto-flow", "row dense");
+test_computed_value("grid-auto-flow", "row dense", "dense");
 test_computed_value("grid-auto-flow", "column dense");
 
-test_computed_value("grid-auto-flow", "dense row", "row dense");
+test_computed_value("grid-auto-flow", "dense row", "dense");
 test_computed_value("grid-auto-flow", "dense column", "column dense");
 
-test_computed_value("grid-auto-flow", "dense", "row dense");
+test_computed_value("grid-auto-flow", "dense", "dense");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid-expected.txt
new file mode 100644
index 0000000..d2139ff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid-expected.txt
@@ -0,0 +1,10 @@
+This is a testharness.js-based test.
+PASS e.style['grid-auto-flow'] = "row" should set the property value
+PASS e.style['grid-auto-flow'] = "column" should set the property value
+FAIL e.style['grid-auto-flow'] = "row dense" should set the property value assert_equals: serialization should be canonical expected "dense" but got "row dense"
+FAIL e.style['grid-auto-flow'] = "dense row" should set the property value assert_equals: serialization should be canonical expected "dense" but got "row dense"
+PASS e.style['grid-auto-flow'] = "dense" should set the property value
+PASS e.style['grid-auto-flow'] = "column dense" should set the property value
+PASS e.style['grid-auto-flow'] = "dense column" should set the property value
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid.html b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid.html
index 4270a3d..7db8b189 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-grid/parsing/grid-auto-flow-valid.html
@@ -14,11 +14,11 @@
 <script>
 test_valid_value("grid-auto-flow", "row");
 test_valid_value("grid-auto-flow", "column");
-test_valid_value("grid-auto-flow", "row dense");
+test_valid_value("grid-auto-flow", "row dense", "dense");
+test_valid_value("grid-auto-flow", "dense row", "dense");
+test_valid_value("grid-auto-flow", "dense");
+test_valid_value("grid-auto-flow", "column dense");
 test_valid_value("grid-auto-flow", "dense column", "column dense");
-
-// Blink/WebKit "dense", Edge/Firefox "row dense"
-test_valid_value("grid-auto-flow", "dense", ["dense", "row dense"]);
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-display-contents.html b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-set-display-contents.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-display-contents.html
rename to third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-set-display-contents.html
index a59576b..6508df0d 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-display-contents.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-set-display-contents.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Lists: counter-reset and counter-increment on display:contents</title>
+<title>CSS Lists: counter-reset, counter-set and counter-increment on display:contents</title>
 <link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
 <link rel="help" href="https://drafts.csswg.org/css-lists/#counters-without-boxes">
 <link rel="match" href="counter-7-ref.html">
@@ -8,6 +8,7 @@
   .inc { counter-increment: x }
   .reset-6 { counter-reset: x 6 }
   .reset-666 { counter-reset: x 666 }
+  .set-666 { counter-set: x 666 }
   .contents { display: contents }
   .result::before { content: counter(x) }
 </style>
@@ -15,5 +16,6 @@
 <div>
   <span class="reset-6"></span>
   <span class="contents reset-666 inc"></span>
+  <span class="contents set-666"></span>
   <span class="inc result"></span>
 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-display-none.html b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-set-display-none.html
similarity index 78%
rename from third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-display-none.html
rename to third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-set-display-none.html
index 3b344a7..510fd8b6 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-display-none.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-reset-increment-set-display-none.html
@@ -1,6 +1,6 @@
 <!DOCTYPE html>
 <meta charset="utf-8">
-<title>CSS Lists: counter-reset and counter-increment on display:none</title>
+<title>CSS Lists: counter-reset, counter-set and counter-increment on display:none</title>
 <link rel="author" title="Rune Lillesveen" href="mailto:futhark@chromium.org">
 <link rel="help" href="https://drafts.csswg.org/css-lists/#counters-without-boxes">
 <link rel="match" href="counter-7-ref.html">
@@ -8,6 +8,7 @@
   .inc { counter-increment: x }
   .reset-6 { counter-reset: x 6 }
   .reset-666 { counter-reset: x 666 }
+  .set-666 { counter-set: x 666 }
   .none { display: none }
   .result::before { content: counter(x) }
 </style>
@@ -15,5 +16,6 @@
 <div>
   <span class="reset-6"></span>
   <span class="none reset-666 inc"></span>
+  <span class="none set-666"></span>
   <span class="inc result"></span>
 </div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-001-ref.html
new file mode 100644
index 0000000..be06ea1d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-001-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Lists: basic tests for 'counter-set'</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+  </style>
+</head>
+<body>
+
+<span>7</span><!-- "7" -->
+<span>0</span><!-- "0" -->
+<span>7</span><!-- "7" -->
+<span>8</span><!-- "8" -->
+<span>2</span><!-- "2" -->
+<x>
+  <span>2</span><!-- "2" -->
+</x>
+<span>3</span><!-- "3" -->
+<x>
+  <span>0</span><!-- "0" -->
+  <span>2</span><!-- "2" -->
+  <x>
+    <span>2.5</span><!-- "2.5" -->
+  </x>
+</x>
+<span>3</span><!-- "3" -->
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-001.html b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-001.html
new file mode 100644
index 0000000..3be4c73
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-001.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Lists: basic tests for 'counter-set'</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <link rel="help" href="https://drafts.csswg.org/css-lists/#propdef-counter-set">
+  <link rel="match" href="counter-set-001-ref.html">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+span::before { content: counters(n, '.'); }
+  </style>
+</head>
+<body>
+
+<span style="counter-set: n 7"></span><!-- "7" -->
+<span style="counter-set: n"></span><!-- "0" -->
+<span style="counter-set: n 8 n 7"></span><!-- "7" -->
+<span style="counter-set: n 6; counter-increment: n 2"></span><!-- "8" -->
+<span style="counter-set: n; counter-increment: n 2"></span><!-- "2" -->
+<x style="counter-reset: n 9">
+  <span style="counter-set: n 2"></span><!-- "2" -->
+</x>
+<span style="counter-increment: n"></span><!-- "3" -->
+<x style="counter-reset: n 9">
+  <span style="counter-set: n"></span><!-- "0" -->
+  <span style="counter-set: n 2"></span><!-- "2" -->
+  <x style="counter-reset: n 1">
+    <span style="counter-set: n 5"></span><!-- "2.5" -->
+  </x>
+</x>
+<span style="counter-increment: n"></span><!-- "3" -->
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-002-ref.html
new file mode 100644
index 0000000..5ee2e30a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-002-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Lists: dynamic update test for 'counter-set'</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+</head>
+<body>
+<ol><li></li></ol>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-002.html b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-002.html
new file mode 100644
index 0000000..a479259
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/counter-set-002.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Lists: dynamic update test for 'counter-set'</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <link rel="help" href="https://drafts.csswg.org/css-lists/#propdef-counter-set">
+  <link rel="match" href="counter-set-002-ref.html">
+</head>
+<body onload="document.getElementById('item').style=''">
+<noscript>Test not run - javascript required.</noscript>
+<ol><li id="item" style="counter-increment: list-item 3"></li></ol>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-counter-increment-computed-style.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-counter-increment-computed-style.html
new file mode 100644
index 0000000..0fae6e3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-counter-increment-computed-style.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Magic list-item counter-increment shouldn't be visible from computed style</title>
+<link rel="help" href="https://drafts.csswg.org/css-lists/#declaring-a-list-item">
+<link rel="help" href="https://drafts.csswg.org/css-lists/#list-item-counter">
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<li data-expected="none">No explicit counter.
+<li><span style="counter-increment:inherit" data-expected="none">Inherited
+<li value="10" data-expected="none">Value attribute.
+<li style="counter-increment: list-item 10" data-expected="list-item 10">Explicit list-item counter.
+<li style="counter-increment: list-item 1" data-expected="list-item 1">Explicit and redundant list-item counter.
+<li style="counter-increment: foo 10" data-expected="foo 10">Other counter.
+<script>
+test(function() {
+  for (const element of document.querySelectorAll("[data-expected]"))
+    assert_equals(getComputedStyle(element).counterIncrement, element.getAttribute("data-expected"), element.innerText);
+}, "list-item counter-increment shouldn't be visible from computed style");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-list-item-counter-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-list-item-counter-ref.html
new file mode 100644
index 0000000..8340d6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-list-item-counter-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference:_CSS Lists: 'counter-increment:list-item' on LI</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 10em; }
+  </style>
+</head>
+<body>
+
+<ol><li value=0>a<li value=4>b<li value=4>c</ol>
+<ol><li value=0>a<li value=9>b<li value=9>c</ol>
+<ol><li value=-1>a<li value=3>b<li value=2>c</ol>
+<ol><li value=0>a<li value=4>b<li value=4>c</ol>
+<ol><li value=2>a<li value=6>b<li value=8>c</ol>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-list-item-counter.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-list-item-counter.html
new file mode 100644
index 0000000..b9a1196
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-list-item-counter.html
@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Lists: 'counter-increment:list-item' on LI</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <link rel="help" href="https://drafts.csswg.org/css-lists/#propdef-counter-increment">
+  <link rel="match" href="li-list-item-counter-ref.html">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 10em; }
+li { counter-increment: list-item 0; }
+.dec { counter-increment:list-item -1; }
+.zero { counter-increment:list-item 1 list-item -1; }
+.two { counter-increment:list-item 3 list-item -1; }
+  </style>
+</head>
+<body>
+
+<ol><li>a<li value=4>b<li>c</ol>
+<ol><li>a<li value=4 style="counter-increment:list-item 5">b<li>c</ol>
+<ol><li class=dec>a<li value=4 class=dec>b<li class=dec>c</ol>
+<ol><li class=zero>a<li value=4 class=zero>b<li class=zero>c</ol>
+<ol><li class=two>a<li value=4 class=two>b<li class=two>c</ol>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-counter-reset-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-counter-reset-001-ref.html
new file mode 100644
index 0000000..9afb1ecf
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-counter-reset-001-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>Reference:_CSS Lists: 'counter-set:list-item' trumps LI @value</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 10em; }
+  </style>
+</head>
+<body>
+
+<ol><li>a<li value=99>b</ol>
+<ol><li>a<li value=149>b</ol>
+<ol><li>a<li value=54>b</ol>
+<ol><li>a<li value=149>b</ol>
+<ol><li>a<li value=51>b</ol>
+<ol><li>a<li value=88>b</ol>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-counter-reset-001.html b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-counter-reset-001.html
new file mode 100644
index 0000000..0e91c3a0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/li-value-counter-reset-001.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>CSS Lists: 'counter-set:list-item' trumps LI @value</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <link rel="help" href="https://drafts.csswg.org/css-lists/#propdef-counter-set">
+  <link rel="match" href="li-value-counter-reset-001-ref.html">
+  <style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 10em; }
+li.set { counter-set: list-item 99; }
+  </style>
+</head>
+<body>
+
+<ol><li>a<li value=4 class=set>b</ol>
+<ol><li>a<li value=4 class=set style="counter-increment:list-item 50">b</ol>
+<ol><li>a<li value=4 style="counter-increment:list-item 50">b</ol>
+<ol><li>a<li class=set style="counter-increment:list-item 50">b</ol>
+<ol><li>a<li style="counter-increment:list-item 50">b</ol>
+<ol><li>a<li value=4 class=set style="counter-set:list-item 88">b</ol>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html
index 72a4c90..2d49bc4 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition-ref.html
@@ -8,4 +8,7 @@
   <img style="display: list-item" alt="Foo">
   <li value="4">Foo
   <li>Bar
+  <div style="display: list-item"><div style="display: list-item">Before</div>WithBefore</div>
+  <div style="display: list-item">WithAfter<div style="display: list-item">After</div></div>
+  <li value="10">Baz
 </ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html
index edae4b9..14e351f 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-lists/list-item-definition.html
@@ -1,15 +1,27 @@
 <!doctype html>
-<title>The definition of what a list-item is only depends on the display value, and doesn't account for pseudo-elements</title>
+<title>The definition of what a list-item is only depends on the display value</title>
 <link rel="help" href="https://drafts.csswg.org/css-lists/#list-item">
 <link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1539171">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1543758">
 <link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
 <link rel="author" href="https://mozilla.org" title="Mozilla">
 <link rel="match" href="list-item-definition-ref.html">
-<!-- TODO: Test pseudo-elements, see https://github.com/w3c/csswg-drafts/issues/3766 -->
+<style>
+  .before::before, .after::after {
+    display: list-item;
+    content: "Before";
+  }
+  .after::after {
+    content: "After";
+  }
+</style>
 <ol>
   <svg style="display: list-item"></svg>
   <img style="display: list-item">
   <img style="display: list-item" alt="Foo">
   <div style="display: list-item">Foo</div>
   <li>Bar
+  <li class="before">WithBefore
+  <li class="after">WithAfter
+  <li>Baz
 </ol>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-001-ref.html
new file mode 100644
index 0000000..d25ecd0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-001-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a multi-column container on button works with a column-span:all child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  button {
+    width: 400px;
+  }
+  .inner {
+    column-count: 3;
+    column-rule: 6px solid;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <button>
+    <div class="inner">
+      <div>block1</div><div>block2</div>
+      <h3>spanner</h3>
+      <div>block3</div><div>block4</div>
+    </div>
+  </button>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-001.html
new file mode 100644
index 0000000..1483309
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-001.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a multi-column container on button works with a column-span:all child</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-button-001-ref.html">
+  <meta name="assert" content="This test checks the page is rendered correctly for a multi-column container on button with a column-span:all child.">
+
+  <style>
+  button {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  </style>
+
+  <button>
+    <div>block1</div><div>block2</div>
+    <h3>spanner</h3>
+    <div>block3</div><div>block4</div>
+  </button>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-002-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-002-ref.html
new file mode 100644
index 0000000..c9ec677
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-002-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on button works with a column-span:all child and position:absolute boxes</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  button {
+    width: 400px;
+    padding: 1em;
+    overflow: hidden;
+    position: absolute;
+  }
+  .inner {
+    column-count: 3;
+    column-rule: 6px solid;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  a {
+    position: absolute;
+    width: 1em;
+    height: 1em;
+    background-color: blue;
+  }
+  </style>
+
+  <button>
+    <div class="inner">
+      <div>block1</div><div>block2</div><a></a>
+      <h3>spanner<a></a></h3>
+      <div>block3</div><div>block4</div><a></a>
+    </div>
+  </button>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-002.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-002.html
new file mode 100644
index 0000000..874cb130de
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-002.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on button works with a column-span:all child and position:absolute boxes</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-button-002-ref.html">
+  <meta name="assert" content="This test checks the page is rendered correctly for a overflow:hidden and position:absolute button multi-column container with a column-span:all child and position:absolute boxes.">
+
+  <style>
+  button {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+    padding: 1em;
+    overflow: hidden;
+    position: absolute;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  a {
+    position: absolute;
+    width: 1em;
+    height: 1em;
+    background-color: blue;
+  }
+  </style>
+
+  <button>
+    <div>block1</div><div>block2</div><a></a>
+    <h3>spanner<a></a></h3>
+    <div>block3</div><div>block4</div><a></a>
+  </button>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-003-ref.html
new file mode 100644
index 0000000..337f9c7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-003-ref.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on button works with a column-span:all child and position:fixed boxes</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  button {
+    width: 400px;
+    padding: 1em;
+    overflow: hidden;
+    position: absolute;
+  }
+  .inner {
+    column-count: 3;
+    column-rule: 6px solid;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  a {
+    position: fixed;
+    width: 1em;
+    height: 1em;
+    background-color: blue;
+  }
+  </style>
+
+  <button>
+    <div class="inner">
+      <div>block1</div><div>block2</div><a></a>
+      <h3>spanner<a></a></h3>
+      <div>block3</div><div>block4</div><a></a>
+    </div>
+  </button>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-003.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-003.html
new file mode 100644
index 0000000..fc15c94a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-button-003.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a overflow:hidden and position:absolute multi-column container on button works with a column-span:all child and position:fixed boxes</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-button-003-ref.html">
+  <meta name="assert" content="This test checks the page is rendered correctly for a overflow:hidden and position:absolute button multi-column container with a column-span:all child and position:absolute boxes.">
+
+  <style>
+  button {
+    column-count: 3;
+    column-rule: 6px solid;
+    width: 400px;
+    padding: 1em;
+    overflow: hidden;
+    position: absolute;
+  }
+  h3 {
+    column-span: all;
+    outline: 1px solid blue;
+  }
+  a {
+    position: fixed;
+    width: 1em;
+    height: 1em;
+    background-color: blue;
+  }
+  </style>
+
+  <button>
+    <div>block1</div><div>block2</div><a></a>
+    <h3>spanner<a></a></h3>
+    <div>block3</div><div>block4</div><a></a>
+  </button>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-001-ref.html
new file mode 100644
index 0000000..e95210f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-001-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test Reference: Test a multi-column container with percentage height children</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+
+  <style>
+  article {
+    width: 400px;
+    height: 200px;
+    outline: 1px solid black;
+  }
+  div {
+    height: 25%;
+  }
+  div.spanner {
+    outline: 1px solid blue;
+    height: 50%;
+  }
+  </style>
+
+  <article>
+    <div>block1</div>
+    <div class="spanner">spanner</div>
+    <div>block2</div>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-001.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-001.html
new file mode 100644
index 0000000..55bdef4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-children-height-001.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+  <meta charset="utf-8">
+  <title>CSS Multi-column Layout Test: Test a multi-column container with percentage height children</title>
+  <link rel="author" title="Ting-Yu Lin" href="tlin@mozilla.com">
+  <link rel="author" title="Mozilla" href="http://www.mozilla.org/">
+  <link rel="help" href="https://drafts.csswg.org/css-multicol-1/#column-span">
+  <link rel="match" href="multicol-span-all-children-height-001-ref.html">
+  <meta name="assert" content="This test checks the the percentage height children under multicol container is rendered correctly.">
+
+  <style>
+  article {
+    column-count: 2;
+    width: 400px;
+    height: 200px;
+    outline: 1px solid black;
+  }
+  div {
+    height: 50%; /* Spread evenly into two colums, each 25%. */
+  }
+  div.spanner {
+    column-span: all;
+    outline: 1px solid blue;
+    height: 50%;
+  }
+  </style>
+
+  <article>
+    <div>block1</div>
+    <div class="spanner">spanner</div>
+    <div>block2</div>
+  </article>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-crash-chrome-007.html b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-crash-chrome-007.html
new file mode 100644
index 0000000..9c24210
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-position/position-absolute-crash-chrome-007.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<title>CSS Position Absolute: Chrome crash</title>
+<link rel="author" href="mailto:atotic@chromium.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link rel="help" href="https://crbug.com/945696">
+<meta name="assert" content="Absolute descendant inside multiple nested split inlines does not crash.">
+<style>
+  body {
+    overflow: hidden;
+    margin: 0px;
+    font-size: 24px;
+  }
+  #block-container {
+    position: relative;
+  }
+  #css-container {
+    position: relative;
+    font-size: 12px;
+  }
+  #anonymous-parent {
+    background-color: #FFFF7F;
+  }
+  #anonymous-split {
+    background-color: #FFD997;
+  }
+  #css-container {
+    background-color: #BEE0FF;
+  }
+  #abs {
+    background-color: rgba(0, 255, 0, 0.5);
+    position:absolute;
+    top: 0px;
+    left: 0px;
+  }
+  #fullabs {
+    background-color: rgba(0, 255, 0, 0.5);
+    position: absolute;
+    top: 0;
+    left: 0;
+    bottom: 0;
+    right: 0;
+  }
+</style>
+<div id="block-container">
+  <span id="anonymous-parent">
+    parent <br>start
+    <span id="anonymous-split">
+      split start
+      <div id="splitter" >splitter</div>
+      split middle
+      <span id="css-container">
+        css-container start
+        <div id="abs">ABS</div>
+        <div id="fullabs">FULLABS</div>
+        css container end
+      </span>
+      split end
+    </span>
+    parent end
+  </span>
+</div>
+<script>
+document.body.offsetTop;
+ test(() => {
+ }, 'test passes if it does not crash');
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-009-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-009-ref.html
new file mode 100644
index 0000000..a3db09f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-009-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 40px; }
+.h m { display:inline-block; width:0; line-height:0; height:0; position:relative; left: -2ch; }
+.v m { writing-mode: vertical-lr; width:0; position:relative; left: -1em; height:0; text-indent:-2ch; }
+.lr { writing-mode: vertical-lr; }
+.big { font-size:xx-large; }
+.big-marker m { font-size:xx-large; }
+li { display: block; }
+</style>
+</head><body>
+<ol class="h">
+  <li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
+  <li><div></div><div class="big"><m style="font-size:initial">AB</m>C<br>D</div>
+  </li>
+</ol>
+<ol class="big-marker h">
+  <li><div><m>AB</m>C<br>D</div></li>
+  <li><div></div><div><m>AB</m>C<br>D</div></li>
+</ol>
+<ol class="v">
+  <li><div><m>AB</m>C<br>D</div></li>
+  <li><div></div><div><m>AB</m>C<br>D</div></li>
+  <li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
+</ol>
+<ol class="v big-marker">
+  <li><div><m>AB</m>C<br>D</div></li>
+</ol>
+</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-009.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-009.html
new file mode 100644
index 0000000..b3627cc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-009.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="match" href="marker-content-009-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 40px; }
+li::marker { content: 'AB'; }
+.v > li::marker { writing-mode: vertical-lr; }
+.lr { writing-mode: vertical-lr; }
+.big { font-size:xx-large; }
+.big-marker > li::marker { font-size:xx-large; }
+f { float: left; margin-right: 20px; }
+</style>
+</head><body>
+<ol>
+  <li><div class="big">C<br>D</div></li>
+  <li><div></div><div class="big">C<br>D</div>
+  </li>
+</ol>
+<ol class="big-marker">
+  <li><div>C<br>D</div></li>
+  <li><div></div><div>C<br>D</div></li>
+</ol>
+<ol class=v>
+  <li><div>C<br>D</div></li>
+  <li><div></div><div>C<br>D</div></li>
+  <li><div class="big">C<br>D</div></li>
+</ol>
+<ol class="v big-marker">
+  <li><div>C<br>D</div></li>
+</ol>
+</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-010-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-010-ref.html
new file mode 100644
index 0000000..5bee9bb1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-010-ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 40px; }
+.h m { display:inline-block; width:0; line-height:0; height:0; position:relative; left: -3ch; }
+.big { font-size:xx-large; }
+.big-marker m { font-size:xx-large; }
+li { display: block; }
+</style>
+</head><body>
+<ol class="h">
+  <li><div class="big"><m style="font-size:initial">1.</m>C<br>D</div></li>
+  <li><div></div><div class="big"><m style="font-size:initial">2.</m>C<br>D</div>
+  </li>
+</ol>
+<ol class="big-marker h">
+  <li><div><m>1.</m>C<br>D</div></li>
+  <li><div></div><div><m>2.</m>C<br>D</div></li>
+</ol>
+</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-010.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-010.html
new file mode 100644
index 0000000..ccd377d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-010.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="match" href="marker-content-010-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 40px; }
+.big { font-size:xx-large; }
+.big-marker > li::marker { font-size:xx-large; }
+</style>
+</head><body>
+<ol>
+  <li><div class="big">C<br>D</div></li>
+  <li><div></div><div class="big">C<br>D</div>
+  </li>
+</ol>
+<ol class="big-marker">
+  <li><div>C<br>D</div></li>
+  <li><div></div><div>C<br>D</div></li>
+</ol>
+</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-011-ref.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-011-ref.html
new file mode 100644
index 0000000..62a64a1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-011-ref.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Reference: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 40px; }
+.h m { display:inline-block; width:0; line-height:0; height:0; position:relative; left: -3ch; }
+.v m { writing-mode: vertical-lr; width:0; position:relative; left: -2em; height:0; text-indent:-3ch; }
+.lr { writing-mode: vertical-lr; }
+.big { font-size:xx-large; }
+.big-marker m { font-size:xx-large; }
+li { display: block; }
+</style>
+</head><body>
+<ol class="h">
+  <li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
+  <li><div></div><div class="big"><m style="font-size:initial">AB</m>C<br>D</div>
+  </li>
+</ol>
+<ol class="big-marker h">
+  <li><div><m>AB</m>C<br>D</div></li>
+  <li><div></div><div><m>AB</m>C<br>D</div></li>
+</ol>
+<ol class="v">
+  <li><div><m>AB</m>C<br>D</div></li>
+  <li><div></div><div><m>AB</m>C<br>D</div></li>
+  <li><div class="big"><m style="font-size:initial">AB</m>C<br>D</div></li>
+</ol>
+<ol class="v big-marker">
+  <li><div><m>AB</m>C<br>D</div></li>
+</ol>
+</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-011.html b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-011.html
new file mode 100644
index 0000000..0cc20b0c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-pseudo/marker-content-011.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html><head>
+<meta charset="utf-8">
+<title>CSS Test: ::marker pseudo elements styled with 'content' property</title>
+<link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.com">
+<link rel="match" href="marker-content-011-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-pseudo-4/#marker-pseudo">
+<style>
+html,body {
+  color:black; background-color:white; font:16px/1 monospace; padding:0; margin:0;
+}
+body { margin-left: 40px; }
+li::marker { content: 'AB'; margin-bottom: 1ch; margin-right: 1ch; }
+.v > li::marker { writing-mode: vertical-lr; margin-right: 1em; }
+.lr { writing-mode: vertical-lr; }
+.big { font-size:xx-large; }
+.big-marker > li::marker { font-size:xx-large; }
+f { float: left; margin-right: 20px; }
+</style>
+</head><body>
+<ol>
+  <li><div class="big">C<br>D</div></li>
+  <li><div></div><div class="big">C<br>D</div>
+  </li>
+</ol>
+<ol class="big-marker">
+  <li><div>C<br>D</div></li>
+  <li><div></div><div>C<br>D</div></li>
+</ol>
+<ol class=v>
+  <li><div>C<br>D</div></li>
+  <li><div></div><div>C<br>D</div></li>
+  <li><div class="big">C<br>D</div></li>
+</ol>
+<ol class="v big-marker">
+  <li><div>C<br>D</div></li>
+</ol>
+</body></html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance-expected.txt
new file mode 100644
index 0000000..8289641
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance-expected.txt
@@ -0,0 +1,41 @@
+This is a testharness.js-based test.
+PASS Property scroll-margin-block-end has initial value 0px
+PASS Property scroll-margin-block-end does not inherit
+PASS Property scroll-margin-block-start has initial value 0px
+PASS Property scroll-margin-block-start does not inherit
+PASS Property scroll-margin-bottom has initial value 0px
+PASS Property scroll-margin-bottom does not inherit
+PASS Property scroll-margin-inline-end has initial value 0px
+PASS Property scroll-margin-inline-end does not inherit
+PASS Property scroll-margin-inline-start has initial value 0px
+PASS Property scroll-margin-inline-start does not inherit
+PASS Property scroll-margin-left has initial value 0px
+PASS Property scroll-margin-left does not inherit
+PASS Property scroll-margin-right has initial value 0px
+PASS Property scroll-margin-right does not inherit
+PASS Property scroll-margin-top has initial value 0px
+PASS Property scroll-margin-top does not inherit
+PASS Property scroll-padding-block-end has initial value auto
+PASS Property scroll-padding-block-end does not inherit
+PASS Property scroll-padding-block-start has initial value auto
+PASS Property scroll-padding-block-start does not inherit
+PASS Property scroll-padding-bottom has initial value auto
+PASS Property scroll-padding-bottom does not inherit
+PASS Property scroll-padding-inline-end has initial value auto
+PASS Property scroll-padding-inline-end does not inherit
+PASS Property scroll-padding-inline-start has initial value auto
+PASS Property scroll-padding-inline-start does not inherit
+PASS Property scroll-padding-left has initial value auto
+PASS Property scroll-padding-left does not inherit
+PASS Property scroll-padding-right has initial value auto
+PASS Property scroll-padding-right does not inherit
+PASS Property scroll-padding-top has initial value auto
+PASS Property scroll-padding-top does not inherit
+PASS Property scroll-snap-align has initial value none
+PASS Property scroll-snap-align does not inherit
+PASS Property scroll-snap-stop has initial value normal
+PASS Property scroll-snap-stop does not inherit
+PASS Property scroll-snap-type has initial value none
+FAIL Property scroll-snap-type does not inherit assert_equals: expected "inline" but got "inline proximity"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance.html
index b380cb40..2569cf3 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/inheritance.html
@@ -33,7 +33,7 @@
 assert_not_inherited('scroll-padding-top', 'auto', '10px');
 assert_not_inherited('scroll-snap-align', 'none', 'start end');
 assert_not_inherited('scroll-snap-stop', 'normal', 'always');
-assert_not_inherited('scroll-snap-type', 'none', 'inline proximity');
+assert_not_inherited('scroll-snap-type', 'none', 'inline');
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas-expected.txt
new file mode 100644
index 0000000..fd97904
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas-expected.txt
@@ -0,0 +1,14 @@
+This is a testharness.js-based test.
+PASS Snaps to the snap position if the snap area doesn't cover the snapport on x.
+PASS Snaps to the snap position if the snap area covers the snapport on x on the right border.
+PASS Snaps to the snap position if the snap area covers the snapport on x on the left border.
+PASS Snaps if the distance between the previous(400) and next(800) snap positions is smaller than snapport(500) on x.
+PASS Snaps if the distance between the previous(400) and next(800) snap positions is smaller than snapport(500) on y.
+PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and the distance between the previous(800) and next(1400) is larger than snapport(500).
+PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and the distance between the previous(800) and next(1400) is larger than snapport(500).
+PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on x and there is no subsequent snap positions.
+PASS Snap to current scroll position which is a valid snap position, as the snap area covers snapport on y and there is no subsequent snap positions.
+FAIL Don't snap back even if scrollTo tries to scroll to positions which are outside of the scroll range and if a snap target element covers the snaport assert_equals: expected 3715 but got 2200
+PASS Snap to current scroll position on x as the area is covering x axis.However, we snap to the specified snap position on y as the area is not covering y axis.
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas.html
index 8f6698d..ee31847 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/overflowing-snap-areas.html
@@ -63,6 +63,7 @@
     <div class="target small" style="top: 200px"></div>
     <div class="target small" style="top: 600px"></div>
     <div class="target small" style="top: 1200px"></div>
+    <div class="target large-y" style="top: 2000px"></div>
   </div>
 </div>
 
@@ -144,6 +145,20 @@
    "snap area covers snapport on y and there is no subsequent snap positions.");
 
 test(() => {
+  const maxScrollTop = scroller_y.scrollHeight - scroller_y.clientHeight;
+
+  // Scroll to the bottom edge which is a valid snap position that a large
+  // target element covers the snapport.
+  scroller_y.scrollTo(0, maxScrollTop);
+  assert_equals(scroller_y.scrollTop, maxScrollTop);
+
+  // Scroll to `the bottom edge + 1`.
+  scroller_y.scrollTo(0, maxScrollTop + 1);
+  assert_equals(scroller_y.scrollTop, maxScrollTop);
+}, "Don't snap back even if scrollTo tries to scroll to positions which are " +
+   "outside of the scroll range and if a snap target element covers the snaport");
+
+test(() => {
   two_axes_scroller.scrollTo(10, 100);
   assert_equals(two_axes_scroller.scrollLeft, 10);
   assert_equals(two_axes_scroller.scrollTop, 200);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt
new file mode 100644
index 0000000..3c91974
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt
@@ -0,0 +1,11 @@
+This is a testharness.js-based test.
+PASS e.style['scroll-snap-type'] = "none" should set the property value
+PASS e.style['scroll-snap-type'] = "x" should set the property value
+PASS e.style['scroll-snap-type'] = "y" should set the property value
+PASS e.style['scroll-snap-type'] = "block" should set the property value
+PASS e.style['scroll-snap-type'] = "inline" should set the property value
+PASS e.style['scroll-snap-type'] = "both" should set the property value
+PASS e.style['scroll-snap-type'] = "y mandatory" should set the property value
+FAIL e.style['scroll-snap-type'] = "inline proximity" should set the property value assert_equals: serialization should be canonical expected "inline" but got "inline proximity"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html
index fde2211..59a0cb9 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html
@@ -20,7 +20,7 @@
 test_valid_value("scroll-snap-type", "both");
 
 test_valid_value("scroll-snap-type", "y mandatory");
-test_valid_value("scroll-snap-type", "inline proximity");
+test_valid_value("scroll-snap-type", "inline proximity", "inline"); // The shortest serialization is preferable
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-padding.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-padding.html
new file mode 100644
index 0000000..0c637ed6d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-padding.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-padding" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  position: absolute;
+  margin: 0px;
+}
+#scroller {
+  height: 500px;
+  width: 500px;
+  overflow: hidden;
+  scroll-snap-type: both mandatory;
+}
+#target {
+  width: 300px;
+  height: 300px;
+  background-color: blue;
+}
+</style>
+
+<div id="scroller">
+  <div style="width: 2000px; height: 2000px;"></div>
+  <div id="target"></div>
+</div>
+
+<script>
+test(() => {
+  scroller.style.scrollPadding = "100px";
+
+  target.style.scrollSnapAlign = "start";
+  target.style.left = "300px";
+  target.style.top = "300px";
+
+  scroller.scrollTo(0, 0);
+  // `target position (300px, 300px)` - `padding (100px, 100px)`.
+  assert_equals(scroller.scrollLeft, 200);
+  assert_equals(scroller.scrollTop, 200);
+
+  target.style.scrollSnapAlign = "end";
+
+  // `target position (300px, 300px)` + `target size (300px, 300px) +
+  // `padding (100px, 100px) - `scroller size (500px, 500px)`.
+  scroller.scrollTo(0, 0);
+  assert_equals(scroller.scrollLeft, 200);
+  assert_equals(scroller.scrollTop, 200);
+}, "Snaps to the positions adjusted by scroll-padding");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-snap-type-on-root-element-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-snap-type-on-root-element-expected.txt
new file mode 100644
index 0000000..2694ce2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-snap-type-on-root-element-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+FAIL The scroll-snap-type on the root element is applied assert_equals: expected 515 but got 1000
+FAIL The writing-mode on the body is used assert_equals: expected 515 but got 1000
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-snap-type-on-root-element.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-snap-type-on-root-element.html
new file mode 100644
index 0000000..c2c413d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-snap-type-on-root-element.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#scroll-snap-type"/>
+<link rel="help" href="https://drafts.csswg.org/css-writing-modes-4/#principal-flow"/>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+html {
+  height: 3000px;
+  scroll-snap-type: inline mandatory;
+}
+#target {
+  position: absolute;
+  background-color: blue;
+  top: 1000px;
+  width: 100%;
+  height: 100px;
+}
+</style>
+<div id="target"></div>
+<script>
+const documentHeight = document.documentElement.clientHeight;
+test(() => {
+  target.style.scrollSnapAlign = "end start";
+
+  window.scrollTo(0, 1000);
+
+  // `target y (1000px)` + `target height (100px)` - document height.
+  assert_equals(document.scrollingElement.scrollTop, 1100 - documentHeight);
+
+  target.style.scrollSnapAlign = "";
+  window.scrollTo(0, 0);
+}, "The scroll-snap-type on the root element is applied");
+
+test(() => {
+  document.body.style.writingMode = "vertical-rl";
+  target.style.scrollSnapAlign = "start end";
+
+  window.scrollTo(0, 1000);
+  // `target y (1000px)` + `target height (100px)` - document height.
+  assert_equals(document.scrollingElement.scrollTop, 1100 - documentHeight);
+}, "The writing-mode on the body is used");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-001-ref.html
new file mode 100644
index 0000000..28b0018
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-001-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<title>Reference</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+    font: 20px/1 sans-serif;
+  }
+  .container > div {
+    height: 1em;
+    margin: 1em 0;
+    background: green;
+  }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-001.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-001.html
new file mode 100644
index 0000000..eeda674e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-001.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<title>#target and snap position with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#choosing'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name="flags" content="may">
+<meta name='assert'
+      content="Test passes if scroll snapping is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when navigating to an element with the target fragment ID.">
+
+<style type='text/css'>
+  iframe {
+    border: solid blue 4px;
+    height: 80px;
+    width: calc(100% - 8px);
+  }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<iframe class="container" src="support/scroll-target-align-001-iframe.html#target">This UA doesn't support iframes; please request a custom version of this test!</iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-002.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-002.html
new file mode 100644
index 0000000..7e82f03
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-002.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html>
+<title>scrollIntoView() and snap position with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#choosing'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name="flags" content="may">
+<meta name='assert'
+      content="Test passes if scroll snapping is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when scrolling an element into view
+               explicitly by script.">
+
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div {
+    height: 1em;
+  }
+  .container { scroll-padding: .5em 0 0;  } /* set up a snap position      */
+  #target    { scroll-margin:  .5em 0 0;
+               scroll-snap-align: center; }
+  #stripe    { background: green;         } /* color part of the snap area */
+  .fail      { color: red;                } /* make failing more obvious   */
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <div id="target"></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').scrollIntoView();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-003.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-003.html
new file mode 100644
index 0000000..1d6fbebb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-align-003.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<title>focus() and snap position with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#choosing'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name="flags" content="may">
+<meta name='assert'
+      content="Test passes if scroll snapping is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when scrolling an element into view
+               even if that operation is implied (in this case, by .focus()).">
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div, a {
+    height: 1em;
+    display: block;
+    outline: none;
+  }
+  .container { scroll-padding:  .5em 0 0; } /* set up a snap position      */
+  #target    { scroll-margin:   .5em 0 0;
+               scroll-snap-align: center; }
+  #stripe    { background: green;         } /* color part of the snap area  */
+  .fail      { color: red;                } /* make failing more obvious    */
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <a href="" id="target"></a>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').focus();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-001.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-001.html
new file mode 100644
index 0000000..8ddbbcec
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-001.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<title>#target and scroll-margin with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#scroll-margin'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name="flags" content="should">
+<meta name='assert'
+      content="Test passes if scroll-margin is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when navigating to an element with the target fragment ID.">
+
+<style type='text/css'>
+  iframe {
+    border: solid blue 4px;
+    height: 80px;
+    width: calc(100% - 8px);
+  }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<iframe class="container" src="support/scroll-target-margin-001-iframe.html#target">This UA doesn't support iframes; please request a custom version of this test!</iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-002.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-002.html
new file mode 100644
index 0000000..a02cf7d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-002.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<title>scrollIntoView() and scroll-margin with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#scroll-margin'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name="flags" content="should">
+<meta name='assert'
+      content="Test passes if scroll-margin is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when scrolling an element into view
+               explicitly by script.">
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div {
+    height: 1em;
+  }
+  #target    { scroll-margin: 2em 0 1em; } /* snap area is exact fit for snapport */
+  #stripe    { background: green;        } /* color part of the snap area         */
+  .fail      { color: red;               } /* make failing more obvious           */
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <div id="target"></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').scrollIntoView();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-003.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-003.html
new file mode 100644
index 0000000..d0434db
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-margin-003.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<title>focus() and scroll-margin with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#scroll-margin'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name="flags" content="should">
+<meta name='assert'
+      content="Test passes if scroll-margin is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when scrolling an element into view
+               even if that operation is implied (in this case, by .focus()).">
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div, a {
+    height: 1em;
+    display: block;
+    outline: none;
+  }
+  #target    { scroll-margin: 2em 0 1em; } /* snap area is exact fit for snapport */
+  #stripe    { background: green;        } /* color part of the snap area         */
+  .fail      { color: red;               } /* make failing more obvious           */
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <a href="" id="target"></a>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').focus();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-001.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-001.html
new file mode 100644
index 0000000..5cd4fddc
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-001.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<title>#target and scroll-padding with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#scroll-padding'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name='assert'
+      content="Test passes if scroll-padding is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when navigating to an element with the target fragment ID.">
+<style type='text/css'>
+  iframe {
+    border: solid blue 4px;
+    height: 80px;
+    width: calc(100% - 8px);
+  }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<iframe class="container" src="support/scroll-target-padding-001-iframe.html#target">This UA doesn't support iframes; please request a custom version of this test!</iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-002.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-002.html
new file mode 100644
index 0000000..3a0ca3b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-002.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<title>scrollIntoView() and scroll-padding with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#scroll-padding'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name='assert'
+      content="Test passes if scroll-padding is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when scrolling an element into view
+               explicitly by script.">
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div {
+    height: 1em;
+  }
+  .container { scroll-padding: 2em 0 1em; } /* snap area is exact fit for snapport */
+  #stripe    { background: green;         } /* color part of the snap area         */
+  .fail      { color: red;                } /* make failing more obvious           */
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <div id="target"></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').scrollIntoView();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-003.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-003.html
new file mode 100644
index 0000000..1e92e9be
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-padding-003.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<title>focus() and scroll-padding with snapping off (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#scroll-margin'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name='assert'
+      content="Test passes if scroll-padding is honored
+               on a scroll container with 'scroll-snap-type: none'
+               when scrolling an element into view
+               even if that operation is implied (in this case, by .focus()).">
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div, a {
+    height: 1em;
+    display: block;
+    outline: none;
+  }
+  .container { scroll-padding: 2em 0 1em; } /* snap area is exact fit for snapport */
+  #stripe    { background: green;         } /* color part of the snap area         */
+  .fail      { color: red;                } /* make failing more obvious           */
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <a href="" id="target"></a>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').focus();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-001.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-001.html
new file mode 100644
index 0000000..76d3222a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-001.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<title>#target and snap position with snapping on (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#choosing'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name='assert'
+      content="Test passes if scroll snapping is honored
+               when navigating to an element with the target fragment ID.">
+
+<style type='text/css'>
+  iframe {
+    border: solid blue 4px;
+    height: 80px;
+    width: calc(100% - 8px);
+  }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<iframe class="container" src="support/scroll-target-snap-001-iframe.html#target">This UA doesn't support iframes; please request a custom version of this test!</iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-002.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-002.html
new file mode 100644
index 0000000..89df44cb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-002.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<title>scrollIntoView() and snap position with snapping on (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#choosing'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name='assert'
+      content="Test passes if scroll snapping is honored
+               when scrolling an element into view
+               explicitly by script.">
+
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+    scroll-snap-type: block;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div {
+    height: 1em;
+  }
+  #target    { scroll-margin:    1em 0 0;
+               scroll-snap-align: center; } /* set up a snap position      */
+  #stripe    { background: green;         } /* color part of the snap area */
+  .fail      { color: red;                } /* make failing more obvious   */
+
+  /* Try to foil the UA */
+  .foilup { margin-bottom: -1em; scroll-snap-align: start; }
+  .foildn { margin-top:    -1em; scroll-snap-align: end; }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="foilup"></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <div class="foilup"></div>
+  <div class="foildn"></div>
+  <div id="target"></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div class="foildn"></div>
+  <div></div>
+  <div class="foildn"></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').scrollIntoView();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-003.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-003.html
new file mode 100644
index 0000000..3e90347a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scroll-target-snap-003.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<title>focus() and snap position with snapping on (y-axis)</title>
+<link rel='author' title='Elika J. Etemad' href='http://fantasai.inkedblade.net/contact'>
+<link rel='help' href='https://www.w3.org/TR/css-scroll-snap-1/#choosing'>
+<link rel='match' href='scroll-target-001-ref.html'>
+<meta name='assert'
+      content="Test passes if scroll snapping is honored
+               when scrolling an element into view
+               even if that operation is implied (in this case, by .focus()).">
+
+<style type='text/css'>
+  .container {
+    border: solid blue 4px;
+    height: 4em;
+    overflow: auto;
+    scroll-snap-type: block;
+
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  .container > div, a {
+    height: 1em;
+    display: block;
+    outline: none;
+  }
+  #target    { scroll-margin:    1em 0 0;
+               scroll-snap-align: center; } /* set up a snap position      */
+  #stripe    { background: green;         } /* color part of the snap area */
+  .fail      { color: red;                } /* make failing more obvious   */
+
+  /* Try to foil the UA */
+  .foilup { margin-bottom: -1em; scroll-snap-align: start; }
+  .foildn { margin-top:    -1em; scroll-snap-align: end;   }
+</style>
+
+<div id='instructions'>Test passes if there is a green stripe across the second quarter of the box below and no red.</div>
+
+<div class="container">
+  <div></div>
+  <div></div>
+  <div></div>
+  <div></div>
+  <div class="foilup"></div>
+  <div class="fail">FAIL</div>
+  <div></div>
+  <div id="stripe"></div>
+  <div class="foilup"></div>
+  <a href="" id="target"></a>
+  <div class="foildn"></div>
+  <div></div>
+  <div class="fail">FAIL</div>
+  <div class="foildn"></div>
+  <div></div>
+  <div class="foildn"></div>
+  <div></div>
+  <div></div>
+  <div></div>
+</div>
+
+<script>
+  document.getElementById('target').focus();
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scrollTo-scrollBy-snaps.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scrollTo-scrollBy-snaps.html
index fba38cb..48bfb51 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scrollTo-scrollBy-snaps.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/scrollTo-scrollBy-snaps.html
@@ -3,7 +3,7 @@
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <style>
-body {
+html {
   margin: 0px;
   overflow: scroll;
   scroll-snap-type: both mandatory;
@@ -23,8 +23,8 @@
 .space {
   left: 0px;
   top: 0px;
-  width: 2100px;
-  height: 2100px;
+  width: 4000px;
+  height: 4000px;
 }
 .target {
   width: 600px;
@@ -151,9 +151,9 @@
     window.scrollTo(0, 0);
     assert_equals(window.scrollX, 0);
     assert_equals(window.scrollY, 0);
-    window.scrollTo(input);
+    window.scrollBy(input);
     assert_equals(window.scrollX, expectedX);
     assert_equals(window.scrollY, expectedY);
   }, `scrollBy(${format_dict(input)}) on window lands on (${expectedX}, ${expectedY})`);
 });
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt
index 21a849e..4819c39 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block-expected.txt
@@ -1,6 +1,11 @@
 This is a testharness.js-based test.
-PASS Snaps correctly for horizontal-tb writing mode with 'inline' and 'block' alignments
-PASS Snaps correctly for vertical-lr writing mode with 'inline' and 'block' alignments
-FAIL Snaps correctly for vertical-rl writing mode with 'inline' and 'block' alignments assert_equals: aligns correctly on x expected -315 but got 300
+PASS Snaps correctly for horizontal-tb writing mode with 'scroll-snap-align: end start' alignment
+PASS Snaps correctly for vertical-lr writing mode with 'scroll-snap-align: end start' alignment
+FAIL Snaps correctly for vertical-rl writing mode with 'scroll-snap-align: end start' alignment assert_equals: aligns correctly on x expected -315 but got 300
+FAIL Snaps correctly for horizontal-tb writing mode with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected 115 but got 0
+FAIL Snaps correctly for vertical-lr writing mode with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected 300 but got 0
+FAIL Snaps correctly for vertical-rl writing mode with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected -500 but got 115
+FAIL Snaps correctly for 'direction: rtl' with 'scroll-snap-align: end start' alignment assert_equals: aligns correctly on x expected -500 but got 0
+FAIL Snaps correctly for 'direction: rtl' with 'scroll-snap-align: start end' alignment assert_equals: aligns correctly on x expected -315 but got 0
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block.html
index 9f9da8f..377039c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-inline-block.html
@@ -22,7 +22,6 @@
   height: 200px;
   left: 300px;
   top: 300px;
-  scroll-snap-align: end start;
 }
 </style>
 
@@ -32,22 +31,81 @@
 </div>
 
 <script>
-var scroller = document.getElementById("scroller");
-var width = scroller.clientWidth;
-var height = scroller.clientHeight;
+const scroller_width = scroller.clientWidth;
+const scroller_height = scroller.clientHeight;
 [
-  ["horizontal-tb", 300, 500 - height],
-  ["vertical-lr", 500 - width, 300],
-  ["vertical-rl", width - 700, 300]
+  ["horizontal-tb", 300,                  500 - scroller_height],
+  ["vertical-lr",   500 - scroller_width, 300],
+  ["vertical-rl",   scroller_width - 700, 300]
 ].forEach(([writing_mode, left, top]) => {
   test(() => {
+    const target_left = getComputedStyle(target).left;
     scroller.style.writingMode = writing_mode;
-    if (writing_mode == "vertical-rl")
-      document.getElementById("target").style.left = (width - 700) + "px";
+    target.style.scrollSnapAlign = "end start";
+    if (writing_mode == "vertical-rl") {
+      target.style.left = (scroller_width - 700) + "px";
+    }
     scroller.scrollTo(0, 0);
     assert_equals(scroller.scrollLeft, left, "aligns correctly on x");
     assert_equals(scroller.scrollTop, top, "aligns correctly on y");
+    target.style.left = target_left;
+    scroller.style.writingMode = "";
   }, "Snaps correctly for " + writing_mode +
-     " writing mode with 'inline' and 'block' alignments");
-})
+     " writing mode with 'scroll-snap-align: end start' alignment");
+});
+
+[
+  ["horizontal-tb", 500 - scroller_width,     300],
+  ["vertical-lr",   300,                      500 - scroller_height],
+  ["vertical-rl",   target.clientWidth - 700, 500 - scroller_height]
+].forEach(([writing_mode, left, top]) => {
+  test(() => {
+    const target_left = getComputedStyle(target).left;
+    scroller.style.writingMode = writing_mode;
+    target.style.scrollSnapAlign = "start end";
+    if (writing_mode == "vertical-rl") {
+      target.style.left = (scroller_width - 700) + "px";
+    }
+    scroller.scrollTo(0, 0);
+    assert_equals(scroller.scrollLeft, left, "aligns correctly on x");
+    assert_equals(scroller.scrollTop, top, "aligns correctly on y");
+    target.style.left = target_left;
+    scroller.style.writingMode = "";
+  }, "Snaps correctly for " + writing_mode +
+     " writing mode with 'scroll-snap-align: start end' alignment");
+});
+
+test(() => {
+  const target_left = getComputedStyle(target).left;
+  scroller.style.direction = "rtl";
+  target.style.scrollSnapAlign = "end start";
+  target.style.left = (scroller_width - 700) + "px";
+
+  scroller.scrollTo(0, 0);
+  assert_equals(scroller.scrollLeft, target.clientWidth - 700,
+                "aligns correctly on x");
+  assert_equals(scroller.scrollTop, 500 - scroller_height,
+                "aligns correctly on y");
+
+  target.style.left = target_left;
+  scroller.style.direction = "";
+}, "Snaps correctly for 'direction: rtl' with 'scroll-snap-align: end start' " +
+   "alignment");
+
+test(() => {
+  const target_left = getComputedStyle(target).left;
+  scroller.style.direction = "rtl";
+  target.style.scrollSnapAlign = "start end";
+  target.style.left = (scroller_width - 700) + "px";
+
+  scroller.scrollTo(0, 0);
+  assert_equals(scroller.scrollLeft, scroller_width - 700,
+                "aligns correctly on x");
+  assert_equals(scroller.scrollTop, 300, "aligns correctly on y");
+
+  target.style.left = target_left;
+  scroller.style.direction = "";
+}, "Snaps correctly for 'direction: rtl' with 'scroll-snap-align: start end' " +
+   "alignment");
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-transformed-target.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-transformed-target.html
new file mode 100644
index 0000000..2a44025
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-transformed-target.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  position: absolute;
+}
+#scroller {
+  overflow: hidden; /* TODO: Use scrollbar-width: none */
+  scroll-snap-type: x mandatory;
+  width: 500px;
+  height: 500px;
+}
+.space {
+  width: 2000px;
+  height: 2000px;
+}
+#target {
+  height: 200px;
+  width: 200px;
+  left: 50px;
+  background-color: blue;
+}
+</style>
+<div id="scroller">
+  <div class="space"></div>
+  <div id="target"></div>
+</div>
+<script>
+test(() => {
+  target.style.scrollSnapAlign = "start";
+  target.style.transform = "translateX(300px)";
+  scroller.scrollTo(10, 0);
+  assert_equals(scroller.scrollLeft, 350 /* left + translateX(300px) */);
+  assert_equals(scroller.scrollTop, 0);
+}, "Snaps to the transformed snap start position");
+
+test(() => {
+  target.style.scrollSnapAlign = "end";
+  target.style.transform = "translateX(300px)";
+  scroller.scrollTo(10, 0);
+  assert_equals(scroller.scrollLeft,
+                50 /* left + width + translateX(300px) - scroller.width */);
+  assert_equals(scroller.scrollTop, 0);
+}, "Snaps to the transformed snap end position");
+
+test(() => {
+  target.style.scrollSnapAlign = "start";
+  target.style.transform = "translateX(-100px)";
+  scroller.scrollTo(10, 0);
+  assert_equals(scroller.scrollLeft, 0);
+  assert_equals(scroller.scrollTop, 0);
+}, "Snaps to visible top left position of the transformed box");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas-expected.txt
new file mode 100644
index 0000000..029b8ee
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas-expected.txt
@@ -0,0 +1,6 @@
+This is a testharness.js-based test.
+PASS Only snap to visible area on X axis, even when the non-visible ones are closer
+PASS Only snap to visible area on Y axis, even when the non-visible ones are closer
+FAIL snap to snap area inflated by scroll-margin, even when the non-visible ones are closer assert_equals: expected 800 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas.html
index 8227434..3e822db 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/snap-to-visible-areas.html
@@ -40,12 +40,20 @@
   top: 800px;
 }
 
+#right-bottom {
+  left: 1800px;
+  top: 1800px;
+  scroll-margin-top: 1000px;
+  scroll-margin-left: 1000px;
+}
+
 </style>
 <div id="scroller">
   <div id="space"></div>
   <div id="left-top" class="snap"></div>
   <div id="right-top" class="snap"></div>
   <div id="left-bottom" class="snap"></div>
+  <div id="right-bottom" class="snap"></div>
 </div>
 <script>
 var scroller = document.getElementById("scroller");
@@ -66,4 +74,13 @@
   assert_equals(scroller.scrollLeft, 0);
   assert_equals(scroller.scrollTop, 800);
 }, 'Only snap to visible area on Y axis, even when the non-visible ones are closer');
+
+test(() => {
+  scroller.scrollTo(0, 0);
+  assert_equals(scroller.scrollLeft, 0);
+  assert_equals(scroller.scrollTop, 0);
+  scroller.scrollTo(300, 300);
+  assert_equals(scroller.scrollLeft, 800);
+  assert_equals(scroller.scrollTop, 800);
+}, 'snap to snap area inflated by scroll-margin, even when the non-visible ones are closer');
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-align-001-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-align-001-iframe.html
new file mode 100644
index 0000000..20922ea
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-align-001-iframe.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<title>iframe for #target and snap position with snapping off</title>
+<style type='text/css'>
+  html, body {
+    margin: 0; padding: 0;
+  }
+  html {
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x fixed;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  div {
+    height: 1em;
+  }
+  html    { scroll-padding:   .5em 0 0; } /* set up a snap position      */
+  #target { scroll-margin:    .5em 0 0;
+            scroll-snap-align:  center; }
+  #stripe { background: green;          } /* color part of the snap area */
+  .fail   { color: red;                 } /* make failing more obvious   */
+  }
+</style>
+
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div id="stripe"></div>
+<div id="target"></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-margin-001-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-margin-001-iframe.html
new file mode 100644
index 0000000..8eb5b9c8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-margin-001-iframe.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>iframe for #target and scroll-margin with snapping off (y</title>
+<style type='text/css'>
+  html, body {
+    margin: 0; padding: 0;
+  }
+  html {
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x fixed;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  div {
+    height: 1em;
+  }
+  #target { scroll-margin: 2em 0 1em; } /* snap area is exact fit for snapport */
+  #stripe { background: green;        } /* color part of the snap area         */
+  .fail   { color: red;               } /* make failing more obvious           */
+  }
+</style>
+
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div id="stripe"></div>
+<div id="target"></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-padding-001-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-padding-001-iframe.html
new file mode 100644
index 0000000..b9467e4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-padding-001-iframe.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>iframe for #target and scroll-snap-padding with snapping off (y</title>
+<style type='text/css'>
+  html, body {
+    margin: 0; padding: 0;
+  }
+  html {
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x fixed;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+  }
+  div {
+    height: 1em;
+  }
+  html    { scroll-padding: 2em 0 1em; } /* snap area is exact fit for snapport  */
+  #stripe { background: green;         } /* color part of the snap area          */
+  .fail   { color: red;                } /* make failing more obvious            */
+  }
+</style>
+
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div id="stripe"></div>
+<div id="target"></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div></div>
+<div></div>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-snap-001-iframe.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-snap-001-iframe.html
new file mode 100644
index 0000000..1a598fa7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/support/scroll-target-snap-001-iframe.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>iframe for #target and snap position with snapping on</title>
+<style type='text/css'>
+  html, body {
+    margin: 0; padding: 0;
+  }
+  html {
+    /* to make failing more obvious */
+    background: 0 1em / 100% 1em linear-gradient(red, red) repeat-x fixed;
+    /* avoid anti-aliasing issues */
+    font: 20px/1 sans-serif;
+    scrollbar-width: none;
+
+    /* turn on snapping */
+    scroll-snap-type: block;
+  }
+  div {
+    height: 1em;
+  }
+  #target { scroll-margin:     1em 0 0;
+            scroll-snap-align:  center; } /* set up a snap position      */
+  #stripe { background: green;          } /* color part of the snap area */
+  .fail   { color: red;                 } /* make failing more obvious   */
+
+  /* Try to foil the UA */
+  .foilup { margin-bottom: -1em; scroll-snap-align: start; }
+  .foildn { margin-top:    -1em; scroll-snap-align: end;   }
+</style>
+
+<div></div>
+<div></div>
+<div></div>
+<div></div>
+<div class="foilup"></div>
+<div class="fail">FAIL</div>
+<div></div>
+<div id="stripe"></div>
+<div class="foilup"></div>
+<div id="target"></div>
+<div class="foildn"></div>
+<div></div>
+<div class="fail">FAIL</div>
+<div class="foildn"></div>
+<div></div>
+<div class="foildn"></div>
+<div></div>
+<div></div>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/unreachable-snap-positions.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/unreachable-snap-positions.html
new file mode 100644
index 0000000..ca4f603
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/unreachable-snap-positions.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.csswg.org/css-scroll-snap-1/#unreachable" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+div {
+  position: absolute;
+  margin: 0px;
+}
+#scroller {
+  height: 500px;
+  width: 500px;
+  overflow: hidden;
+  scroll-snap-type: both mandatory;
+}
+#unreachable {
+  width: 300px;
+  height: 300px;
+  top: -100px;
+  left: -100px;
+  background-color: blue;
+  scroll-snap-align: start;
+}
+#reachable {
+  width: 300px;
+  height: 300px;
+  top: 400px;
+  left: 400px;
+  background-color: blue;
+  scroll-snap-align: start;
+}
+</style>
+
+<div id="scroller">
+  <div style="width: 2000px; height: 2000px;"></div>
+  <div id="unreachable"></div>
+  <div id="reachable"></div>
+</div>
+
+<script>
+test(() => {
+  // Firstly move to the reachable snap position.
+  scroller.scrollTo(400, 400);
+  assert_equals(scroller.scrollLeft, 400);
+  assert_equals(scroller.scrollTop, 400);
+
+  // Then move to a position between the unreachable snap position and the
+  // reachable position but closer to the unreachable one.
+  scroller.scrollTo(100, 100);
+  assert_equals(scroller.scrollLeft, 0);
+  assert_equals(scroller.scrollTop, 0);
+}, "Snaps to the positions defined by the element as much as possible");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html
new file mode 100644
index 0000000..160914c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  img {
+    border: 1px solid black;
+    height: 30px;
+    width: 60px;
+  }
+</style>
+<img src="/css/support/60x60-green.png">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html
new file mode 100644
index 0000000..7dcf110
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-001.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their min-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-001-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 30px;
+    width: 30px;
+    min-width: min-content;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html
new file mode 100644
index 0000000..5447092
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-002.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their min-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-001-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 30px;
+    width: 30px;
+    min-width: max-content;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html
new file mode 100644
index 0000000..56b71a0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  img {
+    border: 1px solid black;
+    height: 80px;
+    width: 60px;
+  }
+</style>
+<img src="/css/support/60x60-green.png">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html
new file mode 100644
index 0000000..8da6b4c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-003.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their max-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-003-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 80px;
+    width: 80px;
+    max-width: min-content;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html
new file mode 100644
index 0000000..b9955af
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-004.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their max-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-003-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 80px;
+    width: 80px;
+    max-width: max-content;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html
new file mode 100644
index 0000000..9964f07
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  img {
+    border: 1px solid black;
+    height: 60px;
+    width: 30px;
+  }
+</style>
+<img src="/css/support/60x60-green.png">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html
new file mode 100644
index 0000000..86a2a72f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-005.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their min-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-005-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 30px;
+    width: 30px;
+    min-height: min-content;
+    writing-mode: vertical-lr;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html
new file mode 100644
index 0000000..ddb8924
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-006.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their min-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-005-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 30px;
+    width: 30px;
+    min-height: max-content;
+    writing-mode: vertical-lr;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html
new file mode 100644
index 0000000..8b9da1c9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007-ref.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>CSS Test Reference</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<style>
+  img {
+    border: 1px solid black;
+    width: 80px;
+    height: 60px;
+  }
+</style>
+<img src="/css/support/60x60-green.png">
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html
new file mode 100644
index 0000000..150052f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-007.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their max-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-007-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 80px;
+    width: 80px;
+    max-height: min-content;
+    writing-mode: vertical-lr;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html
new file mode 100644
index 0000000..259e2f3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-sizing/image-min-max-content-intrinsic-size-change-008.html
@@ -0,0 +1,24 @@
+<!doctype html>
+<html class="reftest-wait">
+<title>CSS Test: Image size is updated properly when intrinsic size changes, even with a fixed width and height, if their max-size depends on their intrinsic size</title>
+<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez">
+<link rel="author" href="https://mozilla.org" title="Mozilla">
+<link rel="help" href="https://drafts.csswg.org/css-sizing/#sizing-values">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1546739">
+<link rel="match" href="image-min-max-content-intrinsic-size-change-007-ref.html">
+<style>
+  img {
+    border: 1px solid black;
+    height: 80px;
+    width: 80px;
+    max-height: max-content;
+    writing-mode: vertical-lr;
+  }
+</style>
+<img>
+<script>
+  let img = document.querySelector("img");
+  img.offsetWidth; // Ensure the image is laid out.
+  img.onload = () => document.documentElement.className = "";
+  img.src = "/css/support/60x60-green.png";
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-015.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-015.html
new file mode 100644
index 0000000..aaa1c2b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-015.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>CSS Text — line breaking at element boundaries</title>
+<meta name=assert content="An empty inline element should not introduce a line-break opportunity">
+<link rel=help href="https://www.w3.org/TR/css-text-3/#line-break-details">
+<link rel=match href="reference/line-breaking-015-ref.html">
+<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
+<style>
+.test { margin: 1em 0; width: 0; line-height: 2; }
+</style>
+<body>
+The word "unbroken" below should <b>not</b> be broken:
+<div class="test">un<span></span>bro<b></b>ken</div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-016.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-016.html
new file mode 100644
index 0000000..c600504
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-016.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>CSS Text — line breaking at element boundaries</title>
+<meta name=assert content="An out-of-flow element should not introduce a line-break opportunity">
+<link rel=help href="https://www.w3.org/TR/css-text-3/#line-break-details">
+<link rel=match href="reference/line-breaking-016-ref.html">
+<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
+<style>
+.test { margin: 1em 0; width: 0; }
+.oof { position: absolute; left: 6em; }
+</style>
+<body>
+The word "unbroken" below should <b>not</b> be broken:
+<div class="test">un<span class="oof"></span>bro<b class="oof">absolute</b>ken</div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-017.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-017.html
new file mode 100644
index 0000000..36af931b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/line-breaking-017.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>CSS Text — line breaking at element boundaries</title>
+<meta name=assert content="An out-of-flow element should not introduce a line-break opportunity">
+<link rel=help href="https://www.w3.org/TR/css-text-3/#line-break-details">
+<link rel=match href="reference/line-breaking-017-ref.html">
+<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
+<style>
+.test { margin: 1em 0; width: 0; }
+.oof { float: left; }
+</style>
+<body>
+The word "unbroken" below should <b>not</b> be broken:
+<div class="test">un<span class="oof"></span>bro<b class="oof">float</b>ken</div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-015-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-015-ref.html
new file mode 100644
index 0000000..2837ce0c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-015-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>CSS Text — reference file for line-breaking test</title>
+<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
+<style>
+.test { margin: 1em 0; line-height: 2; }
+</style>
+<body>
+The word "unbroken" below should <b>not</b> be broken:
+<div class="test">unbroken</div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-016-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-016-ref.html
new file mode 100644
index 0000000..e4d30e0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-016-ref.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>CSS Text — reference file for line-breaking test</title>
+<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
+<style>
+.test { margin: 1em 0; }
+.oof { position: absolute; left: 6em; }
+</style>
+<body>
+The word "unbroken" below should <b>not</b> be broken:
+<div class="test">unbroken<b class="oof">absolute</b></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-017-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-017-ref.html
new file mode 100644
index 0000000..6f94b12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-breaking/reference/line-breaking-017-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+<meta charset="utf-8">
+<title>CSS Text — reference file for line-breaking test</title>
+<link rel=author title="Jonathan Kew" href="jkew@mozilla.com">
+<style>
+.test { margin: 1em 0; }
+</style>
+<body>
+The word "unbroken" below should <b>not</b> be broken:
+<div class="test">unbroken<br><b>float</b></div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/text-transform-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/text-transform-valid.html
index a40166c3..fead45c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-text/parsing/text-transform-valid.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/parsing/text-transform-valid.html
@@ -22,16 +22,20 @@
 test_valid_value("text-transform", "capitalize full-width");
 test_valid_value("text-transform", "uppercase full-size-kana");
 test_valid_value("text-transform", "full-width full-size-kana");
-test_valid_value("text-transform", "full-width lowercase");
-test_valid_value("text-transform", "full-size-kana capitalize");
-test_valid_value("text-transform", "full-size-kana full-width");
+
+// serialization canonicalizes the order of values: https://drafts.csswg.org/cssom/#serialize-a-css-value
+test_valid_value("text-transform", "full-width lowercase", "lowercase full-width");
+test_valid_value("text-transform", "full-size-kana capitalize", "capitalize full-size-kana");
+test_valid_value("text-transform", "full-size-kana full-width", "full-width full-size-kana");
 
 test_valid_value("text-transform", "capitalize full-width full-size-kana");
-test_valid_value("text-transform", "full-width full-size-kana uppercase");
-test_valid_value("text-transform", "full-size-kana lowercase full-width");
-test_valid_value("text-transform", "lowercase full-size-kana full-width");
-test_valid_value("text-transform", "full-width uppercase full-size-kana");
-test_valid_value("text-transform", "full-size-kana full-width capitalize");
+
+// serialization canonicalizes the order of values
+test_valid_value("text-transform", "full-width full-size-kana uppercase", "uppercase full-width full-size-kana");
+test_valid_value("text-transform", "full-size-kana lowercase full-width", "lowercase full-width full-size-kana");
+test_valid_value("text-transform", "lowercase full-size-kana full-width", "lowercase full-width full-size-kana");
+test_valid_value("text-transform", "full-width uppercase full-size-kana", "uppercase full-width full-size-kana");
+test_valid_value("text-transform", "full-size-kana full-width capitalize", "capitalize full-width full-size-kana");
 </script>
 </body>
 </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-multiple-001-ref.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-multiple-001-ref.html
new file mode 100644
index 0000000..694ae878
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/reference/text-transform-multiple-001-ref.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<html lang="ja">
+<meta charset=utf-8>
+<title>text-transform with multiple values</title>
+<body style="font-family:serif">
+<h4>Each pair of lines should look identical:</h4>
+<hr>
+<div>HELLO TRANSFORMED WORLD</div>
+<div>HELLO TRANSFORMED WORLD</div>
+<hr>
+<div>hello transformed world</div>
+<div>hello transformed world</div>
+<hr>
+<div>HELLO Transformed World</div>
+<div>HELLO Transformed World</div>
+<hr>
+<div>KATAKANA: アイウエオカクケシスツトヌ</div>
+<div>KATAKANA: アイウエオカクケシスツトヌ</div>
+<hr>
+<div>hiragana: あいうえおかけつやゆよわ</div>
+<div>hiragana: あいうえおかけつやゆよわ</div>
+<hr>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-multiple-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-multiple-001.html
new file mode 100644
index 0000000..946aa9c9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-text/text-transform/text-transform-multiple-001.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html lang="ja">
+<meta charset=utf-8>
+<title>text-transform with multiple values</title>
+<link rel="author" title="Jonathan Kew" href="mailto:jkew@mozilla.com">
+<link rel=match href="reference/text-transform-multiple-001-ref.html">
+<link rel="help" href="https://drafts.csswg.org/css-text-3/#text-transform-property">
+<meta name="assert" content="case transforms can be combined with full-width and/or full-size-kana transforms">
+<body style="font-family:serif">
+<h4>Each pair of lines should look identical:</h4>
+<hr>
+<div style="text-transform:uppercase full-width">HELLO Transformed world</div>
+<div>HELLO TRANSFORMED WORLD</div>
+<hr>
+<div style="text-transform:lowercase full-width">HELLO Transformed world</div>
+<div>hello transformed world</div>
+<hr>
+<div style="text-transform:capitalize full-width">HELLO Transformed world</div>
+<div>HELLO Transformed World</div>
+<hr>
+<div style="text-transform:uppercase full-size-kana">Katakana: ァィゥェォヵㇰヶㇱㇲッㇳㇴ</div>
+<div>KATAKANA: アイウエオカクケシスツトヌ</div>
+<hr>
+<div style="text-transform:full-width full-size-kana lowercase">Hiragana: ぁぃぅぇぉゕゖっゃゅょゎ</div>
+<div>hiragana: あいうえおかけつやゆよわ</div>
+<hr>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt
index 12d92cd8..d859a1c 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS getAnimations for non-animated content
 PASS getAnimations for CSS Transitions
-FAIL CSS Transitions targetting (pseudo-)elements should have correct order after sorting assert_equals: The animation targeting the ::before element comes second expected (string) "::before" but got (undefined) undefined
+FAIL CSS Transitions targetting (pseudo-)elements should have correct order after sorting assert_equals: Transition #2 has expected target expected (object) Element node <div style="display: list-item; left: 100px; transition: ... but got (undefined) undefined
 PASS Transitions are not returned after they have finished
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative.html
index bffc05f..98b91e0 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/Document-getAnimations.tentative.html
@@ -36,47 +36,88 @@
 }, 'getAnimations for CSS Transitions');
 
 test(t => {
-  addStyle(t, { '.init::after': 'content: ""; width: 0px; ' +
-                                'transition: all 100s;',
-                '.init::before': 'content: ""; width: 0px; ' +
-                                 'transition: all 10s;',
-                '.change::after': 'width: 100px;',
-                '.change::before': 'width: 100px;' });
-  // create two divs with these arrangement:
+  // Create two divs with the following arrangement:
+  //
   //       parent
+  //    (::marker,)
   //     ::before,
   //     ::after
   //        |
   //       child
-  const parent = addDiv(t);
+
+  addStyle(t, {
+    '.init::after': 'content: ""; width: 0px; transition: all 100s;',
+    '.init::before': 'content: ""; width: 0px; transition: all 100s;',
+    '.change::after': 'width: 100px;',
+    '.change::before': 'width: 100px;',
+  });
+
+  const supportsMarkerPseudos = CSS.supports('selector(::marker)');
+  if (supportsMarkerPseudos) {
+    addStyle(t, {
+      '.init::marker': 'content: ""; color: red; transition: all 100s;',
+      '.change::marker': 'color: green;',
+    });
+  }
+
+  const parent = addDiv(t, { 'style': 'display: list-item' });
   const child = addDiv(t);
   parent.appendChild(child);
 
   parent.style.left = '0px';
-  parent.style.transition = 'left 10s';
+  parent.style.transition = 'left 100s';
   parent.classList.add('init');
   child.style.left = '0px';
-  child.style.transition = 'left 10s';
+  child.style.transition = 'left 100s';
   getComputedStyle(parent).left;
 
   parent.style.left = '100px';
   parent.classList.add('change');
   child.style.left = '100px';
 
-  const anims = document.getAnimations();
-  assert_equals(anims.length, 4,
-                'CSS transition on both pseudo-elements and elements ' +
-                'are returned');
-  assert_equals(anims[0].effect.target, parent,
-                'The animation targeting the parent element comes first');
-  assert_equals(anims[1].effect.target.type, '::before',
-                'The animation targeting the ::before element comes second');
-  assert_equals(anims[2].effect.target.type, '::after',
-                'The animation targeting the ::after element comes third');
-  assert_equals(anims[3].effect.target, child,
-                'The animation targeting the child element comes last');
-}, 'CSS Transitions targetting (pseudo-)elements should have correct order ' +
-   'after sorting');
+  const expectedTransitions = [
+    [parent, undefined],
+    [parent, '::marker'],
+    [parent, '::before'],
+    [parent, '::after'],
+    [child, undefined],
+  ];
+  if (!supportsMarkerPseudos) {
+    expectedTransitions.splice(1, 1);
+  }
+
+  const transitions = document.getAnimations();
+  assert_equals(
+    transitions.length,
+    expectedTransitions.length,
+    'CSS transition on both pseudo-elements and elements are returned'
+  );
+
+  for (const [index, expected] of expectedTransitions.entries()) {
+    const [element, pseudo] = expected;
+    const actual = transitions[index];
+
+    if (pseudo) {
+      assert_equals(
+        actual.effect.target.element,
+        element,
+        `Transition #${index + 1} has expected target`
+      );
+      assert_equals(
+        actual.effect.target.type,
+        pseudo,
+        `Transition #${index + 1} has expected pseudo type`
+      );
+    } else {
+      assert_equals(
+        actual.effect.target,
+        element,
+        `Transition #${index + 1} has expected target`
+      );
+    }
+  }
+}, 'CSS Transitions targetting (pseudo-)elements should have correct order '
+   + 'after sorting');
 
 promise_test(async t => {
   const div = addDiv(t, { style: 'left: 0px; transition: all 50ms' });
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/detached-container-001.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/detached-container-001.html
deleted file mode 100644
index 545324b0..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/detached-container-001.html
+++ /dev/null
@@ -1,131 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8">
-        <title>CSS Transitions Test: Not Transitioning within detached element</title>
-        <meta name="assert" content="Test checks that transitions are NOT run within detached elements">
-        <link rel="help" title="2. Transitions" href="http://www.w3.org/TR/css3-transitions/#transitions">
-        <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
-        <meta name="flags" content="dom">
-
-        <script src="/resources/testharness.js" type="text/javascript"></script>
-        <script src="/resources/testharnessreport.js" type="text/javascript"></script>
-
-        <script src="./support/vendorPrefix.js" type="text/javascript"></script>
-        <script src="./support/helper.js" type="text/javascript"></script>
-        <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
-        <script src="./support/generalParallelTest.js" type="text/javascript"></script>
-        <script src="./support/properties.js" type="text/javascript"></script>
-
-        <style type="text/css">
-            #offscreen {
-                position: absolute;
-                top: -100000px;
-                left: -100000px;
-                width: 100000px;
-                height: 100000px;
-            }
-        </style>
-    </head>
-    <body>
-        <!-- required by testharnessreport.js -->
-        <div id="log"></div>
-        <!-- elements used for testing -->
-        <div id="fixture" class="fixture">
-            <div class="container">
-                <div class="transition">Text sample</div>
-            </div>
-        </div>
-        <div id="off-screen"></div>
-
-        <!--
-            SEE ./support/README.md for an abstract explanation of the test procedure
-            http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-        -->
-
-        <script>
-
-            // this test takes its time, give it a minute to run
-            var timeout = 60000;
-            setup({timeout: timeout});
-
-            var tests = [
-                {
-                    name: "transition within detached container",
-                    property: 'background-color',
-                    flags: {},
-                    from: {'background-color': 'red'},
-                    to: {'background-color': 'green'}
-                }
-            ];
-
-            // general transition-duration
-            var duration = '0.5s';
-
-            runParallelAsyncHarness({
-                // array of test data
-                tests: tests,
-                // the number of tests to run in parallel
-                testsPerSlice: 1,
-                // milliseconds to wait before calling teardown and ending test
-                duration: parseFloat(duration) * 1000,
-                // prepare individual test
-                setup: function(data, options) {
-                    var styles = {
-                        '.fixture': {},
-
-                        '.container': data.parentStyle,
-                        '.container.to': {},
-                        '.container.how': {},
-
-                        '.transition': data.from,
-                        '.transition.to' : data.to,
-                        '.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
-                    };
-
-                    generalParallelTest.setup(data, options);
-                    generalParallelTest.addStyles(data, options, styles);
-                },
-                // cleanup after individual test
-                teardown: generalParallelTest.teardown,
-                // invoked prior to running a slice of tests
-                sliceStart: generalParallelTest.sliceStart,
-                // invoked after running a slice of tests
-                sliceDone: generalParallelTest.sliceDone,
-                // test cases, make them as granular as possible
-                cases: {
-                    // test property values while transitioning
-                    // values.start kicks off a transition
-                    'values': {
-                        // run actual test, assertions can be used here!
-                        start: function(test, data, options) {
-                            // identify initial and target values
-                            generalParallelTest.getStyle(data);
-                            // make sure values differ, if they don't, the property could most likely not be parsed
-                            assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
-                            // detach transitioning elements
-                            data.fixture.parentNode.removeChild(data.fixture);
-                            // kick off the transition
-                            generalParallelTest.startTransition(data);
-                        },
-                        done: function(test, data, options) {
-                            // make sure there were no intermediate values
-                            assert_equals(data.transition.values.length, 2, "no intermediate values");
-                        }
-                    },
-                    // test TransitionEnd events
-                    'events': {
-                        done: function(test, data, options) {
-                            // make sure there were no events on parent
-                            test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
-                            // make sure we got the event for the tested property only
-                            test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', ""));
-                        }
-                    }
-                },
-                // called once all tests are done
-                done: generalParallelTest.done
-            });
-        </script>
-    </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/disconnected-element-001.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/disconnected-element-001.html
new file mode 100644
index 0000000..b883ce8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/disconnected-element-001.html
@@ -0,0 +1,203 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for a disconnected element</title>
+<meta name="assert" content="If an element is not in the document during that
+style change event or was not in the document during the previous style change
+event, then transitions are not started for that element in that style change
+event.">
+<meta name="assert" content="If an element is no longer in the document,
+implementations must cancel any running transitions on it and remove transitions
+on it from the completed transitions.">
+<link rel="help" title="Starting transitions"
+  href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+  // Create element but do not attach it to the document
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+
+  // Resolve before-change style
+  getComputedStyle(div).backgroundColor;
+
+  // Set up after-change style
+  div.style.backgroundColor = 'green';
+
+  assert_equals(
+    getComputedStyle(div).backgroundColor,
+    'rgb(255, 0, 0)',
+    'No transition should run'
+  );
+
+  // Wait a frame just to be sure the UA does not start the transition on the
+  // next frame.
+  await waitForFrame();
+
+  assert_equals(
+    getComputedStyle(div).backgroundColor,
+    'rgb(255, 0, 0)',
+    'No transition should run even after waiting a frame'
+  );
+}, 'Transitions do not run on an element not in the document');
+
+test(t => {
+  // Create element but do not attach it to the document
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+
+  // Resolve before-change style
+  getComputedStyle(div).backgroundColor;
+
+  // Add to document
+  document.documentElement.append(div);
+
+  // Set up after-change style
+  div.style.backgroundColor = 'green';
+
+  assert_equals(
+    getComputedStyle(div).backgroundColor,
+    'rgb(0, 128, 0)',
+    'No transition should run'
+  );
+}, 'Transitions do not run for an element newly added to the document');
+
+promise_test(async t => {
+  // Create element and attach it to the document
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+  document.documentElement.append(div);
+
+  // Attach event listeners
+  div.addEventListener('transitionrun', t.step_func(() => {
+    assert_unreached('transitionrun event should not be fired');
+  }));
+
+  // Resolve before-change style
+  getComputedStyle(div).backgroundColor;
+
+  // Set up after-change style
+  div.style.backgroundColor = 'green';
+
+  // But remove the document before the next style change event
+  div.remove();
+
+  // There should be no events received for the triggered transition.
+  //
+  // (We can't verify the presence/absence of transitions by querying
+  // getComputedStyle for this case because it will return an empty string.)
+  await waitForFrame();
+  await waitForFrame();
+}, 'Transitions do not run for an element newly removed from the document');
+
+promise_test(async t => {
+  // Create element and attach it to the document
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+  document.documentElement.append(div);
+
+  // Attach event listeners
+  const eventWatcher = new EventWatcher(t, div, [
+    'transitionrun',
+    'transitioncancel',
+  ]);
+
+  // Trigger transition
+  getComputedStyle(div).backgroundColor;
+  div.style.backgroundColor = 'green';
+  getComputedStyle(div).backgroundColor;
+
+  await eventWatcher.wait_for('transitionrun');
+
+  // Remove the element from the document
+  div.remove();
+
+  await eventWatcher.wait_for('transitioncancel');
+}, 'Transitions are canceled when an element is removed from the document');
+
+promise_test(async t => {
+  // Create a container element. We'll need this later.
+  const container = addDiv(t);
+  document.documentElement.append(container);
+
+  // Create element and attach it to the document
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+  document.documentElement.append(div);
+
+  // Attach event listeners
+  const eventWatcher = new EventWatcher(t, div, [
+    'transitionrun',
+    'transitioncancel',
+  ]);
+
+  // Trigger transition
+  getComputedStyle(div).backgroundColor;
+  div.style.backgroundColor = 'green';
+  getComputedStyle(div).backgroundColor;
+
+  await eventWatcher.wait_for('transitionrun');
+
+  // Re-parent element
+  container.append(div);
+
+  await eventWatcher.wait_for('transitioncancel');
+  assert_equals(
+    getComputedStyle(div).backgroundColor,
+    'rgb(0, 128, 0)',
+    'There should be no transition after re-parenting'
+  );
+}, 'Transitions are canceled when an element is re-parented');
+
+promise_test(async t => {
+  // Create a container element. We'll need this later.
+  const container = addDiv(t);
+  document.documentElement.append(container);
+
+  // Create element and attach it to the document
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+  document.documentElement.append(div);
+
+  // Attach event listeners
+  const eventWatcher = new EventWatcher(t, div, [
+    'transitionrun',
+    'transitioncancel',
+  ]);
+
+  // Trigger transition
+  getComputedStyle(div).backgroundColor;
+  div.style.backgroundColor = 'green';
+  getComputedStyle(div).backgroundColor;
+
+  await eventWatcher.wait_for('transitionrun');
+
+  // Re-parent element to same container
+  document.documentElement.append(div);
+
+  await eventWatcher.wait_for('transitioncancel');
+  assert_equals(
+    getComputedStyle(div).backgroundColor,
+    'rgb(0, 128, 0)',
+    'There should be no transition after re-parenting'
+  );
+}, 'Transitions are canceled when an element is re-parented to the same node');
+</script>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/hidden-container-001.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/hidden-container-001.html
deleted file mode 100644
index 567ae61..0000000
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/hidden-container-001.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta charset="utf-8">
-        <title>CSS Transitions Test: Not Transitioning within hidden element</title>
-        <meta name="assert" content="Test checks that transitions are NOT run within hidden elements">
-        <link rel="help" title="2. Transitions" href="http://www.w3.org/TR/css3-transitions/#transitions">
-        <link rel="author" title="Rodney Rehm" href="http://rodneyrehm.de/en/">
-        <meta name="flags" content="dom">
-
-        <script src="/resources/testharness.js" type="text/javascript"></script>
-        <script src="/resources/testharnessreport.js" type="text/javascript"></script>
-
-        <script src="./support/vendorPrefix.js" type="text/javascript"></script>
-        <script src="./support/helper.js" type="text/javascript"></script>
-        <script src="./support/runParallelAsyncHarness.js" type="text/javascript"></script>
-        <script src="./support/generalParallelTest.js" type="text/javascript"></script>
-        <script src="./support/properties.js" type="text/javascript"></script>
-
-        <style type="text/css">
-            #offscreen {
-                display: none;
-            }
-        </style>
-    </head>
-    <body>
-        <!-- required by testharnessreport.js -->
-        <div id="log"></div>
-        <!-- elements used for testing -->
-        <div id="fixture" class="fixture">
-            <div class="container">
-                <div class="transition">Text sample</div>
-            </div>
-        </div>
-        <div id="offscreen"></div>
-
-        <!--
-            SEE ./support/README.md for an abstract explanation of the test procedure
-            http://test.csswg.org/source/contributors/rodneyrehm/submitted/css3-transitions/README.md
-        -->
-
-        <script>
-
-            // this test takes its time, give it a minute to run
-            var timeout = 60000;
-            setup({timeout: timeout});
-
-            var tests = [
-                {
-                    name: "transition within display:none",
-                    property: 'background-color',
-                    flags: {},
-                    from: {'background-color': 'red'},
-                    to: {'background-color': 'green'}
-                }
-            ];
-
-            // general transition-duration
-            var duration = '0.5s';
-
-            runParallelAsyncHarness({
-                // array of test data
-                tests: tests,
-                // the number of tests to run in parallel
-                testsPerSlice: 1,
-                // milliseconds to wait before calling teardown and ending test
-                duration: parseFloat(duration) * 1000,
-                // prepare individual test
-                setup: function(data, options) {
-                    var styles = {
-                        '.fixture': {},
-
-                        '.container': data.parentStyle,
-                        '.container.to': {},
-                        '.container.how': {},
-
-                        '.transition': data.from,
-                        '.transition.to' : data.to,
-                        '.transition.how' : {transition: 'all ' + duration + ' linear 0s'}
-                    };
-
-                    generalParallelTest.setup(data, options);
-                    generalParallelTest.addStyles(data, options, styles);
-                },
-                // cleanup after individual test
-                teardown: generalParallelTest.teardown,
-                // invoked prior to running a slice of tests
-                sliceStart: generalParallelTest.sliceStart,
-                // invoked after running a slice of tests
-                sliceDone: generalParallelTest.sliceDone,
-                // test cases, make them as granular as possible
-                cases: {
-                    // test property values while transitioning
-                    // values.start kicks off a transition
-                    'values': {
-                        // run actual test, assertions can be used here!
-                        start: function(test, data, options) {
-                            // identify initial and target values
-                            generalParallelTest.getStyle(data);
-                            // make sure values differ, if they don't, the property could most likely not be parsed
-                            assert_not_equals(data.transition.from, data.transition.to, "initial and target values may not match");
-                            // kick off the transition
-                            generalParallelTest.startTransition(data);
-                        },
-                        done: function(test, data, options) {
-                            // make sure there were no intermediate values
-                            assert_equals(data.transition.values.length, 2, "no intermediate values");
-                        }
-                    },
-                    // test TransitionEnd events
-                    'events': {
-                        done: function(test, data, options) {
-                            // make sure there were no events on parent
-                            test.step(generalParallelTest.assertExpectedEventsFunc(data, 'container', ""));
-                            // make sure we got the event for the tested property only
-                            test.step(generalParallelTest.assertExpectedEventsFunc(data, 'transition', ""));
-                        }
-                    }
-                },
-                // called once all tests are done
-                done: generalParallelTest.done
-            });
-        </script>
-    </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-001-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-001-expected.txt
new file mode 100644
index 0000000..81c73cb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-001-expected.txt
@@ -0,0 +1,7 @@
+This is a testharness.js-based test.
+PASS Transitions do not run on an element not being rendered
+FAIL Transitions do not run for an element newly rendered assert_equals: No transition should run expected "rgb(0, 128, 0)" but got "rgb(255, 0, 0)"
+PASS Transitions do not run for an element newly made not rendered
+PASS Transitions are canceled when an element is no longer rendered
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-001.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-001.html
new file mode 100644
index 0000000..10419b9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-001.html
@@ -0,0 +1,127 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for an element that is not being rendered</title>
+<link rel="help" title="Starting transitions"
+  href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+promise_test(async t => {
+  // Create element that is not rendered
+  const div = addDiv(t, {
+    style:
+      'transition: background-color 100s;' +
+      'background-color: red;' +
+      'display: none',
+  });
+
+  // Attach event listeners
+  div.addEventListener(
+    'transitionrun',
+    t.step_func(() => {
+      assert_unreached('transitionrun event should not be fired');
+    })
+  );
+
+  // Resolve before-change style
+  getComputedStyle(div).backgroundColor;
+
+  // Set up and resolve after-change style
+  div.style.backgroundColor = 'green';
+  getComputedStyle(div).backgroundColor;
+
+  // There should be no events received for the triggered transition.
+  await waitForFrame();
+  await waitForFrame();
+}, 'Transitions do not run on an element not being rendered');
+
+test(t => {
+  // Create element that is not rendered
+  const div = addDiv(t, {
+    style:
+      'transition: background-color 100s;' +
+      'background-color: red;' +
+      'display: none',
+  });
+
+  // Resolve before-change style
+  getComputedStyle(div).backgroundColor;
+
+  // Make it rendered
+  div.style.display = 'block';
+
+  // Set up and resolve after-change style
+  div.style.backgroundColor = 'green';
+  getComputedStyle(div).backgroundColor;
+
+  // We should have jumped immediately to the after-change style rather than
+  // transitioning to it.
+  assert_equals(
+    getComputedStyle(div).backgroundColor,
+    'rgb(0, 128, 0)',
+    'No transition should run'
+  );
+}, 'Transitions do not run for an element newly rendered');
+
+promise_test(async t => {
+  // Create element
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+
+  // Attach event listeners
+  div.addEventListener('transitionrun', t.step_func(() => {
+    assert_unreached('transitionrun event should not be fired');
+  }));
+
+  // Resolve before-change style
+  getComputedStyle(div).backgroundColor;
+
+  // Set up after-change style
+  div.style.backgroundColor = 'green';
+
+  // But make the element non-rendered
+  div.style.display = 'none';
+
+  // There should be no events received for the triggered transition.
+  await waitForFrame();
+  await waitForFrame();
+}, 'Transitions do not run for an element newly made not rendered');
+
+promise_test(async t => {
+  // Create element
+  const div = addDiv(t, {
+    style: 'transition: background-color 100s; background-color: red',
+  });
+
+  // Attach event listeners
+  const eventWatcher = new EventWatcher(t, div, [
+    'transitionrun',
+    'transitioncancel',
+  ]);
+
+  // Trigger transition
+  getComputedStyle(div).backgroundColor;
+  div.style.backgroundColor = 'green';
+  getComputedStyle(div).backgroundColor;
+
+  await eventWatcher.wait_for('transitionrun');
+
+  // Make the element no longer rendered
+  div.style.display = 'none';
+
+  await eventWatcher.wait_for('transitioncancel');
+}, 'Transitions are canceled when an element is no longer rendered');
+</script>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-002.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-002.html
new file mode 100644
index 0000000..f26a048
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/non-rendered-element-002.html
@@ -0,0 +1,90 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<title>CSS Transitions Test: Transitions do not run for a pseudo-element that is not being rendered</title>
+<link rel="help" title="Starting transitions"
+  href="https://drafts.csswg.org/css-transitions/#starting">
+
+<script src="/resources/testharness.js" type="text/javascript"></script>
+<script src="/resources/testharnessreport.js" type="text/javascript"></script>
+<script src="./support/helper.js" type="text/javascript"></script>
+
+</head>
+<body>
+<div id="log"></div>
+
+<script>
+
+promise_test(async t => {
+  for (const pseudoType of ['before', 'after']) {
+    const style = addStyle(t, {
+      [`.init::${pseudoType}`]: 'content: ""; width: 0px; transition: width 100s;',
+      [`.change::${pseudoType}`]: 'width: 100px;',
+      [`.cancel::${pseudoType}`]: 'content: none',
+    });
+
+    // Create element (and pseudo-element) and attach event listeners
+    const div = addDiv(t);
+    div.classList.add('init');
+
+    const eventWatcher = new EventWatcher(t, div, [
+      'transitionrun',
+      'transitioncancel',
+    ]);
+
+    // Trigger transition
+    getComputedStyle(div).width;
+    div.classList.add('change');
+    getComputedStyle(div).width;
+
+    await eventWatcher.wait_for('transitionrun');
+
+    // Make the pseudo-element no longer rendered
+    div.classList.add('cancel');
+
+    await eventWatcher.wait_for('transitioncancel');
+
+    div.remove();
+    style.remove();
+  }
+}, 'Transitions on ::before/::after pseudo-elements are canceled when the'
+   + ' content property is cleared');
+
+promise_test(async t => {
+  if (!CSS.supports('selector(::marker)')) {
+    return;
+  }
+
+  addStyle(t, {
+    '.init::marker': 'content: ""; color: red; transition: color 100s;',
+    '.change::marker': 'color: green',
+  });
+
+  // Create element (and pseudo-element) and attach event listeners
+  const div = addDiv(t, { 'style': 'display: list-item' });
+  div.classList.add('init');
+
+  const eventWatcher = new EventWatcher(t, div, [
+    'transitionrun',
+    'transitioncancel',
+  ]);
+
+  // Trigger transition
+  getComputedStyle(div).color;
+  div.classList.add('change');
+  getComputedStyle(div).color;
+
+  await eventWatcher.wait_for('transitionrun');
+
+  // Make the parent element no longer display: list-item so that the pseudo
+  // element no longer renders
+  div.style.display = 'block';
+
+  await eventWatcher.wait_for('transitioncancel');
+}, 'Transitions on ::marker pseudo-elements are canceled when the'
+   + ' parent display type is no longer list-item');
+</script>
+
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/support/helper.js b/third_party/blink/web_tests/external/wpt/css/css-transitions/support/helper.js
index aa3efe8..d5fa61b1 100644
--- a/third_party/blink/web_tests/external/wpt/css/css-transitions/support/helper.js
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/support/helper.js
@@ -231,6 +231,7 @@
       extraStyle.remove();
     });
   }
+  return extraStyle;
 };
 
 /**
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/calc-rgb-percent-001.html b/third_party/blink/web_tests/external/wpt/css/css-values/calc-rgb-percent-001.html
new file mode 100644
index 0000000..1446c28d3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/calc-rgb-percent-001.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Values Test: computed value of rgb() with calc(percentage)</title>
+
+  <!--
+
+  Original code is from Yves Lafon
+
+  Re: [css3-values] percentage in calc() and attr()
+  https://lists.w3.org/Archives/Public/www-style/2016May/0028.html
+
+  -->
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-values-4/#calc-serialize">
+
+  <script src="/resources/testharness.js"></script>
+
+  <script src="/resources/testharnessreport.js"></script>
+
+  <style>
+  div#target
+    {
+      background-color: rgb(calc(5% + 15%), calc(40% / 2), calc(5% * 4));
+      height: 100px;
+    }
+  </style>
+
+  <div id="target"></div>
+
+  <script>
+  test(function()
+    {
+      assert_equals(getComputedStyle(document.getElementById("target")).backgroundColor, "rgb(51, 51, 51)");
+    }, "testing rgb(calc(5% + 15%), calc(40% / 2), calc(5% * 4))");
+  </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/getComputedStyle-border-radius-001.html b/third_party/blink/web_tests/external/wpt/css/css-values/getComputedStyle-border-radius-001.html
new file mode 100644
index 0000000..6f3ba3ac
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/getComputedStyle-border-radius-001.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Values Test: mixed units in calc() and computed border-radius longhand and shorthand values (complex)</title>
+
+  <!--
+
+  Original test is:
+
+https://chromium.googlesource.com/chromium/src/+/c825d655f6aaf73484f9d56e9012793f5b9668cc/third_party/WebKit/LayoutTests/css3/calc/getComputedStyle-border-radius.html
+
+
+  Bug 137688: getPropertyValue on computed style does not do shorthand properties
+  https://bugzilla.mozilla.org/show_bug.cgi?id=137688
+
+  -->
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-values-4/#calc-serialize">
+  <link rel="help" href="https://www.w3.org/TR/css-backgrounds-3/#the-border-radius">
+
+  <script src="/resources/testharness.js"></script>
+
+  <script src="/resources/testharnessreport.js"></script>
+
+  <style>
+  div#target
+    {
+      border: solid 2px;
+      border-top-left-radius: calc(10px + 25%) calc(20px + 25%);
+      border-top-right-radius: calc(1em + 25%);
+      border-bottom-right-radius: calc(25%);
+      border-bottom-left-radius: calc(25px);
+      font-size: 16px;  /* was 10px in original test */
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <div id="target"></div>
+
+  <script>
+  function startTesting()
+  {
+
+  var targetElement = document.getElementById("target");
+
+    function verifyComputedStyle(property_name, expected_value, description)
+    {
+
+    test(function()
+      {
+
+      assert_equals(getComputedStyle(targetElement)[property_name], expected_value);
+
+      }, description);
+    }
+
+ /* verifyComputedStyle(property_name, expected_value, description) */
+
+    verifyComputedStyle("border-top-left-radius", "calc(25% + 10px) calc(25% + 20px)", "testing border-top-left-radius: calc(10px + 25%) calc(20px + 25%)");
+
+    verifyComputedStyle("border-top-right-radius", "calc(25% + 16px)", "testing border-top-right-radius: calc(1em + 25%)");
+
+    verifyComputedStyle("border-bottom-right-radius", "25%", "testing border-bottom-right-radius: calc(25%)");
+
+    verifyComputedStyle("border-bottom-left-radius", "25px", "testing border-bottom-left-radius: calc(25px);");
+
+    verifyComputedStyle("border-radius", "calc(25% + 10px) calc(25% + 16px) 25% 25px / calc(25% + 20px) calc(25% + 16px) 25% 25px", "testing border-radius shorthand");
+
+  /*
+
+  The first value is the horizontal radius, the second the vertical radius.
+
+               horizontal radius                /                 vertical radius
+  |__________________________________________|     |__________________________________________|
+
+
+  The four values for each radii are given in the order top-left, top-right, bottom-right, bottom-left:
+
+
+  top-left top-right bottom-right bottom-left   /  top-left top-right bottom-right bottom-left
+
+  |__________________________________________|     |__________________________________________|
+
+               horizontal radius                /                 vertical radius
+
+  */
+
+  }
+
+  startTesting();
+
+  </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-values/getComputedStyle-border-radius-003.html b/third_party/blink/web_tests/external/wpt/css/css-values/getComputedStyle-border-radius-003.html
new file mode 100644
index 0000000..98d320b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-values/getComputedStyle-border-radius-003.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+
+  <meta charset="UTF-8">
+
+  <title>CSS Values Test: mixed units in calc() and computed border-radius shorthand value (complex)</title>
+
+  <!--
+
+  Bug 137688: getPropertyValue on computed style does not do shorthand properties
+  https://bugzilla.mozilla.org/show_bug.cgi?id=137688
+
+  -->
+
+  <link rel="author" title="Gérard Talbot" href="http://www.gtalbot.org/BrowserBugsSection/css21testsuite/">
+  <link rel="help" href="https://www.w3.org/TR/css-values-4/#calc-serialize">
+  <link rel="help" href="https://www.w3.org/TR/css-backgrounds-3/#the-border-radius">
+
+  <script src="/resources/testharness.js"></script>
+
+  <script src="/resources/testharnessreport.js"></script>
+
+  <style>
+  div#target
+    {
+      border: solid 2px;
+      border-top-left-radius: calc(1px + 1%) calc(5px + 5%);
+      border-top-right-radius: calc(2px + 2%) calc(6px + 6%);
+      border-bottom-right-radius: calc(3px + 3%) calc(7px + 7%);
+      border-bottom-left-radius: calc(4px + 4%) calc(8px + 8%);
+      height: 100px;
+      width: 100px;
+    }
+  </style>
+
+  <div id="target"></div>
+
+  <script>
+  function startTesting()
+  {
+
+  var targetElement = document.getElementById("target");
+
+    function verifyComputedStyle(property_name, expected_value, description)
+    {
+
+    test(function()
+      {
+
+      assert_equals(getComputedStyle(targetElement)[property_name], expected_value);
+
+      }, description);
+    }
+
+ /* verifyComputedStyle(property_name, expected_value, description) */
+
+    verifyComputedStyle("border-radius", "calc(1% + 1px) calc(2% + 2px) calc(3% + 3px) calc(4% + 4px) / calc(5% + 5px) calc(6% + 6px) calc(7% + 7px) calc(8% + 8px)", "testing border-radius shorthand");
+
+  /*
+
+   The first value is the horizontal radius, the second the vertical radius.
+
+               horizontal radius                /                 vertical radius
+  |__________________________________________|     |__________________________________________|
+
+
+  The four values for each radii are given in the order top-left, top-right, bottom-right, bottom-left:
+
+
+  top-left top-right bottom-right bottom-left   /  top-left top-right bottom-right bottom-left
+
+  |__________________________________________|     |__________________________________________|
+
+               horizontal radius                /                 vertical radius
+
+  */
+
+  }
+
+  startTesting();
+
+  </script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMedia-display-none-iframe.html b/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMedia-display-none-iframe.html
new file mode 100644
index 0000000..08fcb3c5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/matchMedia-display-none-iframe.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>CSS Test: matchMedia works on display: none iframes</title>
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#dom-window-matchmedia">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+  function frameLoaded(frame) {
+    test(function() {
+      assert_true(frame.contentWindow.matchMedia("all").matches);
+    }, "matchMedia should work in display: none iframes");
+    test(function() {
+      assert_true(frame.contentWindow.matchMedia("(min-width: 0)").matches);
+      assert_true(!frame.contentWindow.matchMedia("(min-width: 1px)").matches);
+    }, "matchMedia should assume a 0x0 viewport in display: none iframes");
+  }
+</script>
+<iframe style="display: none" onload="frameLoaded(this)"></iframe>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom-view/resize-event-on-initial-layout.html b/third_party/blink/web_tests/external/wpt/css/cssom-view/resize-event-on-initial-layout.html
new file mode 100644
index 0000000..dc2f04b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom-view/resize-event-on-initial-layout.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="viewport" content="width=device-width">
+<link rel="help" href="https://drafts.csswg.org/cssom-view/#run-the-resize-steps"/>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+promise_test(async t => {
+  let gotResizeEvent = false;
+
+  on_event(window, 'resize', () => gotResizeEvent = true);
+
+  await new Promise(resolve  => requestAnimationFrame(resolve));
+  await new Promise(resolve  => requestAnimationFrame(resolve));
+
+  assert_false(gotResizeEvent, 'resize event should not be fired');
+}, 'resize events are not fired on the initial layout');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-001.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-001.tentative-expected.txt
new file mode 100644
index 0000000..b078ddb
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-001.tentative-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS <link disabled> prevents the stylesheet from being in document.styleSheets (from parser)
+FAIL HTMLLinkElement.disabled reflects the <link disabled> attribute, and behaves consistently assert_equals: expected null but got Element node <link title="alt" rel="stylesheet" href="data:text/css,ht...
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-001.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-001.tentative.html
new file mode 100644
index 0000000..877356f9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-001.tentative.html
@@ -0,0 +1,45 @@
+<!doctype html>
+<title>&lt;link disabled&gt;, HTMLLinkElement.disabled and CSSStyleSheet.disabled interactions</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link title="alt" rel="stylesheet" disabled href="data:text/css,html { background: green }">
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+const link = document.querySelector("link[disabled]");
+
+test(function() {
+  assert_equals(document.styleSheets.length, 0);
+  assert_applies(false);
+}, "<link disabled> prevents the stylesheet from being in document.styleSheets (from parser)");
+
+async_test(function(t) {
+  assert_true(link.disabled);
+
+  link.onload = t.step_func_done(function() {
+    assert_equals(document.styleSheets.length, 1);
+    let sheet = document.styleSheets[0];
+    assert_equals(sheet.ownerNode, link);
+    assert_applies(true);
+
+    link.disabled = true;
+    assert_equals(sheet.ownerNode, null);
+    assert_false(sheet.disabled);
+    assert_applies(false);
+    assert_true(link.hasAttribute("disabled"));
+
+    assert_equals(document.styleSheets.length, 0);
+    assert_applies(false);
+  });
+
+  link.disabled = false;
+  assert_true(!link.hasAttribute("disabled"));
+  assert_false(link.disabled);
+}, "HTMLLinkElement.disabled reflects the <link disabled> attribute, and behaves consistently");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-002.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-002.tentative-expected.txt
new file mode 100644
index 0000000..176385c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-002.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL HTMLLinkElement.disabled reflects the <link disabled> attribute, and behaves consistently, when the sheet is an alternate assert_equals: expected null but got Element node <link title="alt" rel="alternate stylesheet" href="data:t...
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-002.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-002.tentative.html
new file mode 100644
index 0000000..9c46f60a
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-002.tentative.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>&lt;link disabled&gt;, HTMLLinkElement.disabled and CSSStyleSheet.disabled interactions (alternate)</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link title="alt" rel="alternate stylesheet" disabled href="data:text/css,html { background: green }">
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+const link = document.querySelector("link[disabled]");
+
+async_test(function(t) {
+  assert_true(link.disabled);
+
+  link.onload = t.step_func_done(function() {
+    assert_equals(document.styleSheets.length, 1);
+    let sheet = document.styleSheets[0];
+    assert_equals(sheet.ownerNode, link);
+    assert_applies(true);
+
+    link.disabled = true;
+    assert_equals(sheet.ownerNode, null);
+    assert_false(sheet.disabled);
+    assert_applies(false);
+    assert_true(link.hasAttribute("disabled"));
+    assert_equals(document.styleSheets.length, 0);
+  });
+
+  link.disabled = false;
+  assert_true(!link.hasAttribute("disabled"));
+  assert_false(link.disabled);
+}, "HTMLLinkElement.disabled reflects the <link disabled> attribute, and behaves consistently, when the sheet is an alternate");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-003.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-003.tentative.html
new file mode 100644
index 0000000..fc86e6b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-003.tentative.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>&lt;link disabled&gt;'s "explicitly enabled" state persists after getting disconnected from the tree</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link title="alt" rel="alternate stylesheet" disabled href="data:text/css,html { background: green }">
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+const link = document.querySelector("link[disabled]");
+async_test(function(t) {
+  assert_true(link.disabled);
+  link.disabled = false;
+  assert_false(link.disabled);
+  assert_true(!link.hasAttribute("disabled"));
+  link.remove();
+
+  link.onload = t.step_func_done(function() {
+    assert_equals(document.styleSheets.length, 1);
+    let sheet = document.styleSheets[0];
+    assert_equals(sheet.ownerNode, link);
+    assert_applies(true);
+  });
+
+  document.head.appendChild(link);
+}, "HTMLLinkElement.disabled's explicitly enabled state persists when disconnected and connected again");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-004.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-004.tentative.html
new file mode 100644
index 0000000..7e6c34e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-004.tentative.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<title>&lt;link disabled&gt;'s "explicitly enabled" state doesn't persist for clones</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link title="alt" rel="alternate stylesheet" disabled href="data:text/css,html { background: green }">
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+const link = document.querySelector("link[disabled]");
+
+async_test(function(t) {
+  link.remove();
+  link.disabled = false; // `link` is explicitly enabled.
+
+  let clonesLoaded = 0;
+
+  for (let shallow of [true, false]) {
+    const clone = link.cloneNode(shallow);
+    clone.onload = t.step_func(function() {
+      assert_false(link.disabled);
+      // Even though it's not disabled, it still doesn't apply, since it's an alternate.
+      assert_applies(false);
+      if (++clonesLoaded == 2) {
+        link.onload = t.step_func_done(function() {
+          assert_false(link.disabled);
+          assert_applies(true); // `link` is still explicitly enabled.
+        });
+        document.head.appendChild(link);
+      }
+    });
+    document.head.appendChild(clone);
+  }
+}, "HTMLLinkElement.disabled's explicitly enabled state doesn't persist on clones");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-005.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-005.tentative.html
new file mode 100644
index 0000000..0233f8c7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-005.tentative.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>&lt;link disabled&gt;'s "explicitly enabled" persists across rel changes</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<link title="alt" rel="yadayada" disabled href="data:text/css,html { background: green }">
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+const link = document.querySelector("link[disabled]");
+
+async_test(function(t) {
+  link.onload = t.step_func_done(function() {
+    assert_applies(true);
+    link.setAttribute("rel", "alternate stylesheet");
+    assert_applies(true);
+    assert_false(link.disabled);
+  });
+  link.disabled = false;
+  link.setAttribute("rel", "stylesheet");
+}, "HTMLLinkElement.disabled's explicitly enabled state persists regardless of rel");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-006.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-006.tentative.html
new file mode 100644
index 0000000..5828e1c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-006.tentative.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>&lt;link disabled&gt;'s "explicitly enabled" state isn't magically set from the setter</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+async_test(function(t) {
+  const link = document.createElement("link");
+  link.setAttribute("rel", "alternate stylesheet");
+  link.setAttribute("title", "alt");
+  link.href = "data:text/css,html { background: green }";
+  link.disabled = false; // This should do nothing, and is the point of this test.
+  link.onload = t.step_func_done(function() {
+    assert_applies(false); // Should not apply, since it's an alternate that hasn't been enabled.
+    assert_false(link.disabled);
+  });
+  document.head.appendChild(link);
+}, "HTMLLinkElement.disabled setter does nothing if the attribute isn't present already.");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-007.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-007.tentative-expected.txt
new file mode 100644
index 0000000..4fac017
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-007.tentative-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL HTMLLinkElement.disabled setter sets the explicitly enabled state if toggled back and forth. assert_equals: expected "rgb(0, 128, 0)" but got "rgba(0, 0, 0, 0)"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-007.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-007.tentative.html
new file mode 100644
index 0000000..451fc3d
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-007.tentative.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<title>&lt;link disabled&gt;'s "explicitly enabled" state works when set explicitly back and forth</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+function assert_applies(applies) {
+  (applies ? assert_equals : assert_not_equals)(getComputedStyle(document.documentElement).backgroundColor, "rgb(0, 128, 0)");
+}
+
+async_test(function(t) {
+  const link = document.createElement("link");
+  link.setAttribute("rel", "alternate stylesheet");
+  link.setAttribute("title", "alt");
+  link.href = "data:text/css,html { background: green }";
+  link.disabled = true;
+  link.disabled = false; // This should make it "explicitly enabled".
+  link.onload = t.step_func_done(function() {
+    assert_applies(true); // Should apply, since it's explicitly enabled.
+    assert_false(link.disabled);
+  });
+  document.head.appendChild(link);
+}, "HTMLLinkElement.disabled setter sets the explicitly enabled state if toggled back and forth.");
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-alternate-ref.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-alternate-ref.html
new file mode 100644
index 0000000..5d87bfda
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-alternate-ref.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<title>CSS Test Reference</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<style>
+  html { background: green }
+</style>
diff --git a/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-alternate.tentative.html b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-alternate.tentative.html
new file mode 100644
index 0000000..5b020a17
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/cssom/HTMLLinkElement-disabled-alternate.tentative.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<title>CSS Test: alternate stylesheets can be disabled by HTMLLinkElement.disabled if they have the disabled attribute already</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1281135">
+<link rel="help" href="https://github.com/whatwg/html/issues/3840">
+<link rel="match" href="HTMLLinkElement-disabled-alternate-ref.html">
+<link title="alt" rel="alternate stylesheet" href="data:text/css,html { background: green }" disabled onload="document.documentElement.className = ''">
+<script>
+  onload = function() {
+    const link = document.querySelector("link[rel='alternate stylesheet']");
+    link.disabled = false;
+  }
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/sharing-in-svg-use-ref.html b/third_party/blink/web_tests/external/wpt/css/selectors/sharing-in-svg-use-ref.html
new file mode 100644
index 0000000..703cc99
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/sharing-in-svg-use-ref.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>CSS Test reference</title>
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<svg width="200" height="100">
+  <defs>
+    <g id="p0">
+      <rect width="100" height="100" style="fill: blue" />
+      <rect x="100" y="0" width="100" height="100" style="fill: purple" />
+    </g>
+  </defs>
+  <use href="#p0" x="0" y="0" />
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/sharing-in-svg-use.html b/third_party/blink/web_tests/external/wpt/css/selectors/sharing-in-svg-use.html
new file mode 100644
index 0000000..08a038c
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/selectors/sharing-in-svg-use.html
@@ -0,0 +1,25 @@
+<!doctype html>
+<title>CSS Test: nth-of-type should work in an svg use subtree</title>
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#child-index">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1540385">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="match" href="sharing-in-svg-use-ref.html">
+<style>
+rect:nth-of-type(1) {
+  fill: blue;
+}
+rect:nth-of-type(2) {
+  fill: purple;
+}
+</style>
+<!-- Should see two different colors -->
+<svg width="200" height="100">
+  <defs>
+    <g id="p0">
+      <rect width="100" height="100" />
+      <rect x="100" y="0" width="100" height="100" />
+    </g>
+  </defs>
+  <use href="#p0" x="0" y="0" />
+</svg>
diff --git a/third_party/blink/web_tests/external/wpt/editing/data/removeformat.js b/third_party/blink/web_tests/external/wpt/editing/data/removeformat.js
index cfc355d8..db5c055 100644
--- a/third_party/blink/web_tests/external/wpt/editing/data/removeformat.js
+++ b/third_party/blink/web_tests/external/wpt/editing/data/removeformat.js
@@ -75,6 +75,26 @@
     "[foobarbaz]",
     [true,true],
     {"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
+["[foo<span style=\"display: none\">bar</span>baz]",
+    [["stylewithcss","true"],["removeformat",""]],
+    "[foobarbaz]",
+    [true,true],
+    {"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
+["[foo<span style=\"display: none\">bar</span>baz]",
+    [["stylewithcss","false"],["removeformat",""]],
+    "[foobarbaz]",
+    [true,true],
+    {"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
+["[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]",
+    [["stylewithcss","true"],["removeformat",""]],
+    "[foobarbaz]",
+    [true,true],
+    {"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
+["[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]",
+    [["stylewithcss","false"],["removeformat",""]],
+    "[foobarbaz]",
+    [true,true],
+    {"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
 ["foo<span style=\"font-weight: bold\">b[a]r</span>baz",
     [["stylewithcss","true"],["removeformat",""]],
     "foo<span style=\"font-weight:bold\">b</span>[a]<span style=\"font-weight:bold\">r</span>baz",
@@ -85,6 +105,26 @@
     "foo<span style=\"font-weight:bold\">b</span>[a]<span style=\"font-weight:bold\">r</span>baz",
     [true,true],
     {"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
+["foo<span style=\"display: none\">b[a]r</span>baz",
+    [["stylewithcss","true"],["removeformat",""]],
+    "foo<span style=\"display:none\">b</span>[a]<span style=\"display:none\">r</span>baz",
+    [true,true],
+    {"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
+["foo<span style=\"display: none\">b[a]r</span>baz",
+    [["stylewithcss","false"],["removeformat",""]],
+    "foo<span style=\"display:none\">b</span>[a]<span style=\"display:none\">r</span>baz",
+    [true,true],
+    {"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
+["foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz",
+    [["stylewithcss","true"],["removeformat",""]],
+    "foo<span style=\"display:none; font-weight:bold\">b</span>[a]<span style=\"display:none; font-weight:bold\">r</span>baz",
+    [true,true],
+    {"stylewithcss":[false,false,"",false,true,""],"removeformat":[false,false,"",false,false,""]}],
+["foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz",
+    [["stylewithcss","false"],["removeformat",""]],
+    "foo<span style=\"display:none; font-weight:bold\">b</span>[a]<span style=\"display:none; font-weight:bold\">r</span>baz",
+    [true,true],
+    {"stylewithcss":[false,true,"",false,false,""],"removeformat":[false,false,"",false,false,""]}],
 ["[foo<span style=\"font-variant: small-caps\">bar</span>baz]",
     [["stylewithcss","true"],["removeformat",""]],
     "[foobarbaz]",
diff --git a/third_party/blink/web_tests/external/wpt/editing/run/removeformat-expected.txt b/third_party/blink/web_tests/external/wpt/editing/run/removeformat-expected.txt
index e078b46..bd2809ff 100644
--- a/third_party/blink/web_tests/external/wpt/editing/run/removeformat-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/editing/run/removeformat-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 1704 tests; 1671 PASS, 33 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 1832 tests; 1787 PASS, 45 FAIL, 0 TIMEOUT, 0 NOTRUN.
 FAIL [["removeformat",""]] "foo[]bar": execCommand("removeformat", false, "") return value assert_equals: expected true but got false
 PASS [["removeformat",""]] "foo[]bar" checks for modifications to non-editable content
 PASS [["removeformat",""]] "foo[]bar" compare innerHTML
@@ -219,6 +219,70 @@
 PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"font-weight: bold\">bar</span>baz]" queryCommandIndeterm("removeformat") after
 PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"font-weight: bold\">bar</span>baz]" queryCommandState("removeformat") after
 PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"font-weight: bold\">bar</span>baz]" queryCommandValue("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]": execCommand("removeformat", false, "") return value
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobarbaz" but got "foo<span style=\"display:none\">bar</span>baz"
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]": execCommand("removeformat", false, "") return value
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobarbaz" but got "foo<span style=\"display:none\">bar</span>baz"
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandState("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none\">bar</span>baz]" queryCommandValue("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]": execCommand("stylewithcss", false, "true") return value
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]": execCommand("removeformat", false, "") return value
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobarbaz" but got "foo<span style=\"display:none\">bar</span>baz"
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]": execCommand("stylewithcss", false, "false") return value
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]": execCommand("removeformat", false, "") return value
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foobarbaz" but got "foo<span style=\"display:none\">bar</span>baz"
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandState("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "[foo<span style=\"display: none; font-weight: bold\">bar</span>baz]" queryCommandValue("removeformat") after
 PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"font-weight: bold\">b[a]r</span>baz": execCommand("stylewithcss", false, "true") return value
 PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"font-weight: bold\">b[a]r</span>baz": execCommand("removeformat", false, "") return value
 PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"font-weight: bold\">b[a]r</span>baz" checks for modifications to non-editable content
@@ -251,6 +315,70 @@
 PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("removeformat") after
 PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"font-weight: bold\">b[a]r</span>baz" queryCommandState("removeformat") after
 PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"font-weight: bold\">b[a]r</span>baz" queryCommandValue("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz": execCommand("stylewithcss", false, "true") return value
+FAIL [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz": execCommand("removeformat", false, "") return value assert_equals: expected true but got false
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<span style=\"display:none\">b</span>a<span style=\"display:none\">r</span>baz" but got "foo<span style=\"display:none\">bar</span>baz"
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz": execCommand("stylewithcss", false, "false") return value
+FAIL [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz": execCommand("removeformat", false, "") return value assert_equals: expected true but got false
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<span style=\"display:none\">b</span>a<span style=\"display:none\">r</span>baz" but got "foo<span style=\"display:none\">bar</span>baz"
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandState("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none\">b[a]r</span>baz" queryCommandValue("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz": execCommand("stylewithcss", false, "true") return value
+FAIL [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz": execCommand("removeformat", false, "") return value assert_equals: expected true but got false
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" checks for modifications to non-editable content
+FAIL [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<span style=\"display:none; font-weight:bold\">b</span>a<span style=\"display:none; font-weight:bold\">r</span>baz" but got "foo<span style=\"display:none; font-weight:bold\">bar</span>baz"
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("removeformat") before
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("removeformat") after
+PASS [["stylewithcss","true"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz": execCommand("stylewithcss", false, "false") return value
+FAIL [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz": execCommand("removeformat", false, "") return value assert_equals: expected true but got false
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" checks for modifications to non-editable content
+FAIL [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" compare innerHTML assert_equals: Unexpected innerHTML (after normalizing inline style) expected "foo<span style=\"display:none; font-weight:bold\">b</span>a<span style=\"display:none; font-weight:bold\">r</span>baz" but got "foo<span style=\"display:none; font-weight:bold\">bar</span>baz"
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("stylewithcss") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("stylewithcss") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("removeformat") before
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandIndeterm("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandState("removeformat") after
+PASS [["stylewithcss","false"],["removeformat",""]] "foo<span style=\"display: none; font-weight: bold\">b[a]r</span>baz" queryCommandValue("removeformat") after
 PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"font-variant: small-caps\">bar</span>baz]": execCommand("stylewithcss", false, "true") return value
 PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"font-variant: small-caps\">bar</span>baz]": execCommand("removeformat", false, "") return value
 PASS [["stylewithcss","true"],["removeformat",""]] "[foo<span style=\"font-variant: small-caps\">bar</span>baz]" checks for modifications to non-editable content
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html
index c9e1a6a..602fabc 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/request/request-keepalive.html
@@ -21,7 +21,7 @@
 
 test(() => {
   const init = {method: 'POST', keepalive: true, body: new ReadableStream()};
-  assert_throws('TypeError', () => {new Request('/', init)});
+  assert_throws(new TypeError(), () => {new Request('/', init)});
 }, 'keepalive flag with stream body');
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch-sw.https.tentative.html b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch-sw.https.tentative.html
index 2286739..f6ece2c 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch-sw.https.tentative.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/stale-while-revalidate/fetch-sw.https.tentative.html
@@ -16,18 +16,24 @@
 <script>
 
   // Duplicating this resource to make service worker scoping simpler.
-  async function setupRegistration(t, scope) {
+  async function setupRegistrationAndWaitToBeControlled(t, scope) {
+    const controlled = new Promise((resolve) => {
+      navigator.serviceWorker.oncontrollerchange = () => { resolve(); };
+    });
     const reg = await navigator.serviceWorker.register('sw-intercept.js');
     await wait_for_state(t, reg.installing, 'activated');
+    await controlled;
     add_completion_callback(_ => reg.unregister());
     return reg;
   }
 
-  function wait25ms(test) {
+  // Using 250ms polling interval to provide enough 'network calmness' to give
+  // the background low priority revalidation request a chance to kick in.
+  function wait250ms(test) {
     return new Promise(resolve => {
       test.step_timeout(() => {
         resolve();
-      }, 25);
+      }, 250);
     });
   }
 
@@ -35,7 +41,7 @@
     var request_token = token();
     const uri = 'stale-script.py?token=' + request_token;
 
-    await setupRegistration(test, 'stale-script.py');
+    await setupRegistrationAndWaitToBeControlled(test, 'stale-script.py');
 
     var service_worker_count = 0;
     navigator.serviceWorker.addEventListener('message', function once(event) {
@@ -54,7 +60,7 @@
         assert_equals(service_worker_count, 2);
         break;
       }
-      await wait25ms(test);
+      await wait250ms(test);
     }
   }, 'Second fetch returns same response');
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/new_window_same_site.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/new_window_same_site.html
new file mode 100644
index 0000000..b75f7ff
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/new_window_same_site.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<meta charset=utf-8>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src="/common/get-host-info.sub.js"></script>
+
+<script>
+
+const CHANNEL_NAME = "new_window_same_site";
+
+async_test(t => {
+  let w = window.open(`${get_host_info().HTTP_REMOTE_ORIGIN}/html/cross-origin-opener/resources/window.sub.html?channel=${CHANNEL_NAME}`, "window_name", "height=200,width=250");
+
+  // w will be closed by its postback iframe. When out of process,
+  // window.close() does not work.
+  t.add_cleanup(() => w.close());
+
+  let bc = new BroadcastChannel(CHANNEL_NAME);
+  bc.onmessage = t.step_func_done((event) => {
+    let payload = event.data;
+    assert_equals(payload.name, "window_name");
+    assert_equals(payload.opener, true);
+  });
+}, "same-site policy works");
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/new_window_same_site.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/new_window_same_site.html.headers
new file mode 100644
index 0000000..34bd099
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/new_window_same_site.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/postback.sub.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/postback.sub.html
new file mode 100644
index 0000000..ee08bab4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/postback.sub.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<script>
+
+let channelName = new URL(location).searchParams.get("channel");
+let bc = new BroadcastChannel(channelName);
+window.addEventListener("message", (event) => {
+  bc.postMessage(event.data);
+  window.parent.close();
+}, false);
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/window.sub.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/window.sub.html
new file mode 100644
index 0000000..7c72f87
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/window.sub.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<meta charset=utf-8>
+
+<script src="/common/get-host-info.sub.js"></script>
+<div id="status"> </div>
+
+<script type="text/javascript">
+
+  let iframe = document.createElement("iframe");
+  iframe.onload = () => {
+    let payload = { name: self.name, opener: !!self.opener };
+    iframe.contentWindow.postMessage(payload, "*");
+  };
+  let channelName = new URL(location).searchParams.get("channel");
+  iframe.src = `${get_host_info().HTTP_ORIGIN}/html/cross-origin-opener/resources/postback.sub.html?channel=${channelName}`;
+  document.body.appendChild(iframe);
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/window.sub.html.headers b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/window.sub.html.headers
new file mode 100644
index 0000000..34bd099
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener/resources/window.sub.html.headers
@@ -0,0 +1 @@
+Cross-Origin-Opener-Policy: same-site
diff --git a/third_party/blink/web_tests/external/wpt/html/interaction/focus/focus-file-input.html b/third_party/blink/web_tests/external/wpt/html/interaction/focus/focus-file-input.html
new file mode 100644
index 0000000..d300711
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/interaction/focus/focus-file-input.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>HTML Test: file input can be programatically focused before layout</title>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#focus">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=505355">
+<link rel="author" title="Mozilla" href="https://mozilla.org/">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<input type="file">
+<script>
+test(function() {
+  let input = document.querySelector("input");
+  assert_not_equals(document.activeElement, input);
+  input.focus();
+  assert_equals(document.activeElement, input);
+});
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html
new file mode 100644
index 0000000..debe014
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<!-- DO NOT EDIT! This test has been generated by tools/gentest.py. -->
+<title>Canvas test: security.pattern.canvas.fillStyle.cross</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/media.js"></script>
+<script src="/common/namespaces.js"></script>
+<script src="/common/canvas-tests.js"></script>
+
+<body>
+<p class="desc">Setting fillStyle to a pattern of an unclean canvas makes the canvas origin-unclean</p>
+
+<script>
+
+forEachCanvasSource("http://{{domains[www1]}}:{{ports[http][0]}}",
+                    "http://{{domains[]}}:{{ports[http][0]}}",
+                    (name, factory) => {
+  promise_test(_ => {
+    return factory().then(source => {
+      const canvas = document.createElement('canvas');
+      const ctx = canvas.getContext('2d');
+      const pattern = ctx.createPattern(source, 'repeat');
+      ctx.fillStyle = pattern;
+      ctx.fillStyle = 'red';
+      assert_throws("SECURITY_ERR", function() { canvas.toDataURL(); });
+      assert_throws("SECURITY_ERR", function() { ctx.getImageData(0, 0, 1, 1); });
+    });
+  }, `${name}: Setting fillStyle to an origin-unclear pattern makes the canvas origin-unclean`);
+});
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validate.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validate.html
index 47b41ff..e32fd90 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validate.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validate.html
@@ -61,7 +61,7 @@
       }, false);
     }
 
-    for (var index = 0; index < fm1.elements.length; index++) {
+    for (var index = 0; index < fm2.elements.length; index++) {
       var ele = fm2.elements.item(index);
       ele.addEventListener("invalid", function (e) {
         times2++;
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-patternMismatch.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-patternMismatch.html
index 5a0012b0..d8677898 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-patternMismatch.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/constraints/form-validation-validity-patternMismatch.html
@@ -18,7 +18,8 @@
         {conditions: {pattern: "[A-Z]+", value: ""}, expected: false, name: "[target] The value attibute is empty string"},
         {conditions: {pattern: "[A-Z]{1}", value: "A"}, expected: false, name: "[target] The value attribute matches the pattern attribute"},
         {conditions: {pattern: "[A-Z]+", value: "\u0041\u0042\u0043"}, expected: false, name: "[target] The value(ABC) in unicode attribute matches the pattern attribute"},
-        {conditions: {pattern: "[a-z]{3,}", value: "ABCD"}, expected: true, name: "[target] The value attribute mismatches the pattern attribute"}
+        {conditions: {pattern: "[a-z]{3,}", value: "ABCD"}, expected: true, name: "[target] The value attribute mismatches the pattern attribute"},
+        {conditions: {pattern: "[A-Z]+", value: "ABC123"}, expected: true, name: "[target] The value attribute mismatches the pattern attribute even when a subset matches"}
       ]
     }
   ];
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete-expected.txt b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete-expected.txt
new file mode 100644
index 0000000..25900f61
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete-expected.txt
@@ -0,0 +1,69 @@
+This is a testharness.js-based test.
+Found 65 tests; 64 PASS, 1 FAIL, 0 TIMEOUT, 0 NOTRUN.
+PASS form autocomplete attribute missing
+PASS form autocomplete attribute on
+PASS form autocomplete attribute off
+PASS form autocomplete attribute invalid
+PASS on is an allowed autocomplete field name
+PASS off is an allowed autocomplete field name
+PASS name is an allowed autocomplete field name
+PASS honorific-prefix is an allowed autocomplete field name
+PASS given-name is an allowed autocomplete field name
+PASS additional-name is an allowed autocomplete field name
+PASS family-name is an allowed autocomplete field name
+PASS honorific-suffix is an allowed autocomplete field name
+PASS nickname is an allowed autocomplete field name
+PASS username is an allowed autocomplete field name
+PASS new-password is an allowed autocomplete field name
+PASS current-password is an allowed autocomplete field name
+FAIL one-time-code is an allowed autocomplete field name assert_equals: expected "one-time-code" but got ""
+PASS organization-title is an allowed autocomplete field name
+PASS organization is an allowed autocomplete field name
+PASS street-address is an allowed autocomplete field name
+PASS address-line1 is an allowed autocomplete field name
+PASS address-line2 is an allowed autocomplete field name
+PASS address-line3 is an allowed autocomplete field name
+PASS address-level4 is an allowed autocomplete field name
+PASS address-level3 is an allowed autocomplete field name
+PASS address-level2 is an allowed autocomplete field name
+PASS address-level1 is an allowed autocomplete field name
+PASS country is an allowed autocomplete field name
+PASS country-name is an allowed autocomplete field name
+PASS postal-code is an allowed autocomplete field name
+PASS cc-name is an allowed autocomplete field name
+PASS cc-given-name is an allowed autocomplete field name
+PASS cc-additional-name is an allowed autocomplete field name
+PASS cc-family-name is an allowed autocomplete field name
+PASS cc-number is an allowed autocomplete field name
+PASS cc-exp is an allowed autocomplete field name
+PASS cc-exp-month is an allowed autocomplete field name
+PASS cc-exp-year is an allowed autocomplete field name
+PASS cc-csc is an allowed autocomplete field name
+PASS cc-type is an allowed autocomplete field name
+PASS transaction-currency is an allowed autocomplete field name
+PASS transaction-amount is an allowed autocomplete field name
+PASS language is an allowed autocomplete field name
+PASS bday is an allowed autocomplete field name
+PASS bday-day is an allowed autocomplete field name
+PASS bday-month is an allowed autocomplete field name
+PASS bday-year is an allowed autocomplete field name
+PASS sex is an allowed autocomplete field name
+PASS url is an allowed autocomplete field name
+PASS photo is an allowed autocomplete field name
+PASS tel is an allowed autocomplete field name
+PASS tel-country-code is an allowed autocomplete field name
+PASS tel-national is an allowed autocomplete field name
+PASS tel-area-code is an allowed autocomplete field name
+PASS tel-local is an allowed autocomplete field name
+PASS tel-local-prefix is an allowed autocomplete field name
+PASS tel-local-suffix is an allowed autocomplete field name
+PASS tel-extension is an allowed autocomplete field name
+PASS email is an allowed autocomplete field name
+PASS impp is an allowed autocomplete field name
+PASS Test whitespace-only attribute value
+PASS Test maximum number of tokens
+PASS Unknown field
+PASS Test 'wearing the autofill anchor mantle' with off/on
+PASS Serialize combinations of section, mode, contact, and field
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete.html b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete.html
index 618aa0a..ec79bac 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/forms/the-form-element/form-autocomplete.html
@@ -47,7 +47,7 @@
   autocompletetest(document.forms.autocomplete_off, ["off", "", "on", "off", ""], "form autocomplete attribute off");
   autocompletetest(document.forms.autocomplete_invalid, ["on", "", "on", "off", ""], "form autocomplete attribute invalid");
 
-  var keywords = [ "on", "off", "name", "honorific-prefix", "given-name", "additional-name", "family-name", "honorific-suffix", "nickname", "username", "new-password", "current-password", "organization-title", "organization", "street-address", "address-line1", "address-line2", "address-line3", "address-level4", "address-level3", "address-level2", "address-level1", "country", "country-name", "postal-code", "cc-name", "cc-given-name", "cc-additional-name", "cc-family-name", "cc-number", "cc-exp", "cc-exp-month", "cc-exp-year", "cc-csc", "cc-type", "transaction-currency", "transaction-amount", "language", "bday", "bday-day", "bday-month", "bday-year", "sex", "url", "photo", "tel", "tel-country-code", "tel-national", "tel-area-code", "tel-local", "tel-local-prefix", "tel-local-suffix", "tel-extension", "email", "impp" ];
+  var keywords = [ "on", "off", "name", "honorific-prefix", "given-name", "additional-name", "family-name", "honorific-suffix", "nickname", "username", "new-password", "current-password", "one-time-code", "organization-title", "organization", "street-address", "address-line1", "address-line2", "address-line3", "address-level4", "address-level3", "address-level2", "address-level1", "country", "country-name", "postal-code", "cc-name", "cc-given-name", "cc-additional-name", "cc-family-name", "cc-number", "cc-exp", "cc-exp-month", "cc-exp-year", "cc-csc", "cc-type", "transaction-currency", "transaction-amount", "language", "bday", "bday-day", "bday-month", "bday-year", "sex", "url", "photo", "tel", "tel-country-code", "tel-national", "tel-area-code", "tel-local", "tel-local-prefix", "tel-local-suffix", "tel-extension", "email", "impp" ];
 
   keywords.forEach(function(keyword) {
     test(function(){
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003-ref.html b/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003-ref.html
new file mode 100644
index 0000000..dbe4c05b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>HTML LI element: dynamic update test for LI @value</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+</head>
+<body onload="document.getElementById('item').removeAttribute('value');">
+<ol><li id="item" value="3"></li></ol>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003.html b/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003.html
new file mode 100644
index 0000000..bad3819
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/grouping-content/the-li-element/grouping-li-reftest-003.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html><head>
+  <meta charset="utf-8">
+  <title>HTML LI element: dynamic update test for LI @value</title>
+  <link rel="author" title="Mats Palmgren" href="mailto:mats@mozilla.org">
+  <link rel="help" href="https://html.spec.whatwg.org/multipage/grouping-content.html#the-li-element">
+  <link rel="help" href="https://drafts.csswg.org/css-lists/#propdef-counter-set">
+  <link rel="match" href="grouping-li-reftest-003-ref.html">
+</head>
+<body onload="document.getElementById('item').removeAttribute('value');">
+<noscript>Test not run - javascript required.</noscript>
+<ol><li id="item" value="3"></li></ol>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/unclosed-svg-script.html b/third_party/blink/web_tests/external/wpt/html/syntax/parsing/unclosed-svg-script.html
index 80f662a..e404861 100644
--- a/third_party/blink/web_tests/external/wpt/html/syntax/parsing/unclosed-svg-script.html
+++ b/third_party/blink/web_tests/external/wpt/html/syntax/parsing/unclosed-svg-script.html
@@ -7,6 +7,7 @@
     var scriptWithEndTagRan = false;
     var scriptWithoutEndTagRan = false;
     var scriptWithBogusEndTagInsideRan = false;
+    var scriptWithBreakout = false;
 </script>
 <svg>
     <script>scriptWithEndTagRan = true;</script>
@@ -17,6 +18,10 @@
 <svg>
     <script>scriptWithBogusEndTagInsideRan = true;</g></script>
 </svg>
+<svg>
+    <script>scriptWithBreakout = true;<s></script>
+</svg>
+</s>
 <script>
     test(function() {
         assert_true(scriptWithEndTagRan);
@@ -27,4 +32,7 @@
     test(function() {
         assert_true(scriptWithBogusEndTagInsideRan);
     }, "SVG scripts with bogus end tag inside should run");
+    test(function() {
+        assert_false(scriptWithBreakout);
+    }, "SVG scripts ended by HTML breakout should not run");
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_no_differences.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_no_differences.html
new file mode 100644
index 0000000..324873a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_no_differences.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This exactly matches the reference, and includes the possibilty of
+     0 pixels different; in this case the maxDifference is ignored --->
+<meta name=fuzzy content="fuzzy-ref-1.html:128;0-100">
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_no_differences_1.html b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_no_differences_1.html
new file mode 100644
index 0000000..6bf85cee
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/infrastructure/reftest/reftest_fuzzy_no_differences_1.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<link rel=match href=fuzzy-ref-1.html>
+<!-- This exactly matches the reference, and includes the possibilty of
+     0 difference in the color channel; in this case the pixelsDifferent is ignored --->
+<meta name=fuzzy content="fuzzy-ref-1.html:0-128;100">
+<style>
+div {
+  width: 100px;
+  height: 100px;
+  background-color: green;
+}
+</style>
+<div></div>
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-streams.idl b/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-streams.idl
index 0feea37..427aa92 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-streams.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/mediacapture-streams.idl
@@ -38,7 +38,6 @@
     MediaTrackConstraints getConstraints();
     MediaTrackSettings getSettings();
     Promise<void> applyConstraints(optional MediaTrackConstraints constraints);
-                    attribute EventHandler onoverconstrained;
 };
 
 enum MediaStreamTrackState {
@@ -149,16 +148,6 @@
     required MediaStreamTrack track;
 };
 
-[Exposed=Window,
- Constructor(DOMString type, OverconstrainedErrorEventInit eventInitDict)]
-interface OverconstrainedErrorEvent : Event {
-    readonly        attribute OverconstrainedError? error;
-};
-
-dictionary OverconstrainedErrorEventInit : EventInit {
-             OverconstrainedError? error = null;
-};
-
 partial interface Navigator {
     [SameObject, SecureContext]
     readonly        attribute MediaDevices mediaDevices;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl b/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl
index cd2e1446..13ad7f8 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/user-timing.idl
@@ -4,12 +4,12 @@
 // Source: User Timing Level 3 (https://w3c.github.io/user-timing/)
 
 dictionary PerformanceMarkOptions {
-    any detail = null;
+    any detail;
     DOMHighResTimeStamp startTime;
 };
 
 dictionary PerformanceMeasureOptions {
-    any detail = null;
+    any detail;
     (DOMString or DOMHighResTimeStamp) start;
     DOMHighResTimeStamp duration;
     (DOMString or DOMHighResTimeStamp) end;
@@ -18,7 +18,7 @@
 partial interface Performance {
     PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions);
     void clearMarks(optional DOMString markName);
-    PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions)? startOrMeasureOptions, optional DOMString endMark);
+    PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions, optional DOMString endMark);
     void clearMeasures(optional DOMString measureName);
 };
 
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist
index 846c75f..a7a4600 100644
--- a/third_party/blink/web_tests/external/wpt/lint.whitelist
+++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -64,6 +64,9 @@
 
 TRAILING WHITESPACE: xhr/resources/headers-some-are-empty.asis
 
+## .gitignore
+W3C-TEST.ORG: .gitignore
+
 ## Documentation ##
 
 W3C-TEST.ORG: README.md
@@ -142,6 +145,7 @@
 SET TIMEOUT: common/reftest-wait.js
 SET TIMEOUT: conformance-checkers/*
 SET TIMEOUT: content-security-policy/*
+SET TIMEOUT: css/css-display/display-contents-shadow-dom-1.html
 SET TIMEOUT: css/selectors/selector-placeholder-shown-type-change-001.html
 SET TIMEOUT: css/selectors/selector-placeholder-shown-type-change-002.html
 SET TIMEOUT: css/selectors/selector-placeholder-shown-type-change-003.html
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html
new file mode 100644
index 0000000..0904d9f1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-baseline.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Baseline of inferred mrows</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#mrow">
+<meta name="assert" content="Baseline for mrow-like elements is correct.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script type="text/javascript">
+  setup({ explicit_done: true });
+  window.addEventListener("load", runTests);
+  function runTests()
+  {
+      ["Mrow", "Sqrt", "Style", "Error", "Phantom", "Math", "Menclose", "Mpadded"].forEach((tag) => {
+          var x = document.getElementById("above" + tag).getBoundingClientRect();
+          var y = document.getElementById("below" + tag).getBoundingClientRect();
+          test(function() {
+              assert_equals(x.bottom, y.top);
+          }, "baseline alignment inside " + tag);
+      });
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+  <p>
+    <math><mrow><mspace id="aboveMrow" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowMrow" width="10px" depth="30px" style="background: blue"></mspace></mrow></math>
+    <math><msqrt><mspace id="aboveSqrt" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowSqrt" width="10px" depth="30px" style="background: blue"></mspace></msqrt></math>
+    <math><mstyle><mspace id="aboveStyle" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowStyle" width="10px" depth="30px" style="background: blue"></mspace></mstyle></math>
+    <math><merror><mspace id="aboveError" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowError" width="10px" depth="30px" style="background: blue"></mspace></merror></math>
+    <math><mphantom><mspace style="visibility: visible;" id="abovePhantom" width="10px" height="30px" style="background: purple"></mspace><mspace style="visibility: visible;" id="belowPhantom" width="10px" depth="30px" style="background: blue"></mspace></mphantom></math>
+    <math><mspace id="aboveMath" width="10px" height="30px" style="background: purple"></mspace><mspace id="belowMath" width="10px" depth="30px" style="background: blue"></mspace></math>
+    <math><menclose notation="box"><mspace id="aboveMenclose" width="10px" height="30px" style="background: purple"
+></mspace><mspace id="belowMenclose" width="10px" depth="30px" style="background: blue"></mspace></menclose></math>
+    <math><mpadded notation="box"><mspace id="aboveMpadded" width="10px" height="30px" style="background: purple"
+></mspace><mspace id="belowMpadded" width="10px" depth="30px" style="background: blue"></mspace></mpadded></math>
+  </p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html
new file mode 100644
index 0000000..f75726c1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/mathml/presentation-markup/mrow/inferred-mrow-stretchy.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>Stretchy in inferred mrows</title>
+<link rel="help" href="https://mathml-refresh.github.io/mathml-core/#mrow">
+<meta name="assert" content="Baseline for mrow-like elements is correct.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  mo {
+    font-size: 10px;
+    font-family: axisheight5000-verticalarrow14000;
+  }
+  @font-face {
+    font-family: axisheight5000-verticalarrow14000;
+    src: url("/fonts/math/axisheight5000-verticalarrow14000.woff");
+  }
+</style>
+<script type="text/javascript">
+  setup({ explicit_done: true });
+  window.addEventListener("load", function() {
+    // Delay the check to workaround WebKit's bug https://webkit.org/b/174030.
+    requestAnimationFrame(() => { document.fonts.ready.then(runTests); });
+  });
+  function runTests()
+  {
+      ["Mrow", "Sqrt", "Style", "Error", "Phantom", "Math", "Menclose", "Mpadded"].forEach((tag) => {
+          var mo = document.getElementById("mo" + tag);
+          test(function() {
+              assert_greater_than_equal(mo.getBoundingClientRect().height, 100);
+          }, "operator stretching inside " + tag);
+      });
+      done();
+  }
+</script>
+</head>
+<body>
+  <div id="log"></div>
+  <p>
+    <math><mrow><mo id="moMrow">&#x21A8;</mo><mspace width="1px" height="100px" style="background: blue"></mspace></mrow></math>
+    <math><msqrt><mo id="moSqrt">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></msqrt></math>
+    <math><mstyle><mo id="moStyle">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mstyle></math>
+    <math><merror><mo id="moError">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></merror></math>
+    <math><mphantom><mo style="visibilty: visible;" id="moPhantom">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mphantom></math>
+    <math><mo id="moMath">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></math>
+    <math><menclose notation="box"><mo id="moMenclose">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></menclose></math>
+    <math><mpadded notation="box"><mo id="moMpadded">&#x21A8;</mo><mspace width="1px" height="100px" style="background: magenta"></mspace></mpadded></math>
+  </p>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
deleted file mode 100644
index 2720255..0000000
--- a/third_party/blink/web_tests/external/wpt/mediacapture-streams/idlharness.https.window-expected.txt
+++ /dev/null
@@ -1,167 +0,0 @@
-This is a testharness.js-based test.
-Found 163 tests; 151 PASS, 12 FAIL, 0 TIMEOUT, 0 NOTRUN.
-PASS mediacapture-streams interfaces.
-PASS Partial interface Navigator: original interface defined
-PASS Partial interface Navigator[2]: original interface defined
-PASS Partial interface MediaDevices: original interface defined
-PASS MediaStream interface: existence and properties of interface object
-PASS MediaStream interface object length
-PASS MediaStream interface object name
-PASS MediaStream interface: existence and properties of interface prototype object
-PASS MediaStream interface: existence and properties of interface prototype object's "constructor" property
-PASS MediaStream interface: existence and properties of interface prototype object's @@unscopables property
-PASS MediaStream interface: attribute id
-PASS MediaStream interface: operation getAudioTracks()
-PASS MediaStream interface: operation getVideoTracks()
-PASS MediaStream interface: operation getTracks()
-PASS MediaStream interface: operation getTrackById(DOMString)
-PASS MediaStream interface: operation addTrack(MediaStreamTrack)
-PASS MediaStream interface: operation removeTrack(MediaStreamTrack)
-PASS MediaStream interface: operation clone()
-PASS MediaStream interface: attribute active
-PASS MediaStream interface: attribute onaddtrack
-PASS MediaStream interface: attribute onremovetrack
-PASS MediaStream must be primary interface of [object MediaStream]
-PASS Stringification of [object MediaStream]
-PASS MediaStream interface: [object MediaStream] must inherit property "id" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "getAudioTracks()" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "getVideoTracks()" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "getTracks()" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "getTrackById(DOMString)" with the proper type
-PASS MediaStream interface: calling getTrackById(DOMString) on [object MediaStream] with too few arguments must throw TypeError
-PASS MediaStream interface: [object MediaStream] must inherit property "addTrack(MediaStreamTrack)" with the proper type
-PASS MediaStream interface: calling addTrack(MediaStreamTrack) on [object MediaStream] with too few arguments must throw TypeError
-PASS MediaStream interface: [object MediaStream] must inherit property "removeTrack(MediaStreamTrack)" with the proper type
-PASS MediaStream interface: calling removeTrack(MediaStreamTrack) on [object MediaStream] with too few arguments must throw TypeError
-PASS MediaStream interface: [object MediaStream] must inherit property "clone()" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "active" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "onaddtrack" with the proper type
-PASS MediaStream interface: [object MediaStream] must inherit property "onremovetrack" with the proper type
-PASS MediaStream must be primary interface of new MediaStream()
-PASS Stringification of new MediaStream()
-PASS MediaStream interface: new MediaStream() must inherit property "id" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "getAudioTracks()" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "getVideoTracks()" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "getTracks()" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "getTrackById(DOMString)" with the proper type
-PASS MediaStream interface: calling getTrackById(DOMString) on new MediaStream() with too few arguments must throw TypeError
-PASS MediaStream interface: new MediaStream() must inherit property "addTrack(MediaStreamTrack)" with the proper type
-PASS MediaStream interface: calling addTrack(MediaStreamTrack) on new MediaStream() with too few arguments must throw TypeError
-PASS MediaStream interface: new MediaStream() must inherit property "removeTrack(MediaStreamTrack)" with the proper type
-PASS MediaStream interface: calling removeTrack(MediaStreamTrack) on new MediaStream() with too few arguments must throw TypeError
-PASS MediaStream interface: new MediaStream() must inherit property "clone()" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "active" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "onaddtrack" with the proper type
-PASS MediaStream interface: new MediaStream() must inherit property "onremovetrack" with the proper type
-PASS MediaStreamTrack interface: existence and properties of interface object
-PASS MediaStreamTrack interface object length
-PASS MediaStreamTrack interface object name
-PASS MediaStreamTrack interface: existence and properties of interface prototype object
-PASS MediaStreamTrack interface: existence and properties of interface prototype object's "constructor" property
-PASS MediaStreamTrack interface: existence and properties of interface prototype object's @@unscopables property
-PASS MediaStreamTrack interface: attribute kind
-PASS MediaStreamTrack interface: attribute id
-PASS MediaStreamTrack interface: attribute label
-PASS MediaStreamTrack interface: attribute enabled
-PASS MediaStreamTrack interface: attribute muted
-PASS MediaStreamTrack interface: attribute onmute
-PASS MediaStreamTrack interface: attribute onunmute
-PASS MediaStreamTrack interface: attribute readyState
-PASS MediaStreamTrack interface: attribute onended
-PASS MediaStreamTrack interface: operation clone()
-PASS MediaStreamTrack interface: operation stop()
-PASS MediaStreamTrack interface: operation getCapabilities()
-PASS MediaStreamTrack interface: operation getConstraints()
-PASS MediaStreamTrack interface: operation getSettings()
-PASS MediaStreamTrack interface: operation applyConstraints(MediaTrackConstraints)
-FAIL MediaStreamTrack interface: attribute onoverconstrained assert_true: The prototype object must have a property "onoverconstrained" expected true got false
-PASS MediaStreamTrack must be primary interface of [object MediaStreamTrack]
-PASS Stringification of [object MediaStreamTrack]
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "kind" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "id" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "label" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "enabled" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "muted" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "onmute" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "onunmute" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "readyState" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "onended" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "clone()" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "stop()" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "getCapabilities()" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "getConstraints()" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "getSettings()" with the proper type
-PASS MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "applyConstraints(MediaTrackConstraints)" with the proper type
-PASS MediaStreamTrack interface: calling applyConstraints(MediaTrackConstraints) on [object MediaStreamTrack] with too few arguments must throw TypeError
-FAIL MediaStreamTrack interface: [object MediaStreamTrack] must inherit property "onoverconstrained" with the proper type assert_inherits: property "onoverconstrained" not found in prototype chain
-PASS MediaStreamTrackEvent interface: existence and properties of interface object
-PASS MediaStreamTrackEvent interface object length
-PASS MediaStreamTrackEvent interface object name
-PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object
-PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's "constructor" property
-PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's @@unscopables property
-PASS MediaStreamTrackEvent interface: attribute track
-PASS MediaStreamTrackEvent must be primary interface of [object MediaStreamTrackEvent]
-PASS Stringification of [object MediaStreamTrackEvent]
-PASS MediaStreamTrackEvent interface: [object MediaStreamTrackEvent] must inherit property "track" with the proper type
-FAIL OverconstrainedErrorEvent interface: existence and properties of interface object assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent interface object length assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent interface object name assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent interface: existence and properties of interface prototype object assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent interface: attribute error assert_own_property: self does not have own property "OverconstrainedErrorEvent" expected property "OverconstrainedErrorEvent" missing
-FAIL OverconstrainedErrorEvent must be primary interface of new OverconstrainedErrorEvent("type", {}) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: OverconstrainedErrorEvent is not defined"
-FAIL Stringification of new OverconstrainedErrorEvent("type", {}) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: OverconstrainedErrorEvent is not defined"
-FAIL OverconstrainedErrorEvent interface: new OverconstrainedErrorEvent("type", {}) must inherit property "error" with the proper type assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: OverconstrainedErrorEvent is not defined"
-PASS MediaDevices interface: existence and properties of interface object
-PASS MediaDevices interface object length
-PASS MediaDevices interface object name
-PASS MediaDevices interface: existence and properties of interface prototype object
-PASS MediaDevices interface: existence and properties of interface prototype object's "constructor" property
-PASS MediaDevices interface: existence and properties of interface prototype object's @@unscopables property
-PASS MediaDevices interface: attribute ondevicechange
-PASS MediaDevices interface: operation enumerateDevices()
-PASS MediaDevices interface: operation getSupportedConstraints()
-PASS MediaDevices interface: operation getUserMedia(MediaStreamConstraints)
-PASS MediaDevices must be primary interface of navigator.mediaDevices
-PASS Stringification of navigator.mediaDevices
-PASS MediaDevices interface: navigator.mediaDevices must inherit property "ondevicechange" with the proper type
-PASS MediaDevices interface: navigator.mediaDevices must inherit property "enumerateDevices()" with the proper type
-PASS MediaDevices interface: navigator.mediaDevices must inherit property "getSupportedConstraints()" with the proper type
-PASS MediaDevices interface: navigator.mediaDevices must inherit property "getUserMedia(MediaStreamConstraints)" with the proper type
-PASS MediaDevices interface: calling getUserMedia(MediaStreamConstraints) on navigator.mediaDevices with too few arguments must throw TypeError
-PASS MediaDeviceInfo interface: existence and properties of interface object
-PASS MediaDeviceInfo interface object length
-PASS MediaDeviceInfo interface object name
-PASS MediaDeviceInfo interface: existence and properties of interface prototype object
-PASS MediaDeviceInfo interface: existence and properties of interface prototype object's "constructor" property
-PASS MediaDeviceInfo interface: existence and properties of interface prototype object's @@unscopables property
-PASS MediaDeviceInfo interface: attribute deviceId
-PASS MediaDeviceInfo interface: attribute kind
-PASS MediaDeviceInfo interface: attribute label
-PASS MediaDeviceInfo interface: attribute groupId
-PASS MediaDeviceInfo interface: operation toJSON()
-PASS InputDeviceInfo interface: existence and properties of interface object
-PASS InputDeviceInfo interface object length
-PASS InputDeviceInfo interface object name
-PASS InputDeviceInfo interface: existence and properties of interface prototype object
-PASS InputDeviceInfo interface: existence and properties of interface prototype object's "constructor" property
-PASS InputDeviceInfo interface: existence and properties of interface prototype object's @@unscopables property
-PASS InputDeviceInfo interface: operation getCapabilities()
-PASS InputDeviceInfo must be primary interface of [object InputDeviceInfo]
-PASS Stringification of [object InputDeviceInfo]
-PASS InputDeviceInfo interface: [object InputDeviceInfo] must inherit property "getCapabilities()" with the proper type
-PASS MediaDeviceInfo interface: [object InputDeviceInfo] must inherit property "deviceId" with the proper type
-PASS MediaDeviceInfo interface: [object InputDeviceInfo] must inherit property "kind" with the proper type
-PASS MediaDeviceInfo interface: [object InputDeviceInfo] must inherit property "label" with the proper type
-PASS MediaDeviceInfo interface: [object InputDeviceInfo] must inherit property "groupId" with the proper type
-PASS MediaDeviceInfo interface: [object InputDeviceInfo] must inherit property "toJSON()" with the proper type
-PASS MediaDeviceInfo interface: default toJSON operation on [object InputDeviceInfo]
-PASS Navigator interface: attribute mediaDevices
-PASS Navigator interface: operation getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback)
-PASS Navigator interface: navigator must inherit property "mediaDevices" with the proper type
-PASS Navigator interface: navigator must inherit property "getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback)" with the proper type
-PASS Navigator interface: calling getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback) on navigator with too few arguments must throw TypeError
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/app-change-payment-method.js b/third_party/blink/web_tests/external/wpt/payment-handler/app-change-payment-method.js
new file mode 100644
index 0000000..7a9f7a7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-handler/app-change-payment-method.js
@@ -0,0 +1,30 @@
+self.addEventListener('canmakepayment', (event) => {
+  event.respondWith(true);
+});
+
+async function responder(event) {
+  const methodName = event.methodData[0].supportedMethods;
+  if (!event.changePaymentMethod) {
+    return {
+      methodName,
+      details: {
+        changePaymentMethodReturned:
+          'The changePaymentMethod() method is not implemented.',
+      },
+    };
+  }
+  let changePaymentMethodReturned;
+  try {
+    const response = await event.changePaymentMethod(methodName, {
+      country: 'US',
+    });
+    changePaymentMethodReturned = response;
+  } catch (err) {
+    changePaymentMethodReturned = error.message;
+  }
+  return {methodName, details: {changePaymentMethodReturned}};
+}
+
+self.addEventListener('paymentrequest', (event) => {
+  event.respondWith(responder(event));
+});
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method.https-expected.txt b/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method.https-expected.txt
new file mode 100644
index 0000000..046d3ae
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method.https-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL Tests for PaymentRequestEvent.changePaymentMethod() Uncaught TypeError: Cannot set property 'click' of undefined
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method.https.html b/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method.https.html
new file mode 100644
index 0000000..b85dad6
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/payment-handler/change-payment-method.https.html
@@ -0,0 +1,170 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>Tests for PaymentRequestEvent.changePaymentMethod()</title>
+<link
+  rel="help"
+  href="https://w3c.github.io/payment-handler/#changepaymentmethod-method"
+/>
+<link rel="manifest" href="/payment-handler/basic-card.json" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="register-and-activate-service-worker.js"></script>
+<p>If the payment sheet is shown, please authorize the mock payment.</p>
+<script>
+  async function runTests(registration) {
+    const methodName = window.location.origin + '/payment-handler/payment-app/';
+    await registration.paymentManager.instruments.clear();
+    await registration.paymentManager.instruments.set('instrument-key', {
+      name: 'Instrument Name',
+      method: methodName,
+    });
+
+    promise_test(async (t) => {
+      const request = new PaymentRequest([{supportedMethods: methodName}], {
+        total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}},
+      });
+      // Intentionally do not respond to the 'paymentmethodchange' event.
+      const response = await test_driver.bless('showing a payment sheet', () =>
+        request.show()
+      );
+      const complete_promise = response.complete('success');
+
+      assert_equals(response.details.changePaymentMethodReturned, null);
+
+      return complete_promise;
+    }, 'If updateWith(details) is not run, changePaymentMethod() returns null.');
+
+    promise_test(async (t) => {
+      const request = new PaymentRequest([{supportedMethods: methodName}], {
+        total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}},
+      });
+      request.addEventListener('paymentmethodchange', (event) => {
+        assert_equals(event.methodName, methodName);
+        assert_equals(event.methodDetails.country, 'US');
+        event.updateWith(Promise.reject('Error'));
+      });
+      const response_promise = test_driver.bless(
+        'showing a payment sheet',
+        () => request.show()
+      );
+
+      return promise_rejects(t, 'AbortError', response_promise);
+    }, 'If updateWith(details) is rejected, abort the PaymentRequest.show().');
+
+    promise_test(async (t) => {
+      const request = new PaymentRequest([{supportedMethods: methodName}], {
+        total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}},
+      });
+      request.addEventListener('paymentmethodchange', (event) => {
+        assert_equals(event.methodName, methodName);
+        assert_equals(event.methodDetails.country, 'US');
+        event.updateWith(
+          new Promise(() => {
+            throw 'Error for test';
+          })
+        );
+      });
+      const response_promise = test_driver.bless(
+        'showing a payment sheet',
+        () => request.show()
+      );
+
+      return promise_rejects(t, 'AbortError', response_promise);
+    }, 'If updateWith(details) throws inside of the promise, abort the PaymentRequest.show().');
+
+    promise_test(async (t) => {
+      const request = new PaymentRequest([{supportedMethods: methodName}], {
+        total: {label: 'Total', amount: {currency: 'USD', value: '0.01'}},
+      });
+      request.addEventListener('paymentmethodchange', (event) => {
+        assert_equals(event.methodName, methodName);
+        assert_equals(event.methodDetails.country, 'US');
+        event.updateWith({
+          total: {label: 'Total', amount: {currency: 'GBP', value: '0.02'}},
+          error: 'Error for test',
+          modifiers: [
+            {
+              supportedMethods: methodName,
+              data: {soup: 'potato'},
+              total: {
+                label: 'Modified total',
+                amount: {currency: 'EUR', value: '0.03'},
+              },
+              additionalDisplayItems: [
+                {
+                  label: 'Modified display item',
+                  amount: {currency: 'INR', value: '0.06'},
+                },
+              ],
+            },
+            {
+              supportedMethods: methodName + '2',
+              data: {soup: 'tomato'},
+              total: {
+                label: 'Modified total #2',
+                amount: {currency: 'CHF', value: '0.07'},
+              },
+              additionalDisplayItems: [
+                {
+                  label: 'Modified display item #2',
+                  amount: {currency: 'CAD', value: '0.08'},
+                },
+              ],
+            },
+          ],
+          paymentMethodErrors: {country: 'Unsupported country'},
+          displayItems: [
+            {
+              label: 'Display item',
+              amount: {currency: 'CNY', value: '0.04'},
+            },
+          ],
+          shippingOptions: [
+            {
+              label: 'Shipping option',
+              id: 'id',
+              amount: {currency: 'JPY', value: '0.05'},
+            },
+          ],
+        });
+      });
+      const response = await test_driver.bless('showing a payment sheet', () =>
+        request.show()
+      );
+      const complete_promise = response.complete('success');
+      const changePaymentMethodReturned =
+        response.details.changePaymentMethodReturned;
+
+      assert_equals(changePaymentMethodReturned.total.currency, 'GBP');
+      assert_equals(changePaymentMethodReturned.total.value, '0.02');
+      assert_equals(changePaymentMethodReturned.total.label, undefined);
+      assert_equals(changePaymentMethodReturned.error, 'Error for test');
+      assert_equals(changePaymentMethodReturned.modifiers.length, 1);
+      assert_equals(changePaymentMethodReturned.displayItems, undefined);
+      assert_equals(changePaymentMethodReturned.shippingOptions, undefined);
+      assert_equals(
+        changePaymentMethodReturned.paymentMethodErrors.country,
+        'Unsupported country'
+      );
+
+      const modifier = changePaymentMethodReturned.modifiers[0];
+
+      assert_equals(modifier.supportedMethods, methodName);
+      assert_equals(modifier.data.soup, 'potato');
+      assert_equals(modifier.total.label, '');
+      assert_equals(modifier.total.amount.currency, 'EUR');
+      assert_equals(modifier.total.amount.value, '0.03');
+      assert_equals(modifier.additionalDisplayItems, undefined);
+
+      return complete_promise;
+    }, 'The changePaymentMethod() returns some details from the "paymentmethodchange" event\'s updateWith(details) call.');
+  }
+
+  registerAndActiveServiceWorker(
+    'app-change-payment-method.js',
+    'payment-app/',
+    runTests
+  );
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/performance-timeline/po-observe.html b/third_party/blink/web_tests/external/wpt/performance-timeline/po-observe.html
index 6cc3f1e..a48f0f37 100644
--- a/third_party/blink/web_tests/external/wpt/performance-timeline/po-observe.html
+++ b/third_party/blink/web_tests/external/wpt/performance-timeline/po-observe.html
@@ -51,7 +51,6 @@
       });
       po_nop.observe({
         entryTypes,
-        buffered: false
       });
 
       // this PerformanceObserver should be notified about the previously
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-none-css_touch-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html
similarity index 86%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-none-css_touch-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html
index dec694f..cc96024 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-none-css_touch-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-none-css_touch.html
@@ -7,6 +7,9 @@
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <script src="pointerevent_support.js"></script>
         <style>
             #target0 {
@@ -84,6 +87,7 @@
             function run() {
                 var target0 = document.getElementById("target0");
                 var btnComplete = document.getElementById("btnComplete");
+                var clickIsReceived = false;
 
                 // Check if "touch-action: none" attribute works properly
                 //TA: 15.2
@@ -93,13 +97,25 @@
                         assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
                         assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
                     });
-                    test_touchaction.done();
+                    clickIsReceived = true;
                     updateDescriptionComplete();
                 });
 
                 on_event(target0, 'scroll', function(event) {
                     test_touchaction.step(failOnScroll, "scroll received while touch-action is none");
                 });
+
+                // Inject touch inputs.
+                touchScrollInTarget(target0, 'down').then(function() {
+                    return touchScrollInTarget(target0, 'right');
+                }).then(function() {
+                    return touchTapInTarget(btnComplete);
+                }).then(function() {
+                    test_touchaction.step(function () {
+                        assert_true(clickIsReceived, "click should be received before the test finishes");
+                    }, "click should be received before the test finishes");
+                    test_touchaction.done();
+                });
             }
         </script>
         <h1>touch-action: none</h1>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html
similarity index 85%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html
index e757bae..a91f1f5 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-css_touch.html
@@ -7,6 +7,9 @@
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <script src="pointerevent_support.js"></script>
         <style>
             #target0 {
@@ -83,6 +86,7 @@
             function run() {
                 var target0 = document.getElementById("target0");
                 var btnComplete = document.getElementById("btnComplete");
+                var clickIsReceived = false;
 
                 // Check if "touch-action: pan-x" attribute works properly
                 //TA: 15.3
@@ -92,9 +96,21 @@
                         assert_not_equals(target0.scrollLeft, 0, "scroll x offset should not be 0 in the end of the test");
                         assert_equals(target0.scrollTop, 0, "scroll y offset should be 0 in the end of the test");
                     });
-                    test_touchaction.done();
+                    clickIsReceived = true;
                     updateDescriptionComplete();
                 });
+
+                // Inject touch inputs.
+                touchScrollInTarget(target0, 'down').then(function() {
+                    return touchScrollInTarget(target0, 'right');
+                }).then(function() {
+                    return touchTapInTarget(btnComplete);
+                }).then(function() {
+                    test_touchaction.step(function () {
+                        assert_true(clickIsReceived, "click should be received before the test finishes");
+                    }, "click should be received before the test finishes");
+                    test_touchaction.done();
+                });
             }
         </script>
         <h1>touch-action: pan-x</h1>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html
index e2a4386..d056eb9 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch.html
@@ -7,6 +7,9 @@
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <script src="pointerevent_support.js"></script>
         <style>
             .scroller > div {
@@ -87,6 +90,7 @@
             function run() {
                 var target0 = document.getElementById("target0");
                 var btnComplete = document.getElementById("btnComplete");
+                var clickIsReceived = false;
 
                 // Check if touch-action attribute works properly for embedded divs
                 //
@@ -97,9 +101,21 @@
                         assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
                         assert_not_equals(target0.scrollTop, 0, "scroll y offset should not be 0 in the end of the test");
                     });
-                    test_touchaction.done();
+                    clickIsReceived = true;
                     updateDescriptionComplete();
                 });
+
+                // Inject touch inputs.
+                touchScrollInTarget(target0, 'down').then(function() {
+                    return touchScrollInTarget(target0, 'right');
+                }).then(function() {
+                    return touchTapInTarget(btnComplete);
+                }).then(function() {
+                    test_touchaction.step(function () {
+                        assert_true(clickIsReceived, "click should be received before the test finishes");
+                    }, "click should be received before the test finishes");
+                    test_touchaction.done();
+                });
             }
         </script>
         <h1>behaviour: pan-y</h1>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html
similarity index 86%
rename from third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html
rename to third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html
index 44f89b8e..98168755 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerevent_touch-action-pan-y-css_touch.html
@@ -8,6 +8,9 @@
         <link rel="stylesheet" type="text/css" href="pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
+        <script src="/resources/testdriver.js"></script>
+        <script src="/resources/testdriver-actions.js"></script>
+        <script src="/resources/testdriver-vendor.js"></script>
         <script src="pointerevent_support.js"></script>
         <style>
             #target0 {
@@ -84,6 +87,7 @@
             function run() {
                 var target0 = document.getElementById("target0");
                 var btnComplete = document.getElementById("btnComplete");
+                var clickIsReceived = false;
 
                 // Check if "touch-action: pan-y" attribute works properly
                 //TA: 15.4
@@ -93,9 +97,21 @@
                         assert_equals(target0.scrollLeft, 0, "scroll x offset should be 0 in the end of the test");
                         assert_not_equals(target0.scrollTop, 0, "scroll y offset should not be 0 in the end of the test");
                     });
-                    test_touchaction.done();
+                    clickIsReceived = true;
                     updateDescriptionComplete();
                 });
+
+                // Inject touch inputs.
+                touchScrollInTarget(target0, 'down').then(function() {
+                    return touchScrollInTarget(target0, 'right');
+                }).then(function() {
+                    return touchTapInTarget(btnComplete);
+                }).then(function() {
+                    test_touchaction.step(function () {
+                        assert_true(clickIsReceived, "click should be received before the test finishes");
+                    }, "click should be received before the test finishes");
+                    test_touchaction.done();
+                });
             }
         </script>
         <h1>touch-action: pan-y</h1>
diff --git a/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_coordinates_when_locked.html b/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_coordinates_when_locked.html
index 9dfd5e1..a7932725 100644
--- a/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_coordinates_when_locked.html
+++ b/third_party/blink/web_tests/external/wpt/pointerevents/pointerlock/pointerevent_coordinates_when_locked.html
@@ -3,7 +3,7 @@
     <head>
         <title>Pointer Events pointer lock tests</title>
         <meta name="viewport" content="width=device-width">
-        <link rel="stylesheet" type="text/css" href="/external/wpt/pointerevents/pointerevent_styles.css">
+        <link rel="stylesheet" type="text/css" href="../pointerevent_styles.css">
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
         <script src="/resources/testdriver.js"></script>
@@ -36,21 +36,19 @@
                 var test_pointerEvent = setup_pointerevent_test("Test pointerevent coordinates when pointer is locked", ['mouse']);
                 var div1 = document.getElementById("target");
 
-                on_event(div1, 'pointerdown', function(event) {
+                on_event(div1, 'click', function(event) {
                     if (test_state == kStateInit)
                        div1.requestPointerLock();
-                });
-                on_event(div1, 'pointerup', function(event) {
-                    if (test_state == kStateLocked)
+                    else if (test_state == kStateLocked)
                         document.exitPointerLock();
                 });
                 on_event(div1, 'pointermove', function(event) {
                     if (test_state == kStateLocked) {
                         test_pointerEvent.step(function() {
-                            assert_equals(last_pointer_client_pos['x'], event.clientX)
-                            assert_equals(last_pointer_client_pos['y'], event.clientY)
-                            assert_equals(last_pointer_screen_pos['x'], event.screenX)
-                            assert_equals(last_pointer_screen_pos['y'], event.screenY)
+                            assert_equals(event.clientX, last_pointer_client_pos['x'], 'clientX')
+                            assert_equals(event.clientY, last_pointer_client_pos['y'], 'clientY')
+                            assert_equals(event.screenX, last_pointer_screen_pos['x'], 'screenX')
+                            assert_equals(event.screenY, last_pointer_screen_pos['y'], 'screenY')
                         });
                     } else {
                         last_pointer_client_pos = {'x': event.clientX, 'y': event.clientY}
@@ -63,6 +61,17 @@
                         test_pointerEvent.step(function() {
                             assert_equals(document.pointerLockElement, div1, "document.pointerLockElement should be div1.");
                         });
+
+                        var actions = new test_driver.Actions();
+                        pos_x = div1.offsetWidth / 2;
+                        pos_y = div1.offsetHeight / 2;
+                        for (var i = 0; i < 10; i++) {
+                            // Move left and up.
+                            pos_x += 10;
+                            pos_y -= 10;
+                            actions.pointerMove(pos_x, pos_y, {origin: div1});
+                        }
+                        actions.pointerDown().pointerUp().send();
                     } else if (test_state == kStateLocked) {
                         test_state = kStateUnlocked;
                         test_pointerEvent.step(function() {
@@ -72,18 +81,7 @@
                     }
                 });
 
-                var actions = new test_driver.Actions();
-                actions.pointerMove(/* x = */ 0, /* y = */ 0, {origin: div1}).pointerDown();
-
-                pos_x = div1.offsetWidth / 2;
-                pos_y = div1.offsetHeight / 2;
-                for (var i = 0; i < 10; i++) {
-                    // Alternatively move left/right and up/down.
-                    pos_x += ((-1)**i) * i * 10;
-                    pos_y -= ((-1)**i) * i * 10;
-                    actions.pointerMove(pos_x, pos_y, {origin: div1});
-                }
-                actions.pointerUp().send();
+                new test_driver.Actions().pointerMove(/* x = */ 0, /* y = */ 0, {origin: div1}).pointerDown().pointerUp().send();
             }
         </script>
     </head>
@@ -93,16 +91,16 @@
         <h4>
             Test Description: This test checks the pointer event coordinates stays unchanged when pointer is locked.
             <ol>
-                 <li>Press left button down on the green rectangle and hold it.</li>
-                 <li>Move the mouse inside the green rectangle.</li>
-                 <li>Release mouse button. </li>
+                 <li>Click left mouse button on the green rectangle.</li>
+                 <li>Move the mouse around.</li>
+                 <li>Click left mouse button again. </li>
             </ol>
             </ol>
 
             Test passes if the proper behavior of the events is observed.
         </h4>
         <div id="testContainer">
-            <div id="target" style="width:800px;height:250px;background:green"></div>
+            <div id="target" style="width:200px;height:200px;background:green"></div>
         </div>
         <div class="spacer"></div>
     </body>
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-embed.html b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-embed.html
new file mode 100644
index 0000000..bbba46c5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-embed.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<meta name=timeout content=long>
+<title>Resource Timing embed navigate - back button navigation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/nested-contexts.js"></script>
+<script>
+    open_test_window("resources/embed-navigate-back.html",  "Test that embed navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/embed-navigate-back.html?crossorigin",  "Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/embed-navigate.html",  "Test that embed navigations are not observable by the parent");
+    open_test_window("resources/embed-navigate.html?crossorigin",  "Test that crossorigin embed navigations are not observable by the parent");
+    open_test_window("resources/embed-refresh.html",  "Test that embed refreshes are not observable by the parent");
+    open_test_window("resources/embed-refresh.html?crossorigin",  "Test that crossorigin embed refreshes are not observable by the parent");
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-iframe.html b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-iframe.html
new file mode 100644
index 0000000..86a8328
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-iframe.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<meta name=timeout content=long>
+<title>Resource Timing embed navigate - back button navigation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/nested-contexts.js"></script>
+<script>
+    open_test_window("resources/iframe-navigate-back.html",  "Test that iframe navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/iframe-navigate-back.html?crossorigin",  "Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/iframe-navigate.html",  "Test that iframe navigations are not observable by the parent");
+    open_test_window("resources/iframe-navigate.html?crossorigin",  "Test that crossorigin iframe navigations are not observable by the parent");
+    open_test_window("resources/iframe-refresh.html",  "Test that iframe refreshes are not observable by the parent");
+    open_test_window("resources/iframe-refresh.html?crossorigin",  "Test that crossorigin iframe refreshes are not observable by the parent");
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-object.html b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-object.html
new file mode 100644
index 0000000..20cceea
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations-object.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8" />
+<meta name=timeout content=long>
+<title>Resource Timing embed navigate - back button navigation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="resources/nested-contexts.js"></script>
+<script>
+    open_test_window("resources/object-navigate-back.html",  "Test that object navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/object-navigate-back.html?crossorigin",  "Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent");
+    open_test_window("resources/object-navigate.html",  "Test that object navigations are not observable by the parent");
+    open_test_window("resources/object-navigate.html?crossorigin",  "Test that crossorigin object navigations are not observable by the parent");
+    open_test_window("resources/object-refresh.html",  "Test that object refreshes are not observable by the parent");
+    open_test_window("resources/object-refresh.html?crossorigin",  "Test that crossorigin object refreshes are not observable by the parent");
+</script>
+
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations.html b/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations.html
deleted file mode 100644
index 483cc5b..0000000
--- a/third_party/blink/web_tests/external/wpt/resource-timing/nested-context-navigations.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8" />
-<meta name=timeout content=long>
-<title>Resource Timing embed navigate - back button navigation</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/get-host-info.sub.js"></script>
-<script src="resources/nested-contexts.js"></script>
-<script>
-    open_test_window("resources/embed-navigate-back.html",  "Test that embed navigations are not observable by the parent, even after history navigations by the parent");
-    open_test_window("resources/embed-navigate-back.html?crossorigin",  "Test that crossorigin embed navigations are not observable by the parent, even after history navigations by the parent");
-    open_test_window("resources/embed-navigate.html",  "Test that embed navigations are not observable by the parent");
-    open_test_window("resources/embed-navigate.html?crossorigin",  "Test that crossorigin embed navigations are not observable by the parent");
-    open_test_window("resources/embed-refresh.html",  "Test that embed refreshes are not observable by the parent");
-    open_test_window("resources/embed-refresh.html?crossorigin",  "Test that crossorigin embed refreshes are not observable by the parent");
-    open_test_window("resources/iframe-navigate-back.html",  "Test that iframe navigations are not observable by the parent, even after history navigations by the parent");
-    open_test_window("resources/iframe-navigate-back.html?crossorigin",  "Test that crossorigin iframe navigations are not observable by the parent, even after history navigations by the parent");
-    open_test_window("resources/iframe-navigate.html",  "Test that iframe navigations are not observable by the parent");
-    open_test_window("resources/iframe-navigate.html?crossorigin",  "Test that crossorigin iframe navigations are not observable by the parent");
-    open_test_window("resources/iframe-refresh.html",  "Test that iframe refreshes are not observable by the parent");
-    open_test_window("resources/iframe-refresh.html?crossorigin",  "Test that crossorigin iframe refreshes are not observable by the parent");
-    open_test_window("resources/object-navigate-back.html",  "Test that object navigations are not observable by the parent, even after history navigations by the parent");
-    open_test_window("resources/object-navigate-back.html?crossorigin",  "Test that crossorigin object navigations are not observable by the parent, even after history navigations by the parent");
-    open_test_window("resources/object-navigate.html",  "Test that object navigations are not observable by the parent");
-    open_test_window("resources/object-navigate.html?crossorigin",  "Test that crossorigin object navigations are not observable by the parent");
-    open_test_window("resources/object-refresh.html",  "Test that object refreshes are not observable by the parent");
-    open_test_window("resources/object-refresh.html?crossorigin",  "Test that crossorigin object refreshes are not observable by the parent");
-</script>
-
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/redirects.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/redirects.sub.html
index 0e3f405e..d3d4f75 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/redirects.sub.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/redirects.sub.html
@@ -13,7 +13,7 @@
 let iframe;
 const redirect_url = 'common/redirect.py';
 const url_prefix = redirect_url + '?location=/resource-timing/resources/';
-const https_url_prefix = redirect_url + '?location=https://{{hosts[][www]}}:{{ports[https][0]}}/resource-timing/resources/';
+const https_url_prefix = redirect_url + '?location=https://{{hosts[alt][]}}:{{ports[https][0]}}/resource-timing/resources/';
 function setup_iframe() {
     const iframe_content =
         '<link rel="stylesheet" href="/' + url_prefix + 'resource_timing_test0.css"></link>' +
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https.sub.html
index cf49fb9..21f1f02a 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https.sub.html
@@ -2,7 +2,7 @@
 <script>
 function request() {
   var client = new XMLHttpRequest,
-      baseurl = "https://{{hosts[][www]}}:{{ports[https][0]}}{{location[pathname]}}",
+      baseurl = "https://{{hosts[alt][]}}:{{ports[https][0]}}{{location[pathname]}}",
       url = new URL("fake_responses.py", baseurl).href;
     client.open("GET", url, false)
     client.send(null)
diff --git a/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https_redirect.sub.html b/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https_redirect.sub.html
index c55e037d..2ee92b2a 100644
--- a/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https_redirect.sub.html
+++ b/third_party/blink/web_tests/external/wpt/resource-timing/resources/fake_responses_https_redirect.sub.html
@@ -2,7 +2,7 @@
 <script>
 function request() {
   var client = new XMLHttpRequest,
-      baseurl = "http://{{hosts[][www]}}:{{ports[http][0]}}{{location[pathname]}}",
+      baseurl = "http://{{hosts[alt][]}}:{{ports[http][0]}}{{location[pathname]}}",
       subresource = "fake_responses.py",
       redirecturl = new URL(subresource, "https://{{hosts[][www]}}:{{ports[https][0]}}{{location[pathname]}}").href,
       url = new URL(subresource + "?redirect=" + redirecturl, baseurl).href;
diff --git a/third_party/blink/web_tests/external/wpt/tools/ci/ci_wptrunner_infrastructure.sh b/third_party/blink/web_tests/external/wpt/tools/ci/ci_wptrunner_infrastructure.sh
index f3ce3e7..e5b485d 100755
--- a/third_party/blink/web_tests/external/wpt/tools/ci/ci_wptrunner_infrastructure.sh
+++ b/third_party/blink/web_tests/external/wpt/tools/ci/ci_wptrunner_infrastructure.sh
@@ -25,7 +25,7 @@
     for PRODUCT in "${PRODUCTS[@]}"; do
         if [[ "$PRODUCT" == "chrome" ]]; then
             add_wpt_hosts
-            test_infrastructure "--binary=$(which google-chrome-unstable)"
+            test_infrastructure "--binary=$(which google-chrome-unstable) --channel dev"
         else
             test_infrastructure
         fi
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/item.py b/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
index 1556bfa..f18e5ba6 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/item.py
@@ -105,6 +105,8 @@
 
 
 class TestharnessTest(URLManifestItem):
+    __slots__ = ()
+
     item_type = "testharness"
 
     @property
@@ -162,10 +164,15 @@
 
     @property
     def fuzzy(self):
-        rv = self._extras.get("fuzzy", [])
-        if isinstance(rv, list):
-            return {tuple(item[0]): item[1]
-                    for item in self._extras.get("fuzzy", [])}
+        fuzzy = self._extras.get("fuzzy", {})
+        if not isinstance(fuzzy, list):
+            return fuzzy
+
+        rv = {}
+        for k, v in fuzzy:
+            if k is not None:
+                k = tuple(k)
+            rv[k] = v
         return rv
 
     def to_json(self):
@@ -207,30 +214,44 @@
 
 
 class RefTestNode(RefTestBase):
+    __slots__ = ()
+
     item_type = "reftest_node"
 
 
 class RefTest(RefTestBase):
+    __slots__ = ()
+
     item_type = "reftest"
 
 
 class ManualTest(URLManifestItem):
+    __slots__ = ()
+
     item_type = "manual"
 
 
 class ConformanceCheckerTest(URLManifestItem):
+    __slots__ = ()
+
     item_type = "conformancechecker"
 
 
 class VisualTest(URLManifestItem):
+    __slots__ = ()
+
     item_type = "visual"
 
 
 class Stub(URLManifestItem):
+    __slots__ = ()
+
     item_type = "stub"
 
 
 class WebDriverSpecTest(URLManifestItem):
+    __slots__ = ()
+
     item_type = "wdspec"
 
     @property
@@ -245,6 +266,8 @@
 
 
 class SupportFile(ManifestItem):
+    __slots__ = ()
+
     item_type = "support"
 
     @property
diff --git a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
index dd2e3627..5dde9374 100644
--- a/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
+++ b/third_party/blink/web_tests/external/wpt/tools/manifest/manifest.py
@@ -483,9 +483,11 @@
                              allow_cached=allow_cached)
         except ManifestVersionMismatch:
             logger.info("Manifest version changed, rebuilding")
+            rebuild = True
 
         if manifest is not None and manifest.url_base != url_base:
             logger.info("Manifest url base did not match, rebuilding")
+            rebuild = True
 
     if manifest is None:
         manifest = Manifest(tests_root, url_base)
diff --git a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
index 0654986..8caf51e 100644
--- a/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
+++ b/third_party/blink/web_tests/external/wpt/tools/requirements_mypy.txt
@@ -1,3 +1,3 @@
 mypy==0.701
 mypy-extensions==0.4.1
-typed-ast==1.3.4
+typed-ast==1.3.5
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py b/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
index 3f578c0..66ad8b50 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/browser.py
@@ -461,36 +461,48 @@
     def find_webdriver(self, channel=None):
         return find_executable("chromedriver")
 
-    def _latest_chromedriver_url(self, browser_binary=None):
-        latest = None
-        chrome_version = self.version(browser_binary)
-        assert chrome_version, "Cannot detect the version of Chrome"
-
-        # Remove channel suffixes (e.g. " dev").
-        chrome_version = chrome_version.split(' ')[0]
+    def _official_chromedriver_url(self, chrome_version):
+        # http://chromedriver.chromium.org/downloads/version-selection
         parts = chrome_version.split(".")
-        if len(parts) == 4:
-            latest_url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s.%s.%s" % tuple(parts[:-1])
+        assert len(parts) == 4
+        latest_url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s.%s.%s" % tuple(parts[:-1])
+        try:
+            latest = get(latest_url).text.strip()
+        except requests.RequestException:
+            latest_url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s" % parts[0]
             try:
                 latest = get(latest_url).text.strip()
             except requests.RequestException:
-                latest_url = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_%s" % parts[0]
-                try:
-                    latest = get(latest_url).text.strip()
-                except requests.RequestException:
-                    pass
-        if latest is None:
-            # Fall back to *Chromium* build archives.
+                return None
+        return "https://chromedriver.storage.googleapis.com/%s/chromedriver_%s.zip" % (
+            latest, self.platform_string())
+
+    def _chromium_chromedriver_url(self, chrome_version):
+        try:
+            # Try to find the Chromium build with the same revision.
             omaha = get("https://omahaproxy.appspot.com/deps.json?version=" + chrome_version).json()
             revision = omaha['chromium_base_position']
             url = "https://storage.googleapis.com/chromium-browser-snapshots/%s/%s/chromedriver_%s.zip" % (
                 self.chromium_platform_string(), revision, self.platform_string())
-        else:
-            url = "https://chromedriver.storage.googleapis.com/%s/chromedriver_%s.zip" % (
-                latest, self.platform_string())
-
+            # Check the status without downloading the content (this is a streaming request).
+            get(url)
+        except requests.RequestException:
+            # Fall back to the tip-of-tree Chromium build.
+            revision_url = "https://storage.googleapis.com/chromium-browser-snapshots/%s/LAST_CHANGE" % (
+                self.chromium_platform_string())
+            revision = get(revision_url).text.strip()
+            url = "https://storage.googleapis.com/chromium-browser-snapshots/%s/%s/chromedriver_%s.zip" % (
+                self.chromium_platform_string(), revision, self.platform_string())
         return url
 
+    def _latest_chromedriver_url(self, browser_binary=None):
+        chrome_version = self.version(browser_binary)
+        assert chrome_version, "Cannot detect the version of Chrome"
+        # Remove channel suffixes (e.g. " dev").
+        chrome_version = chrome_version.split(' ')[0]
+        return (self._official_chromedriver_url(chrome_version) or
+                self._chromium_chromedriver_url(chrome_version))
+
     def install_webdriver(self, dest=None, channel=None, browser_binary=None):
         if dest is None:
             dest = os.pwd
diff --git a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
index c54d5aa..c0cfa58 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wpt/run.py
@@ -277,6 +277,8 @@
         if kwargs["browser_channel"] == "dev":
             logger.info("Automatically turning on experimental features for Chrome Dev")
             kwargs["binary_args"].append("--enable-experimental-web-platform-features")
+            # HACK(Hexcles): work around https://github.com/web-platform-tests/wpt/issues/16448
+            kwargs["webdriver_args"].append("--disable-build-check")
 
 
 class ChromeAndroid(BrowserSetup):
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/fennec.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/fennec.py
index 45c83d9..9414ff2 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/fennec.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/browsers/fennec.py
@@ -68,7 +68,8 @@
 
 
 def run_info_extras(**kwargs):
-    rv = {"e10s": False,
+    package = kwargs["package_name"]
+    rv = {"e10s": True if package is not None and "geckoview" in package else False,
           "headless": False,
           "sw-e10s": False}
     rv.update(run_info_browser_version(kwargs["binary"]))
@@ -110,6 +111,7 @@
         self.device_serial = device_serial
         self.tests_root = kwargs["tests_root"]
         self.install_fonts = kwargs["install_fonts"]
+        self.stackwalk_binary = kwargs["stackwalk_binary"]
 
     @property
     def package_name(self):
@@ -220,3 +222,8 @@
             # browser to shut down. This allows the leak log to be written
             self.runner.stop()
         self.logger.debug("stopped")
+
+    def check_crash(self, process, test):
+        if not os.environ.get("MINIDUMP_STACKWALK", "") and self.stackwalk_binary:
+            os.environ["MINIDUMP_STACKWALK"] = self.stackwalk_binary
+        return self.runner.check_for_crashes()
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
index f35c03a3..d1c123a 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/base.py
@@ -9,8 +9,6 @@
 from six.moves.urllib.parse import urljoin, urlsplit, urlunsplit
 from abc import ABCMeta, abstractmethod
 
-from PIL import Image, ImageChops, ImageStat
-
 from ..testrunner import Stop
 from .protocol import Protocol, BaseProtocolPart
 
@@ -311,11 +309,15 @@
             self.logger.info("Allowed %s pixels different, maximum difference per channel %s" %
                              ("-".join(str(item) for item in allowed_different),
                               "-".join(str(item) for item in allowed_per_channel)))
-            equal = (allowed_per_channel[0] <= max_per_channel <= allowed_per_channel[1] and
-                     allowed_different[0] <= pixels_different <= allowed_different[1])
+            equal = ((pixels_different == 0 and allowed_different[0] == 0) or
+                     (max_per_channel == 0 and allowed_per_channel[0] == 0) or
+                     (allowed_per_channel[0] <= max_per_channel <= allowed_per_channel[1] and
+                      allowed_different[0] <= pixels_different <= allowed_different[1]))
         return equal if relation == "==" else not equal
 
     def get_differences(self, screenshots):
+        from PIL import Image, ImageChops, ImageStat
+
         lhs = Image.open(io.BytesIO(base64.b64decode(screenshots[0]))).convert("RGB")
         rhs = Image.open(io.BytesIO(base64.b64decode(screenshots[1]))).convert("RGB")
         diff = ImageChops.difference(lhs, rhs)
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
index 0b0068f..8ceb992 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executormarionette.py
@@ -708,7 +708,7 @@
 
         format_map = {"url": strip_server(url)}
 
-        protocol.base.execute_script("window.open('about:blank', '%s', 'noopener')" % self.window_id)
+        protocol.base.execute_script("window.open(undefined, '%s', 'noopener')" % self.window_id)
         test_window = protocol.testharness.get_test_window(self.window_id, parent_window,
                                                            timeout=10*self.timeout_multiplier)
         self.protocol.base.set_window(test_window)
@@ -897,7 +897,8 @@
                 # with after closing a window we need to give a new window
                 # focus
                 handles = self.executor.protocol.marionette.window_handles
-                self.executor.protocol.marionette.switch_to_window(handles[0])
+                if handles:
+                    self.executor.protocol.marionette.switch_to_window(handles[0])
         except Exception as e:
             # Ignore errors during teardown
             self.logger.warning(traceback.format_exc(e))
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js
index 8d9b296f..3ac142e6 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js
+++ b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js
@@ -1175,18 +1175,6 @@
       { type: 'discrete', options: [ [ 'auto', 'smooth' ] ] }
     ]
   },
-  'scroll-snap-type-x': {
-    // https://developer.mozilla.org/en/docs/Web/CSS/scroll-snap-type-x
-    types: [
-      { type: 'discrete', options: [ [ 'mandatory', 'proximity' ] ] }
-    ]
-  },
-  'scroll-snap-type-y': {
-    // https://developer.mozilla.org/en/docs/Web/CSS/scroll-snap-type-y
-    types: [
-      { type: 'discrete', options: [ [ 'mandatory', 'proximity' ] ] }
-    ]
-  },
   'shape-outside': {
     // http://dev.w3.org/csswg/css-shapes/#propdef-shape-outside
     types: [
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands-expected.txt
new file mode 100644
index 0000000..03400ec3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands-expected.txt
@@ -0,0 +1,4 @@
+This is a testharness.js-based test.
+FAIL It should be possible to animate the all shorthand assert_approx_equals: Should be half way through an opacity animation expected 0.5 +/- 0.0001 but got 0
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html
new file mode 100644
index 0000000..ff62a23b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/keyframe-effects/computed-keyframes-shorthands.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Calculating computed keyframes: Shorthand properties</title>
+<link rel="help" href="https://drafts.csswg.org/web-animations-1/#calculating-computed-keyframes">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../testcommon.js"></script>
+<body>
+<div id="log"></div>
+<div id="target"></div>
+<script>
+'use strict';
+
+test(t => {
+  const div = createDiv(t);
+  div.style.opacity = '0';
+
+  const animation = div.animate({ all: 'initial' }, 100 * MS_PER_SEC);
+  animation.currentTime = 50 * MS_PER_SEC;
+
+  assert_approx_equals(
+    parseFloat(getComputedStyle(div).opacity),
+    0.5,
+    0.0001,
+    'Should be half way through an opacity animation'
+  );
+}, 'It should be possible to animate the all shorthand');
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt
index 665e3cb..6606b51 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 133 tests; 125 PASS, 8 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 135 tests; 125 PASS, 10 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS Element.animate() creates an Animation object
 PASS Element.animate() creates an Animation object in the relevant realm of the target element
 PASS Element.animate() creates an Animation object with a KeyframeEffect
@@ -132,6 +132,8 @@
 FAIL Element.animate() calls play on the Animation assert_equals: expected "running" but got "pending"
 PASS Element.animate() does NOT trigger a style change event
 PASS CSSPseudoElement.animate() creates an Animation object
+FAIL CSSPseudoElement.animate() creates an Animation object for ::marker Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to parse the rule '.pseudo::marker{animation: anim 10s; content: '';}'.
 PASS CSSPseudoElement.animate() creates an Animation object targeting to the correct CSSPseudoElement object
+FAIL CSSPseudoElement.animate() creates an Animation object targeting to the correct CSSPseudoElement object for ::marker Failed to execute 'insertRule' on 'CSSStyleSheet': Failed to parse the rule '.pseudo::marker{animation: anim 10s; content: '';}'.
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate.html b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate.html
index b7c590e..fcf753b 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate.html
+++ b/third_party/blink/web_tests/external/wpt/web-animations/interfaces/Animatable/animate.html
@@ -244,11 +244,25 @@
 }, 'CSSPseudoElement.animate() creates an Animation object');
 
 test(t => {
+  const pseudoTarget = getPseudoElement(t, 'marker');
+  const anim = pseudoTarget.animate(null);
+  assert_class_string(anim, 'Animation', 'The returned object is an Animation for ::marker');
+}, 'CSSPseudoElement.animate() creates an Animation object for ::marker');
+
+test(t => {
   const pseudoTarget = getPseudoElement(t, 'before');
   const anim = pseudoTarget.animate(null);
   assert_equals(anim.effect.target, pseudoTarget,
                 'The returned Animation targets to the correct object');
 }, 'CSSPseudoElement.animate() creates an Animation object targeting ' +
    'to the correct CSSPseudoElement object');
+
+test(t => {
+  const pseudoTarget = getPseudoElement(t, 'marker');
+  const anim = pseudoTarget.animate(null);
+  assert_equals(anim.effect.target, pseudoTarget,
+                'The returned Animation targets to the correct object for ::marker');
+}, 'CSSPseudoElement.animate() creates an Animation object targeting ' +
+   'to the correct CSSPseudoElement object for ::marker');
 </script>
 </body>
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/testcommon.js b/third_party/blink/web_tests/external/wpt/web-animations/testcommon.js
index 889cab8..82b7053 100644
--- a/third_party/blink/web_tests/external/wpt/web-animations/testcommon.js
+++ b/third_party/blink/web_tests/external/wpt/web-animations/testcommon.js
@@ -93,6 +93,9 @@
                       [`.pseudo::${type}`]: 'animation: anim 10s; ' +
                                             'content: \'\';'  });
   const div = createDiv(test);
+  if (type == 'marker') {
+    div.style.display = 'list-item';
+  }
   div.classList.add('pseudo');
   const anims = document.getAnimations();
   assert_true(anims.length >= 1);
diff --git a/third_party/blink/web_tests/external/wpt/webmessaging/message-channels/worker-post-after-close.html b/third_party/blink/web_tests/external/wpt/webmessaging/message-channels/worker-post-after-close.html
new file mode 100644
index 0000000..a2f6d92
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webmessaging/message-channels/worker-post-after-close.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<link rel="help" href="https://html.spec.whatwg.org/multipage/comms.html#messageevent">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+async_test(t => {
+  function workerCode() {
+    onmessage = function(e) {
+      close();
+      var mc = new MessageChannel();
+      mc.port1.onmessage = function() {
+        postMessage("message received!");
+      }
+      mc.port2.postMessage(42);
+      postMessage("done");
+    }
+  }
+
+  var workerBlob = new Blob([workerCode.toString() + ";workerCode();"], {type:"application/javascript"});
+
+  var w = new Worker(URL.createObjectURL(workerBlob));
+  w.postMessage('');
+  w.onmessage = function(e) {
+    if (e.data == "done") {
+      setTimeout(function() {
+        t.done();
+      }, 250);
+    } else {
+      assert_true(false, "A wrong message has been received!");
+    }
+  }
+}, 'MessageChannel/MessagePort should not work after a worker self.close()');
+
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https-expected.txt
new file mode 100644
index 0000000..5ce0b60
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https-expected.txt
@@ -0,0 +1,15 @@
+This is a testharness.js-based test.
+FAIL getIdentityAssertion() should load IdP proxy and return assertion generated pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should succeed if mock-idp.js return different domain and protocol in assertion pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with RTCError('idp-execution-failure') if mock-idp.js throws error assert_equals: Expect initial pc.idpErrorInfo to be null expected (object) null but got (undefined) undefined
+FAIL getIdentityAssertion() should reject with RTCError('idp-bad-script-failure') if IdP proxy script do not register its callback pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with OperationError if mock-idp.js return invalid result pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with RTCError('idp-load-failure') if IdP cannot be loaded pc.setIdentityProvider is not a function
+FAIL getIdentityAssertion() should reject with RTCError('idp-need-login') when mock-idp.js requires login assert_equals: Expect initial pc.idpLoginUrl to be null expected (object) null but got (undefined) undefined
+FAIL setIdentityProvider() with no peerIdentity provided should use peerIdentity value from getConfiguration() pc.setIdentityProvider is not a function
+FAIL Calling setIdentityProvider() multiple times should reset identity assertions pc.setIdentityProvider is not a function
+FAIL createOffer() should return SDP containing identity assertion string if identity provider is set pc.setIdentityProvider is not a function
+FAIL createOffer() should reject with OperationError if identity assertion request fails pc.setIdentityProvider is not a function
+FAIL createAnswer() should reject with OperationError if identity assertion request fails pc.setIdentityProvider is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html
similarity index 91%
rename from third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html
rename to third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html
index 2bd860d9..90178910 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-getIdentityAssertion.sub.https.html
@@ -72,14 +72,14 @@
       assert_equals(args.origin, window.origin,
         'Expect args.origin argument to be the origin of this window');
 
-      assert_equals(env.location,
-        `https://${idpHost}/.well-known/idp-proxy/idp-test.js?foo=bar`,
+      assert_equals(env.location.href,
+        `https://${idpHost}/.well-known/idp-proxy/mock-idp.js?foo=bar`,
         'Expect IdP proxy to be loaded with full well-known URL constructed from provider and protocol');
 
-      assert_equals(env.origin, `https://${idpHost}`,
+      assert_equals(env.location.origin, `https://${idpHost}`,
         'Expect IdP to have its own origin');
 
-      assert_equals(args.options.protocol, 'idp-test.js?foo=bar',
+      assert_equals(args.options.protocol, 'mock-idp.js?foo=bar',
         'Expect options.protocol to be the same value as being passed from here');
 
       assert_equals(args.options.usernameHint, `alice@${idpDomain}`,
@@ -114,7 +114,7 @@
       const { idp, assertion } = parseAssertionResult(assertionResultStr);
       assert_equals(idp.domain, idpDomain2);
       assert_equals(idp.protocol, 'foo');
-      assert_equals(assertion.options.usernameHint, `alice@${idpDomain2}`);
+      assert_equals(assertion.args.options.usernameHint, `alice@${idpDomain2}`);
     });
   }, 'getIdentityAssertion() should succeed if mock-idp.js return different domain and protocol in assertion');
 
@@ -350,12 +350,17 @@
   }, 'createOffer() should return SDP containing identity assertion string if identity provider is set');
 
   /*
-    4.4.2.  Steps to create an offer
-      1.  If the need for an identity assertion was identified when createOffer was
-          invoked, wait for the identity assertion request process to complete.
-      2.  If the identity provider was unable to produce an identity assertion, reject p
-          with a newly created NotReadableError and abort these steps.
-   */
+    6. Requesting Identity Assertions
+
+      The identity assertion request process is triggered by a call to
+      createOffer, createAnswer, or getIdentityAssertion. When these calls are
+      invoked and an identity provider has been set, the following steps are
+      executed:
+
+      ...
+
+      If assertion generation fails, then the promise for the corresponding
+      function call is rejected with a newly created OperationError.   */
   promise_test(t => {
     const pc = new RTCPeerConnection();
     const port = window.location.port;
@@ -366,18 +371,10 @@
       usernameHint: `alice@${idpDomain}`
     });
 
-    return promise_rejects(t, 'NotReadableError',
+    return promise_rejects(t, 'OperationError',
       pc.createOffer());
-  }, 'createOffer() should reject with NotReadableError if identitity assertion request fails');
+  }, 'createOffer() should reject with OperationError if identity assertion request fails');
 
-  /*
-    4.4.2.  Steps to create an answer
-      1.  If the need for an identity assertion was identified when createAnswer was
-          invoked, wait for the identity assertion request process to complete.
-
-      2.  If the identity provider was unable to produce an identity assertion, reject p
-          with a newly created NotReadableError and abort these steps.
-   */
   promise_test(t => {
     const pc = new RTCPeerConnection();
     const port = window.location.port;
@@ -392,9 +389,9 @@
     .createOffer()
     .then(offer => pc.setRemoteDescription(offer))
     .then(() =>
-      promise_rejects(t, 'NotReadableError',
+      promise_rejects(t, 'OperationError',
         pc.createAnswer()));
 
-  }, 'createAnswer() should reject with NotReadableError if identitity assertion request fails');
+  }, 'createAnswer() should reject with OperationError if identity assertion request fails');
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt
new file mode 100644
index 0000000..36044e3b
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https-expected.txt
@@ -0,0 +1,9 @@
+This is a testharness.js-based test.
+FAIL setRemoteDescription() on offer with a=identity should establish peerIdentity promise_test: Unhandled rejection with value: object "TypeError: pc1.setIdentityProvider is not a function"
+FAIL setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with InvalidModificationError promise_test: Unhandled rejection with value: object "TypeError: pc1.setIdentityProvider is not a function"
+FAIL setRemoteDescription() with peerIdentity set and with IdP proxy that return validationAssertion with mismatch contents should reject with OperationError pc1.setIdentityProvider is not a function
+FAIL setRemoteDescription() and peerIdentity should reject with OperationError if IdP return validated identity that is different from its own domain pc1.setIdentityProvider is not a function
+FAIL When IdP throws error and pc has target peer identity, setRemoteDescription() and peerIdentity rejected with RTCError('idp-execution-error') pc1.setIdentityProvider is not a function
+FAIL IdP failure with no target peer identity should have following setRemoteDescription() succeed and replace pc.peerIdentity with a new promise pc1.setIdentityProvider is not a function
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.html b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html
similarity index 87%
rename from third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.html
rename to third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html
index 64ad212..518d5777 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc-identity/RTCPeerConnection-peerIdentity.https.html
@@ -8,7 +8,7 @@
   'use strict';
 
   // Test is based on the following editor draft:
-  //   https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+  //   https://w3c.github.io/webrtc-identity/identity.html
 
   // The tests here interacts with the mock identity provider located at
   //   /.well-known/idp-proxy/mock-idp.js
@@ -54,7 +54,7 @@
       is, there is a current value for peerIdentity ), then this also establishes a
       target peer identity.
    */
-  promise_test(t => {
+  promise_test(async t => {
     const pc1 = new RTCPeerConnection();
     t.add_cleanup(() => pc1.close());
     const pc2 = new RTCPeerConnection();
@@ -70,51 +70,57 @@
       usernameHint: `alice@${idpDomain}`
     });
 
-    return pc1.createOffer()
-    .then(offer => pc2.setRemoteDescription(offer))
-    .then(() => pc2.peerIdentity)
-    .then(identityAssertion => {
-      const { idp, name } = identityAssertion;
-      assert_equals(idp, idpDomain, `Expect IdP domain to be ${idpDomain}`);
-      assert_equals(identityAssertion, `alice@${idpDomain}`,
-        `Expect validated identity from mock-idp.js to be same as specified in usernameHint`);
-    });
+    const peerIdentity = pc2.peerIdentity;
+    await pc2.setRemoteDescription(await pc1.createOffer());
+    const { idp, name } = await peerIdentity;
+    assert_equals(idp, idpHost, `Expect IdP to be ${idpHost}`);
+    assert_equals(name, `alice@${idpDomain}`,
+      `Expect validated identity from mock-idp.js to be same as specified in usernameHint`);
   }, 'setRemoteDescription() on offer with a=identity should establish peerIdentity');
 
   /*
-    4.3.2. setRemoteDescription
-      The target peer identity cannot be changed once set. Once set, if a different
-      value is provided, the user agent MUST reject the returned promise with a newly
-      created InvalidModificationError and abort this operation. The RTCPeerConnection
-      MUST be closed if the validated peer identity does not match the target peer
-      identity.
-   */
-  promise_test(t => {
+    If the peerIdentity configuration is applied to the RTCPeerConnection, this
+    establishes a target peer identity of the provided value. Alternatively, if the
+    RTCPeerConnection has previously authenticated the identity of the peer (that
+    is, the peerIdentity promise is resolved), then this also establishes a
+    target peer identity.
+
+    The target peer identity cannot be changed once set.
+  */
+  promise_test(async t => {
     const port = window.location.port;
     const [idpDomain] = getIdpDomains();
     const idpHost = hostString(idpDomain, port);
 
     const pc1 = new RTCPeerConnection();
     t.add_cleanup(() => pc1.close());
+    pc1.setIdentityProvider(idpHost, {
+      protocol: 'mock-idp.js',
+      usernameHint: `doesnt_matter@${idpDomain}`
+    });
+
     const pc2 = new RTCPeerConnection({
       peerIdentity: `bob@${idpDomain}`
     });
 
     t.add_cleanup(() => pc2.close());
 
-    pc1.setIdentityProvider(idpHost, {
+    pc2.setIdentityProvider(idpHost, {
       protocol: 'mock-idp.js',
       usernameHint: `alice@${idpDomain}`
     });
 
-    return pc1.createOffer()
-    .then(offer =>
-      promise_rejects(t, 'InvalidModificationError',
-        pc2.setRemoteDescription(offer)))
-    .then(() => {
-      assert_true(pc2.signalingState, 'closed',
-        'Expect peer connection to be closed after mismatch peer identity');
-    });
+    const offer = await pc1.createOffer();
+
+    try {
+      await pc2.setRemoteDescription(offer);
+      assert_true(false, "Previous line (sRD) should have thrown!");
+    } catch (e) {
+      assert_equals(e.name, 'InvalidModificationError');
+    }
+
+    assert_true(pc2.signalingState, 'closed',
+      'Expect peer connection to be closed after mismatch peer identity');
   }, 'setRemoteDescription() on offer with a=identity that resolve to value different from target peer identity should reject with InvalidModificationError');
 
   /*
@@ -154,7 +160,7 @@
 
     return pc1.createOffer()
     .then(offer => Promise.all([
-      promise_rejects(t, 'OperationError',
+      promise_rejects(t, 'IdpError',
         pc2.setRemoteDescription(offer)),
       promise_rejects(t, 'OperationError',
         peerIdentityPromise)
@@ -194,10 +200,10 @@
     .then(assertionResultStr => {
       const { idp, assertion } = parseAssertionResult(assertionResultStr);
 
-      assert_equals(idp.domain, idpDomain1,
-        'Sanity check domain of assertion is domain1');
+      assert_equals(idp.domain, idpHost1,
+        'Sanity check domain of assertion is host1');
 
-      assert_equals(assertion.options.usernameHint, `alice@${idpDomain2}`,
+      assert_equals(assertion.args.options.usernameHint, `alice@${idpDomain2}`,
         'Sanity check domain1 is going to validate a domain2 identity');
 
       return pc1.createOffer();
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-send.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-send.html
index 4b8d0c2..76d3524d 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-send.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCDataChannel-send.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCDataChannel.prototype.send</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
new file mode 100644
index 0000000..a0ef9ca7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
@@ -0,0 +1,16 @@
+This is a testharness.js-based test.
+PASS addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError
+PASS addTrack - Calling removeTrack when connection is closed should throw InvalidStateError
+PASS addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError
+PASS addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError
+PASS addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError
+PASS addTrack - Calling removeTrack on different connection should throw InvalidAccessError
+PASS addTransceiver - Calling removeTrack with valid sender should set sender.track to null
+PASS addTrack - Calling removeTrack with valid sender should set sender.track to null
+PASS Calling removeTrack with currentDirection sendrecv should set direction to recvonly
+PASS Calling removeTrack with currentDirection sendonly should set direction to inactive
+PASS Calling removeTrack with currentDirection recvonly should not change direction
+PASS Calling removeTrack with currentDirection inactive should not change direction
+FAIL Calling removeTrack on a stopped transceiver should be a no-op promise_test: Unhandled rejection with value: object "TypeError: pc.getTransceivers(...)[0].stop is not a function"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https.html
index ffb3fec..f2add7f 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-removeTrack.https.html
@@ -292,6 +292,20 @@
     assert_equals(transceiver.currentDirection, 'inactive');
   }, 'Calling removeTrack with currentDirection inactive should not change direction');
 
+  promise_test(async t => {
+    const pc = new RTCPeerConnection();
+    t.add_cleanup(() => pc.close());
+    const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+    t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+    const [track] = stream.getTracks();
+    const sender = pc.addTrack(track, stream);
+
+    pc.getTransceivers()[0].stop();
+    pc.removeTrack(sender);
+    assert_equals(sender.track, track);
+  }, "Calling removeTrack on a stopped transceiver should be a no-op");
+
+
   /*
     TODO
       5.1.  removeTrack
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 07801b9..4b0e913 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
@@ -2,8 +2,8 @@
 PASS setLocalDescription() with valid answer should succeed
 PASS setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer
 PASS setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError
-FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
-FAIL Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" that is not a DOMException InvalidStateError: property "code" is equal to 0, expected 11
+FAIL Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kStable" 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 assert_throws: function "function() { throw e }" threw object "OperationError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': Failed to set local answer sdp: Called in wrong state: kHaveLocalOffer" 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 "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer.html
index e8b3ef5..c97021b0 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setLocalDescription-answer.html
@@ -153,9 +153,9 @@
 
     return pc.createOffer()
     .then(offer =>
-      promise_rejects(t, 'InvalidStateError',
+      promise_rejects(t, 'InvalidModificationError',
         pc.setLocalDescription({ type: 'answer', sdp: offer.sdp })));
-  }, 'Calling setLocalDescription(answer) from stable state should reject with InvalidStateError');
+  }, 'Calling setLocalDescription(answer) from stable state should reject with InvalidModificationError');
 
   promise_test(t => {
     const pc = new RTCPeerConnection();
@@ -167,9 +167,9 @@
       pc.setLocalDescription(offer)
       .then(() => generateAnswer(offer)))
     .then(answer =>
-      promise_rejects(t, 'InvalidStateError',
+      promise_rejects(t, 'InvalidModificationError',
         pc.setLocalDescription(answer)));
-  }, 'Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidStateError');
+  }, 'Calling setLocalDescription(answer) from have-local-offer state should reject with InvalidModificationError');
 
   promise_test(async t => {
     const pc1 = new RTCPeerConnection();
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt
index f338dbc..a6fe1caf 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback-expected.txt
@@ -3,5 +3,6 @@
 FAIL setRemoteDescription(rollback) from stable state should reject with InvalidStateError assert_throws: function "function() { throw e }" threw object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType." that is not a DOMException InvalidStateError: property "code" is equal to undefined, expected 11
 FAIL setRemoteDescription(rollback) should ignore invalid sdp content and succeed promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 FAIL local offer created before setRemoteDescription(remote offer) then rollback should still be usable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
+FAIL local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
index f2dbf0b..25541925 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
@@ -132,4 +132,31 @@
     await pc1.setLocalDescription(offer1);
   }, `local offer created before setRemoteDescription(remote offer) then rollback should still be usable`);
 
+  promise_test(async t => {
+    const pc1 = new RTCPeerConnection();
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+    t.add_cleanup(() => pc2.close());
+
+    const stream = await getNoiseStream({ video: true });
+    t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+    pc1.addTrack(stream.getTracks()[0], stream);
+
+    // We don't use this right away. pc1 has provisionally decided that the
+    // (only) transceiver is bound to level 0.
+    const offer1 = await pc1.createOffer();
+
+    // Create offer from pc2, apply and rollback on pc1
+    const offer2 = await pc2.createOffer({offerToReceiveAudio: true, offerToReceiveVideo: true});
+    // pc1 now should change its mind about what level its video transceiver is
+    // bound to. It was 0, now it is 1.
+    await pc1.setRemoteDescription(offer2);
+
+    // Rolling back should put things back the way they were.
+    await pc1.setRemoteDescription({type: "rollback"});
+
+    // Then try applying pc1's old offer
+    await pc1.setLocalDescription(offer1);
+  }, "local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable");
+
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html
index b5f3c55e..0b560d2 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html
+++ b/third_party/blink/web_tests/external/wpt/webrtc/RTCRtpTransceiver.https.html
@@ -1,5 +1,6 @@
 <!doctype html>
 <meta charset=utf-8>
+<meta name="timeout" content="long">
 <title>RTCRtpTransceiver</title>
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
@@ -990,6 +991,9 @@
       ]);
 
     hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+    pc2.close();
+    hasProps(pc2.getTransceivers(), [{currentDirection: null}]);
   };
 
   const checkSendrecvWithNoSendTrack = async t => {
@@ -1277,8 +1281,10 @@
     pc1.close();
     pc2.close();
 
-    // Still shouldn't throw
-    stoppedTransceiver.stop();
+    // Spec says the closed check comes before the stopped check, so this
+    // should throw now.
+    checkThrows(() => stoppedTransceiver.stop(),
+                "InvalidStateError", "RTCRtpTransceiver.stop() with closed PC");
   };
 
   const checkStopAfterCreateOffer = async t => {
@@ -2182,6 +2188,36 @@
                   "No rejected m-line, because it was reused");
   };
 
+  const checkStopAfterCreateOfferWithReusedMsection = async t => {
+    const pc1 = new RTCPeerConnection();
+    t.add_cleanup(() => pc1.close());
+    const pc2 = new RTCPeerConnection();
+    t.add_cleanup(() => pc2.close());
+
+    const stream = await getNoiseStream({audio: true, video: true});
+    t.add_cleanup(() => stopTracks(stream));
+    const audio = stream.getAudioTracks()[0];
+    const video = stream.getVideoTracks()[0];
+
+    pc1.addTrack(audio, stream);
+    pc1.addTrack(video, stream);
+
+    await offerAnswer(pc1, pc2);
+    pc1.getTransceivers()[1].stop();
+    await offerAnswer(pc1, pc2);
+
+    // Second (video) m-section has been negotiated disabled.
+    const transceiver = pc1.addTransceiver("video");
+    const offer = await pc1.createOffer();
+    transceiver.stop();
+    await pc1.setLocalDescription(offer);
+    await pc2.setRemoteDescription(offer);
+
+    const answer = await pc2.createAnswer();
+    await pc2.setLocalDescription(answer);
+    await pc1.setRemoteDescription(answer);
+  };
+
 const tests = [
   checkAddTransceiverNoTrack,
   checkAddTransceiverWithTrack,
@@ -2217,7 +2253,8 @@
   checkLocalRollback,
   checkRollbackAndSetRemoteOfferWithDifferentType,
   checkRemoteRollback,
-  checkMsectionReuse
+  checkMsectionReuse,
+  checkStopAfterCreateOfferWithReusedMsection
 ].forEach(test => promise_test(test, test.name));
 
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
index eba2b00b..285b97c 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 214 tests; 205 PASS, 9 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 214 tests; 209 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS Partial interface Navigator: original interface defined
 PASS Partial dictionary WebGLContextAttributes: original dictionary defined
@@ -38,10 +38,10 @@
 PASS XRSession interface: attribute onblur
 PASS XRSession interface: attribute onfocus
 PASS XRSession interface: attribute onend
-FAIL XRSession interface: attribute onselect assert_true: The prototype object must have a property "onselect" expected true got false
-FAIL XRSession interface: attribute oninputsourceschange assert_true: The prototype object must have a property "oninputsourceschange" expected true got false
-FAIL XRSession interface: attribute onselectstart assert_true: The prototype object must have a property "onselectstart" expected true got false
-FAIL XRSession interface: attribute onselectend assert_true: The prototype object must have a property "onselectend" expected true got false
+PASS XRSession interface: attribute onselect
+PASS XRSession interface: attribute oninputsourceschange
+PASS XRSession interface: attribute onselectstart
+PASS XRSession interface: attribute onselectend
 PASS XRRenderState interface: existence and properties of interface object
 PASS XRRenderState interface object length
 PASS XRRenderState interface object name
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-abort.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-abort.any.js
new file mode 100644
index 0000000..9b38ccf9
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-abort.any.js
@@ -0,0 +1,15 @@
+// META: title=XMLHttpRequest: abort event
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.onabort = test.step_func(function () {
+    test.done();
+  });
+  client.open("GET", "resources/well-formed.xml");
+  client.send(null);
+  client.abort();
+  test.step_timeout(() => {
+    assert_unreached("onabort not called after 4 ms");
+  }, 4);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-abort.htm b/third_party/blink/web_tests/external/wpt/xhr/event-abort.htm
deleted file mode 100644
index 2f80d1b..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-abort.htm
+++ /dev/null
@@ -1,29 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>XMLHttpRequest: abort event</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onabort" data-tested-assertations="../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-abort" data-tested-assertations="../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#dom-xmlhttprequest-abort" data-tested-assertations="following::ol//ol//ol/li[3]" />
-  </head>
-  <body>
-    <div id="log"></div>
-    <script>
-      var test = async_test();
-      test.step(function() {
-        var client = new XMLHttpRequest();
-        client.onabort = test.step_func(function() {
-          test.done();
-        });
-        client.open("GET", "resources/well-formed.xml");
-        client.send(null);
-        client.abort();
-        test.step_timeout(() => {
-          assert_unreached("onabort not called after 4 ms");
-        }, 4);
-      });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-error.sub.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-error.sub.any.js
new file mode 100644
index 0000000..df63dc05
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-error.sub.any.js
@@ -0,0 +1,13 @@
+// META: title=XMLHttpRequest Test: event - error
+
+async_test(function (t) {
+  var client = new XMLHttpRequest();
+  client.onerror = t.step_func(function (e) {
+    assert_true(e instanceof ProgressEvent);
+    assert_equals(e.type, "error");
+    t.done();
+  });
+
+  client.open("GET", "http://nonexistent.{{host}}:{{ports[http][0]}}");
+  client.send("null");
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-error.sub.html b/third_party/blink/web_tests/external/wpt/xhr/event-error.sub.html
deleted file mode 100644
index 5f27560..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-error.sub.html
+++ /dev/null
@@ -1,25 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>XMLHttpRequest Test: event - error</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<meta name="assert" content="Check if event onerror is fired When the request has failed.">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-
-<div id="log"></div>
-
-<script>
-
-async_test(function (t) {
-  var client = new XMLHttpRequest();
-  client.onerror = t.step_func(function(e) {
-    assert_true(e instanceof ProgressEvent);
-    assert_equals(e.type, "error");
-    t.done();
-  });
-
-  client.open("GET", "http://nonexistent.{{host}}:{{ports[http][0]}}");
-  client.send("null");
-}, document.title);
-
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-load.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-load.any.js
new file mode 100644
index 0000000..72e46a5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-load.any.js
@@ -0,0 +1,21 @@
+// META: title=XMLHttpRequest: The send() method: Fire an event named load (synchronous flag is unset)
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.onload = test.step_func(function (e) {
+    assert_true(e instanceof ProgressEvent);
+    assert_equals(e.type, "load");
+    assert_equals(client.readyState, 4);
+    test.done();
+  });
+  client.onreadystatechange = test.step_func(function () {
+    if (client.readyState !== 4) return;
+
+    test.step_timeout(() => {
+      assert_unreached("Didn't get load event within 4ms of readystatechange==4");
+    }, 4);
+  });
+  client.open("GET", "resources/well-formed.xml");
+  client.send(null);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-load.htm b/third_party/blink/web_tests/external/wpt/xhr/event-load.htm
deleted file mode 100644
index cdd0c5b..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-load.htm
+++ /dev/null
@@ -1,30 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>XMLHttpRequest: The send() method: Fire an event named load (synchronous flag is unset)</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onload" data-tested-assertations="../.." />
-<link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-load" data-tested-assertations="../.." />
-<div id="log"></div>
-
-<script>
-  var test = async_test();
-  test.step(function() {
-    var client = new XMLHttpRequest();
-    client.onload = test.step_func(function(e) {
-      assert_true(e instanceof ProgressEvent);
-      assert_equals(e.type, "load");
-      assert_equals(client.readyState, 4);
-      test.done();
-    });
-    client.onreadystatechange = test.step_func(function() {
-      if (client.readyState !== 4) return;
-
-      test.step_timeout(() => {
-          assert_unreached("Didn't get load event within 4ms of readystatechange==4");
-      }, 4);
-    });
-    client.open("GET", "resources/well-formed.xml");
-    client.send(null);
-  });
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-loadend.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-loadend.any.js
new file mode 100644
index 0000000..7bd1844
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-loadend.any.js
@@ -0,0 +1,19 @@
+// META: title=XMLHttpRequest: loadend event
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.onloadend = test.step_func(function (e) {
+    assert_true(e instanceof ProgressEvent);
+    assert_equals(e.type, "loadend");
+    test.done();
+  });
+  client.onreadystatechange = function () {
+    if (client.readyState !== 4) return;
+    test.step_timeout(() => {
+      assert_unreached("onloadend not called after 100 ms");
+    }, 100);
+  };
+  client.open("GET", "resources/well-formed.xml");
+  client.send(null);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-loadend.htm b/third_party/blink/web_tests/external/wpt/xhr/event-loadend.htm
deleted file mode 100644
index b17d9b9..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-loadend.htm
+++ /dev/null
@@ -1,32 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>XMLHttpRequest: loadend event</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onloadend" data-tested-assertations="/../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-loadend" data-tested-assertations="/../.." />
-  </head>
-  <body>
-    <div id="log"></div>
-    <script>
-      var test = async_test();
-      test.step(function() {
-        var client = new XMLHttpRequest();
-        client.onloadend = test.step_func(function(e) {
-         assert_true(e instanceof ProgressEvent);
-         assert_equals(e.type, "loadend");
-         test.done();
-        });
-        client.onreadystatechange = function() {
-          if (client.readyState !== 4) return;
-          test.step_timeout(() => {
-            assert_unreached("onloadend not called after 100 ms");
-          }, 100);
-        };
-        client.open("GET", "resources/well-formed.xml");
-        client.send(null);
-      });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-loadstart-upload.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-loadstart-upload.any.js
new file mode 100644
index 0000000..0f41cd12
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-loadstart-upload.any.js
@@ -0,0 +1,19 @@
+// META: title=XMLHttpRequest: The send() method: Fire a progress event named loadstart on upload object (synchronous flag is unset)
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.upload.onloadstart = test.step_func(function (e) {
+    assert_true(e instanceof ProgressEvent);
+    assert_equals(e.total, 7, 'upload.onloadstart: event.total');
+    assert_equals(e.loaded, 0, 'upload.onloadstart: event.loaded');
+    assert_equals(e.type, "loadstart");
+    test.done();
+  });
+  client.onreadystatechange = test.step_func(function () {
+    if (client.readyState === 4)
+      assert_unreached("onloadstart not called.");
+  });
+  client.open("POST", "resources/trickle.py?ms=5&count=8");
+  client.send('foo=bar');
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-loadstart-upload.htm b/third_party/blink/web_tests/external/wpt/xhr/event-loadstart-upload.htm
deleted file mode 100644
index 275d418a..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-loadstart-upload.htm
+++ /dev/null
@@ -1,28 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>XMLHttpRequest: The send() method: Fire a progress event named loadstart on upload object (synchronous flag is unset)</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onprogress" data-tested-assertations="../.." />
-<link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-progress" data-tested-assertations="../.." />
-<div id="log"></div>
-<script>
-  var test = async_test();
-  test.step(function() {
-    var client = new XMLHttpRequest();
-    client.upload.onloadstart = test.step_func(function(e) {
-      assert_true(e instanceof ProgressEvent);
-      assert_equals(e.total, 7, 'upload.onloadstart: event.total');
-      assert_equals(e.loaded, 0, 'upload.onloadstart: event.loaded');
-      assert_equals(e.type, "loadstart");
-      test.done();
-    });
-    client.onreadystatechange = test.step_func(function() {
-      if (client.readyState === 4)
-        assert_unreached("onloadstart not called.");
-    });
-    client.open("POST", "resources/trickle.py?ms=5&count=8");
-    client.send('foo=bar');
-  });
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-loadstart.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-loadstart.any.js
new file mode 100644
index 0000000..4778404
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-loadstart.any.js
@@ -0,0 +1,17 @@
+// META: title=XMLHttpRequest: loadstart event
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.onloadstart = test.step_func(function (e) {
+    assert_true(e instanceof ProgressEvent);
+    assert_equals(e.type, "loadstart");
+    assert_equals(client.readyState, 1);
+    test.done();
+  });
+  test.step_timeout(function () {
+    assert_unreached("onloadstart not called after 500 ms");
+  }, 500);
+  client.open("GET", "resources/well-formed.xml");
+  client.send(null);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-loadstart.htm b/third_party/blink/web_tests/external/wpt/xhr/event-loadstart.htm
deleted file mode 100644
index 442be93..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-loadstart.htm
+++ /dev/null
@@ -1,31 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>XMLHttpRequest: loadstart event</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onloadstart" data-tested-assertations="../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-loadstart" data-tested-assertations="../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following-sibling::ol/li[9]/ol/li[2]" />
-  </head>
-  <body>
-    <div id="log"></div>
-    <script>
-      var test = async_test();
-      test.step(function() {
-        var client = new XMLHttpRequest();
-        client.onloadstart = test.step_func(function(e) {
-          assert_true(e instanceof ProgressEvent);
-          assert_equals(e.type, "loadstart");
-          assert_equals(client.readyState, 1);
-          test.done();
-        });
-        test.step_timeout(function () {
-          assert_unreached("onloadstart not called after 500 ms");
-        }, 500);
-        client.open("GET", "resources/well-formed.xml");
-        client.send(null);
-      });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-progress.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-progress.any.js
new file mode 100644
index 0000000..0e7c3a4
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-progress.any.js
@@ -0,0 +1,18 @@
+// META: title=XMLHttpRequest: The send() method: Fire a progress event named progress (synchronous flag is unset)
+// META: timeout=long
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.onprogress = test.step_func(function (e) {
+    assert_true(e instanceof ProgressEvent);
+    assert_equals(e.type, "progress");
+    test.done();
+  });
+  client.onreadystatechange = test.step_func(function () {
+    if (client.readyState === 4)
+      assert_unreached("onprogress not called.");
+  });
+  client.open("GET", "resources/trickle.py?count=4&delay=150");
+  client.send(null);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-progress.htm b/third_party/blink/web_tests/external/wpt/xhr/event-progress.htm
deleted file mode 100644
index 5e9090e..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-progress.htm
+++ /dev/null
@@ -1,27 +0,0 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>XMLHttpRequest: The send() method: Fire a progress event named progress (synchronous flag is unset)</title>
-<meta name="timeout" content="long">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onprogress" data-tested-assertations="../.." />
-<link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-progress" data-tested-assertations="../.." />
-<div id="log"></div>
-<script>
-  var test = async_test();
-  test.step(function() {
-    var client = new XMLHttpRequest();
-    client.onprogress = test.step_func(function(e) {
-      assert_true(e instanceof ProgressEvent);
-      assert_equals(e.type, "progress");
-      test.done();
-    });
-    client.onreadystatechange = test.step_func(function() {
-      if (client.readyState === 4)
-        assert_unreached("onprogress not called.");
-    });
-    client.open("GET", "resources/trickle.py?count=4&delay=150");
-    client.send(null);
-  });
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-readystate-sync-open.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-readystate-sync-open.any.js
new file mode 100644
index 0000000..321635e7
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-readystate-sync-open.any.js
@@ -0,0 +1,23 @@
+// META: title=XMLHttpRequest: open() call fires sync readystate event
+
+const title = "XMLHttpRequest: open() call fires sync readystate event";
+
+test(function () {
+  var client = new XMLHttpRequest()
+  var eventsFired = []
+  client.onreadystatechange = function () {
+    eventsFired.push(client.readyState)
+  }
+  client.open('GET', "...", false)
+  assert_array_equals(eventsFired, [1])
+}, title + ' (sync)');
+
+test(function () {
+  var client = new XMLHttpRequest()
+  var eventsFired = []
+  client.onreadystatechange = function () {
+    eventsFired.push(client.readyState)
+  }
+  client.open('GET', "...", true)
+  assert_array_equals(eventsFired, [1])
+}, title + ' (async)');
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-readystate-sync-open.htm b/third_party/blink/web_tests/external/wpt/xhr/event-readystate-sync-open.htm
deleted file mode 100644
index ae9697e..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-readystate-sync-open.htm
+++ /dev/null
@@ -1,33 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <title>XMLHttpRequest: open() call fires sync readystate event</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#the-open()-method" data-tested-assertations="following::ol[1]/li[13]/ol[1]/li[2]" />
-
-  </head>
-  <body>
-    <div id="log"></div>
-    <script>
-      test(function() {
-        var client = new XMLHttpRequest()
-        var eventsFired = []
-        client.onreadystatechange = function(){
-          eventsFired.push(client.readyState)
-        }
-        client.open('GET', "...", false)
-        assert_array_equals(eventsFired, [1])
-      }, document.title + ' (sync)')
-      test(function() {
-        var client = new XMLHttpRequest()
-        var eventsFired = []
-        client.onreadystatechange = function(){
-          eventsFired.push(client.readyState)
-        }
-        client.open('GET', "...", true)
-        assert_array_equals(eventsFired, [1])
-      }, document.title + ' (async)')
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-readystatechange-loaded.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-readystatechange-loaded.any.js
new file mode 100644
index 0000000..1e4467aa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-readystatechange-loaded.any.js
@@ -0,0 +1,23 @@
+// META: title=XMLHttpRequest: the LOADING state change may be emitted multiple times
+
+var test = async_test();
+
+test.step(function () {
+    var client = new XMLHttpRequest();
+    var countedLoading = 0;
+
+    client.onreadystatechange = test.step_func(function () {
+        if (client.readyState === 3) {
+            countedLoading += 1;
+        }
+
+        if (client.readyState === 4) {
+            assert_greater_than(countedLoading, 1, "LOADING state change may be emitted multiple times");
+
+            test.done();
+        }
+    });
+
+    client.open("GET", "resources/trickle.py?count=10"); // default timeout in trickle.py is 1/2 sec, so this request will take 5 seconds to complete
+    client.send(null);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-readystatechange-loaded.htm b/third_party/blink/web_tests/external/wpt/xhr/event-readystatechange-loaded.htm
deleted file mode 100644
index 6cbcc22..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-readystatechange-loaded.htm
+++ /dev/null
@@ -1,37 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
-    <meta charset="utf-8">
-    <title>XMLHttpRequest: the LOADING state change may be emitted multiple times</title>
-    <meta name="timeout" content="long">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following::ol[1]/li[10]/dt[1]">
-</head>
-
-<div id="log"></div>
-
-<script>
-
-var test = async_test();
-
-test.step(function() {
-    var client = new XMLHttpRequest();
-    var countedLoading = 0;
-
-    client.onreadystatechange = test.step_func(function() {
-        if (client.readyState === 3) {
-            countedLoading += 1;
-        }
-
-        if (client.readyState === 4) {
-            assert_greater_than(countedLoading, 1, "LOADING state change may be emitted multiple times");
-
-            test.done();
-        }
-    });
-
-    client.open("GET", "resources/trickle.py?count=10"); // default timeout in trickle.py is 1/2 sec, so this request will take 5 seconds to complete
-    client.send(null);
-});
-</script>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-timeout-order.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-timeout-order.any.js
new file mode 100644
index 0000000..b35e908
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-timeout-order.any.js
@@ -0,0 +1,21 @@
+// META: title=XMLHttpRequest: event - timeout (order of events)
+// META: script=resources/xmlhttprequest-event-order.js
+
+var test = async_test();
+test.step(function () {
+    var xhr = new XMLHttpRequest();
+    prepare_xhr_for_event_order_test(xhr);
+    xhr.addEventListener("loadend", function () {
+        test.step(function () {
+            assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", 4, "upload.timeout(0,0,false)", "upload.loadend(0,0,false)", "timeout(0,0,false)", "loadend(0,0,false)"]);
+            test.done();
+        });
+    });
+
+    xhr.timeout = 5;
+    xhr.open("POST", "resources/delay.py?ms=20000");
+    xhr.send("Test Message");
+    test.step_timeout(() => {
+        assert_unreached("ontimeout not called.");
+    }, 10);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-timeout-order.htm b/third_party/blink/web_tests/external/wpt/xhr/event-timeout-order.htm
deleted file mode 100644
index d4dc7801..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-timeout-order.htm
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-    <meta name="assert" content="Check the order of events fired when the request has failed.">
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <script src="resources/xmlhttprequest-event-order.js"></script>
-    <title>XMLHttpRequest: event - timeout (order of events)</title>
-</head>
-
-<body>
-    <div id="log"></div>
-
-    <script type="text/javascript">
-        var test = async_test();
-
-        test.step(function()
-        {
-            var xhr = new XMLHttpRequest();
-            prepare_xhr_for_event_order_test(xhr);
-            xhr.addEventListener("loadend", function() {
-                test.step(function() {
-                    assert_xhr_event_order_matches([1, "loadstart(0,0,false)", "upload.loadstart(0,12,true)", 4, "upload.timeout(0,0,false)", "upload.loadend(0,0,false)", "timeout(0,0,false)", "loadend(0,0,false)"]);
-                    test.done();
-                });
-            });
-
-            xhr.timeout = 5;
-            xhr.open("POST", "resources/delay.py?ms=20000");
-            xhr.send("Test Message");
-            test.step_timeout(() => {
-              assert_unreached("ontimeout not called.");
-            }, 10);
-        });
-    </script>
-</body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-timeout.any.js b/third_party/blink/web_tests/external/wpt/xhr/event-timeout.any.js
new file mode 100644
index 0000000..d114b08
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-timeout.any.js
@@ -0,0 +1,18 @@
+// META: title=XMLHttpRequest: timeout event
+
+var test = async_test();
+test.step(function () {
+  var client = new XMLHttpRequest();
+  client.ontimeout = function () {
+    test.step(function () {
+      assert_equals(client.readyState, 4);
+      test.done();
+    });
+  };
+  client.timeout = 5;
+  client.open("GET", "resources/delay.py?ms=20000");
+  client.send(null);
+  test.step_timeout(() => {
+    assert_unreached("ontimeout not called.");
+  }, 10);
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-timeout.htm b/third_party/blink/web_tests/external/wpt/xhr/event-timeout.htm
deleted file mode 100644
index c4021356..0000000
--- a/third_party/blink/web_tests/external/wpt/xhr/event-timeout.htm
+++ /dev/null
@@ -1,34 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>XMLHttpRequest: timeout event</title>
-    <script src="/resources/testharness.js"></script>
-    <script src="/resources/testharnessreport.js"></script>
-    <link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-ontimeout" data-tested-assertations="../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-timeout" data-tested-assertations="../.." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#the-timeout-attribute" data-tested-assertations="following-sibling::ol/li[2]" />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#timeout-error" data-tested-assertations=".." />
-    <link rel="help" href="https://xhr.spec.whatwg.org/#infrastructure-for-the-send()-method" data-tested-assertations="following-sibling::dl//code[contains(@title,'dom-XMLHttpRequest-timeout')]/.. following-sibling::dl//code[contains(@title,'dom-XMLHttpRequest-timeout')]/../following-sibling::dd" />
-  </head>
-  <body>
-    <div id="log"></div>
-    <script>
-      var test = async_test();
-      test.step(function() {
-        var client = new XMLHttpRequest();
-        client.ontimeout = function() {
-          test.step(function() {
-            assert_equals(client.readyState, 4);
-            test.done();
-          });
-        };
-        client.timeout = 5;
-        client.open("GET", "resources/delay.py?ms=20000");
-        client.send(null);
-        test.step_timeout(() => {
-          assert_unreached("ontimeout not called.");
-        }, 10);
-      });
-    </script>
-  </body>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress-crossorigin.htm b/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress-crossorigin.any.js
similarity index 67%
rename from third_party/blink/web_tests/external/wpt/xhr/event-upload-progress-crossorigin.htm
rename to third_party/blink/web_tests/external/wpt/xhr/event-upload-progress-crossorigin.any.js
index 5e558a2..1036f2b1 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress-crossorigin.htm
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress-crossorigin.any.js
@@ -1,14 +1,8 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>XMLHttpRequest: upload progress event for cross-origin requests</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/get-host-info.sub.js"></script>
-<div id="log"></div>
-<script>
+// META: title=XMLHttpRequest: upload progress event for cross-origin requests
+// META: script=/common/get-host-info.sub.js
+
 const remote = get_host_info().HTTP_REMOTE_ORIGIN + "/xhr/resources/corsenabled.py",
-      redirect = "resources/redirect.py?code=307&location=" + remote;
+  redirect = "resources/redirect.py?code=307&location=" + remote;
 
 [remote, redirect].forEach(url => {
   async_test(test => {
@@ -29,5 +23,4 @@
     client.upload.onloadstart = test.unreached_func(); // registered too late
     client.upload.onprogress = test.unreached_func(); // registered too late
   }, "Upload events registered too late (" + url + ")");
-});
-</script>
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress.htm b/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress.any.js
similarity index 68%
rename from third_party/blink/web_tests/external/wpt/xhr/event-upload-progress.htm
rename to third_party/blink/web_tests/external/wpt/xhr/event-upload-progress.any.js
index 697d4cbd..5d15467 100644
--- a/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress.htm
+++ b/third_party/blink/web_tests/external/wpt/xhr/event-upload-progress.any.js
@@ -1,14 +1,8 @@
-<!doctype html>
-<html lang=en>
-<meta charset=utf-8>
-<title>XMLHttpRequest: upload progress event</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/common/get-host-info.sub.js"></script>
-<div id="log"></div>
-<script>
+// META: title=XMLHttpRequest: upload progress event
+// META: script=/common/get-host-info.sub.js
+
 const remote = get_host_info().HTTP_REMOTE_ORIGIN + "/xhr/resources/corsenabled.py",
-      redirect = "resources/redirect.py?code=307&location=" + remote;
+  redirect = "resources/redirect.py?code=307&location=" + remote;
 
 [remote, redirect].forEach(url => {
   async_test(test => {
@@ -29,5 +23,4 @@
     client.upload.onloadstart = test.unreached_func(); // registered too late
     client.upload.onprogress = test.unreached_func(); // registered too late
   }, "Upload events registered too late (" + url + ")");
-});
-</script>
+});
\ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-none-css_touch-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-none-css_touch-manual-automation.js
deleted file mode 100644
index 77e7e61..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-none-css_touch-manual-automation.js
+++ /dev/null
@@ -1,10 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return touchScrollInTarget('#target0', 'down').then(function() {
-    return touchScrollInTarget('#target0', 'right');
-  }).then(function() {
-    btnComplete.click();
-  });
-}
-
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual-automation.js
deleted file mode 100644
index 77e7e61..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-css_touch-manual-automation.js
+++ /dev/null
@@ -1,10 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return touchScrollInTarget('#target0', 'down').then(function() {
-    return touchScrollInTarget('#target0', 'right');
-  }).then(function() {
-    btnComplete.click();
-  });
-}
-
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual-automation.js
deleted file mode 100644
index d22c9b8f..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-x-pan-y-pan-y_touch-manual-automation.js
+++ /dev/null
@@ -1,9 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return touchScrollInTarget('#target0 > div > div', 'down').then(function() {
-    return touchScrollInTarget('#target0 > div > div', 'right');
-  }).then(function() {
-    return touchTapInTarget('#btnComplete');
-  });
-}
diff --git a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual-automation.js b/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual-automation.js
deleted file mode 100644
index 85d90a3..0000000
--- a/third_party/blink/web_tests/external/wpt_automation/pointerevents/pointerevent_touch-action-pan-y-css_touch-manual-automation.js
+++ /dev/null
@@ -1,9 +0,0 @@
-importAutomationScript('/pointerevents/pointerevent_common_input.js');
-
-function inject_input() {
-  return touchScrollInTarget('#target0', 'down').then(function() {
-    return touchScrollInTarget('#target0', 'right');
-  }).then(function() {
-    btnComplete.click();
-  });
-}
diff --git a/third_party/blink/web_tests/fast/loader/document-write-after-form-submit-expected.txt b/third_party/blink/web_tests/fast/loader/document-write-after-form-submit-expected.txt
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/third_party/blink/web_tests/fast/loader/document-write-after-form-submit-expected.txt
@@ -0,0 +1 @@
+PASS
diff --git a/third_party/blink/web_tests/fast/loader/document-write-after-form-submit.html b/third_party/blink/web_tests/fast/loader/document-write-after-form-submit.html
new file mode 100644
index 0000000..e4e06c2
--- /dev/null
+++ b/third_party/blink/web_tests/fast/loader/document-write-after-form-submit.html
@@ -0,0 +1,7 @@
+<form id="f"  method="get" action="resources/pass-and-notify-done.html"></form>
+<script>
+if (window.testRunner)
+  testRunner.dumpAsText();
+f.submit();
+document.write("This should not cancel the form submission");
+</script>
diff --git a/third_party/blink/web_tests/fast/workers/worker-performance-time.html b/third_party/blink/web_tests/fast/workers/worker-performance-time.html
new file mode 100644
index 0000000..5e39ef1e
--- /dev/null
+++ b/third_party/blink/web_tests/fast/workers/worker-performance-time.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Test the timing in the worker to be consistent between animation and performance.now().</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script id="worker" type="text/worker">
+var countWorker = 10;
+function animate(time) {
+  var timeNow = performance.now();
+  countWorker--;
+  self.postMessage([time,timeNow, countWorker]);
+  if(countWorker > 0)
+    requestAnimationFrame(animate);
+};
+
+self.onmessage = function(msg){
+  requestAnimationFrame(animate);
+}
+</script>
+<script>
+async_test(function(t) {
+  var blob = new Blob([document.getElementById("worker").textContent]);
+  var worker = new Worker(URL.createObjectURL(blob));
+  worker.onmessage = t.step_func(function(pairTime) {
+    var time = pairTime.data[0];
+    var timeNow = pairTime.data[1];
+    var count = pairTime.data[2];
+    assert_approx_equals(time, timeNow, 2, "Times must be close enough");
+    if(count == 0)
+      t.done();
+  });
+  worker.postMessage("");
+}, 'Test the timing in the worker to be consistent between animation and performance.now');
+</script>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/html/embedded_content/remove_object_element_with_invalid_data.html b/third_party/blink/web_tests/html/embedded_content/remove_object_element_with_invalid_data.html
new file mode 100644
index 0000000..dfd3c8d
--- /dev/null
+++ b/third_party/blink/web_tests/html/embedded_content/remove_object_element_with_invalid_data.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+"use strict";
+
+async_test((test) => {
+  window.onload = test.step_func_done(() => {
+    let test_div = document.getElementById("test_div");
+    document.body.removeChild(test_div);
+  });
+}, 'Do not crash if an OBJECT element is removed while committing failed navigation.');
+</script>
+</head>
+<body>
+<div id="test_div">
+  <object data="INVALID"></object>
+</div>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/portals/portals-elements-nesting-expected.txt b/third_party/blink/web_tests/http/tests/devtools/portals/portals-elements-nesting-expected.txt
new file mode 100644
index 0000000..3eac774
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/portals/portals-elements-nesting-expected.txt
@@ -0,0 +1,21 @@
+Tests that portals are rendered inline.
+
+
+Running: testSetUp
+
+Running: testRemove
+- <html>
+      <head></head>
+    - <body>
+        - <div>
+            - <portal src="http://devtools.oopif.test:8000/devtools/oopif/resources/empty.html">
+                - #document
+                    - <html>
+                          <head></head>
+                          <body>\n\n</body>
+                      </html>
+              </portal>
+          </div>
+      </body>
+  </html>
+
diff --git a/third_party/blink/web_tests/http/tests/devtools/portals/portals-elements-nesting.js b/third_party/blink/web_tests/http/tests/devtools/portals/portals-elements-nesting.js
new file mode 100644
index 0000000..78605954
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/portals/portals-elements-nesting.js
@@ -0,0 +1,26 @@
+// 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.
+
+(async function() {
+  TestRunner.addResult(`Tests that portals are rendered inline.\n`);
+  await TestRunner.loadModule('elements_test_runner');
+  await TestRunner.showPanel('elements');
+
+  // Save time on style updates.
+  Elements.StylesSidebarPane.prototype.update = function() {};
+  Elements.MetricsSidebarPane.prototype.update = function() {};
+
+  await TestRunner.navigatePromise('resources/portal_host.html');
+
+  TestRunner.runTestSuite([
+    function testSetUp(next) {
+      ElementsTestRunner.expandElementsTree(next);
+    },
+
+    function testRemove(next) {
+      ElementsTestRunner.dumpElementsTree();
+      TestRunner.completeTest();
+    },
+  ]);
+})();
diff --git a/third_party/blink/web_tests/http/tests/devtools/portals/resources/portal_host.html b/third_party/blink/web_tests/http/tests/devtools/portals/resources/portal_host.html
new file mode 100644
index 0000000..c61619f
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/devtools/portals/resources/portal_host.html
@@ -0,0 +1,5 @@
+<body>
+    <div>
+        <portal src="http://devtools.oopif.test:8000/devtools/oopif/resources/empty.html"></portal>
+    </div>
+</body>
diff --git a/third_party/blink/web_tests/http/tests/navigation/frozen-useragent-expected.txt b/third_party/blink/web_tests/http/tests/navigation/frozen-useragent-expected.txt
new file mode 100644
index 0000000..dd65419
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/navigation/frozen-useragent-expected.txt
@@ -0,0 +1,3 @@
+Tests for frozen user agent working properly as defined by https://github.com/WICG/ua-client-hints
+UserAgent should match one of the frozen UA strings: true
+Navigator.platform should match the corresponding frozen user agent: true
diff --git a/third_party/blink/web_tests/http/tests/navigation/frozen-useragent.html b/third_party/blink/web_tests/http/tests/navigation/frozen-useragent.html
new file mode 100644
index 0000000..5ba9994
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/navigation/frozen-useragent.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<body>
+
+  <div>Tests for frozen user agent working properly as defined by https://github.com/WICG/ua-client-hints</div>
+<script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+    }
+
+    var userAgent = navigator.userAgent;
+    var platform = navigator.platform;
+
+    // Validate the user agent string using the following frozen user agent strings found in content/common/user_agent.h:
+    var desktopUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3764.0 Safari/537.36"
+    var frozenUserAgents = [
+      desktopUserAgent,
+      "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3764.0 Safari/537.36",
+      "Mozilla/5.0 (Linux; Android 9; Unspecified Device) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3764.0 Mobile Safari/537.36"
+    ];
+
+    // Platform values should match strings defined in third_party/blink/renderer/core/frame/navigator.cc.
+    var desktopPlatform = "Win32";
+    var mobilePlatform = "Linux armv8l";
+
+    document.write("UserAgent should match one of the frozen UA strings: " + (frozenUserAgents.indexOf(userAgent) > -1) + "<br>");
+
+    var platformMatchesUserAgent;
+    if (userAgent == desktopUserAgent) {
+      platformMatchesUserAgent = (platform == desktopPlatform);
+    } else {
+      platformMatchesUserAgent = (platform == mobilePlatform);
+    }
+
+    // Validate navigator.appVersion and navigator.appCodeName
+    document.write("Navigator.platform should match the corresponding frozen user agent: " +  platformMatchesUserAgent);
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/media/controls/timeline-thumb-shows-on-focus.html b/third_party/blink/web_tests/media/controls/timeline-thumb-shows-on-focus.html
new file mode 100644
index 0000000..6759358
--- /dev/null
+++ b/third_party/blink/web_tests/media/controls/timeline-thumb-shows-on-focus.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<title>Test that the timeline thumb is displayed when the timeline is focused.</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-controls.js"></script>
+<video controls width=500 preload=none src="../content/60_sec_video.webm"></video>
+<script>
+async_test(t => {
+  const video = document.querySelector('video');
+  const timeline = timelineElement(video);
+  const thumb = timelineThumb(video);
+  enableTestMode(video);
+
+  video.addEventListener('loadedmetadata', t.step_func(() => {
+    timeline.focus();
+    setTimeout(t.step_func_done(() => {
+      const thumbStyle = getComputedStyle(thumb);
+      assert_equals(thumbStyle.opacity, '1', 'The thumb should be visible');
+    }));
+  }));
+
+  video.load();
+});
+</script>
+</html>
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html
new file mode 100644
index 0000000..2364b16
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-account-for-clip.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/blink/public/mojom/page/spatial_navigation.mojom.js"></script>
+<script src="../../../../../fast/spatial-navigation/resources/mock-snav-service.js"></script>
+<script src="../../../../../fast/spatial-navigation/resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 130px;
+    height: 130px;
+    border: 1px solid black;
+  }
+
+  #clip {
+    margin: 5px;
+    width: 100px;
+    height: 100px;
+    overflow: hidden;
+    background-color: lightgrey;
+  }
+
+  #target {
+    margin: 20px;
+    height: 50px;
+  }
+
+  pre {
+    position: absolute;
+    top: 400px;
+  }
+
+</style>
+<div tabindex="0">
+  Outer Target
+  <div id="clip" tabindex="0">
+    Clip
+    <div id="target" tabindex="0">Inner Target</div>
+  </div>
+</div>
+
+<script>
+  const target = document.getElementById("target");
+
+  // This test checks that the spatial navigation overlap testing works
+  // correctly in the presence of clipping. The spatial navigation algorithm
+  // attempts to prioritize the inner element when one valid target is fully
+  // contained by another valid target. This test ensures the inner is
+  // considered fully contained even if it has clipped overflow that would
+  // spill outside the outer target.
+  test(() => {
+    assert_true(!!window.internals);
+    snav.triggerMove('Down');
+    assert_equals(window.internals.interestedElement,
+                  target,
+                  "Expected interest to move to |target| element.");
+  }, "Navigation to fully contained but clipped element.");
+</script>
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-does-not-submit.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-does-not-submit.html
new file mode 100644
index 0000000..b4e3cd5
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-does-not-submit.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/blink/public/mojom/page/spatial_navigation.mojom.js"></script>
+<script src="../../../../../fast/spatial-navigation/resources/mock-snav-service.js"></script>
+<script src="../../../../../fast/spatial-navigation/resources/snav-testharness.js"></script>
+
+<form action="javascript:fail();">
+<input type="text" id="first"></input>
+<input type="submit" value="Submit" />
+</form>
+
+<script>
+  function fail() {
+    assert_false(true, "Form should not have been submitted.");
+  }
+  promise_test(async () => {
+    let first = document.getElementById("first");
+
+    snav.triggerMove("Down");
+    await snavCallback();
+
+    assert_false(mockSnavService.canExitFocus,
+                "Should not be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_false(mockSnavService.hasNextFormElement,
+                "Should not be able to move to next form element.");
+
+    eventSender.keyDown('Enter');
+    assert_equals(document.activeElement,
+                  first,
+                  "'second' should be focused.");
+
+    await snav.rAF();
+
+    assert_true(mockSnavService.canExitFocus,
+                "Should be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_true(mockSnavService.hasNextFormElement,
+                 "Should be able to move to next form element.");
+  }, 'Form does not submit when passing spat nav focus.');
+</script>
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state-on-click.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state-on-click.html
index 3fb47bba..09564259 100644
--- a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state-on-click.html
+++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state-on-click.html
@@ -12,58 +12,46 @@
 </form>
 
 <script>
-  async_test((t) => {
+  function notCalled() {
+    assert_false(true, "Should not be called");
+  };
+  mockSnavService.callback = notCalled;
+
+  promise_test(async () => {
     let first = document.getElementById("first");
     let second = document.getElementById("second");
 
-    mockSnavService.callback = notCalled;
+    await snav.rAF();
 
-    async function runTest() {
-      console.error('0');
-      await snav.rAF();
+    snav.triggerMove('Down');
 
-      snav.triggerMove('Down');
-      await snavCallback();
-      assert_equals(window.internals.interestedElement,
-                    first,
-                    "'first' should be interested.");
-      assert_not_equals(document.activeElement,
-                        first,
-                        "'first' should not yet be focused.");
-      assert_false(mockSnavService.canExitFocus,
-                  "Should be able to exit focus.");
-      assert_true(mockSnavService.canSelectElement,
-                  "Should be able to select element.");
-      assert_false(mockSnavService.hasNextFormElement,
-                   "Should be able to move to next form element.");
+    await snavCallback();
+    assert_equals(window.internals.interestedElement,
+                  first,
+                  "'first' should be interested.");
+    assert_not_equals(document.activeElement,
+                      first,
+                      "'first' should not yet be focused.");
+    assert_false(mockSnavService.canExitFocus,
+                "Should be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_false(mockSnavService.hasNextFormElement,
+                 "Should be able to move to next form element.");
 
-      eventSender.keyDown('Enter');
-      await snavCallback();
-      assert_true(mockSnavService.canExitFocus,
-                  "Should be able to exit focus.");
-      assert_true(mockSnavService.canSelectElement,
-                  "Should be able to select element.");
-      assert_true(mockSnavService.hasNextFormElement,
-                  "Should be able to move to next form element.");
-      assert_equals(window.internals.interestedElement,
-                    first,
-                    "'first' should be interested.");
-      assert_equals(document.activeElement,
-                    first,
-                    "'first' should be focused.");
-
-      t.done();
-    };
-
-    t.step_timeout(() => {
-      runTest();
-    }, 0);
-
-    function notCalled() {
-      t.step_timeout(() => {
-        assert_false(true, "Should not be called");
-      }, 0);
-    };
-
+    eventSender.keyDown('Enter');
+    await snavCallback();
+    assert_true(mockSnavService.canExitFocus,
+                "Should be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_true(mockSnavService.hasNextFormElement,
+                "Should be able to move to next form element.");
+    assert_equals(window.internals.interestedElement,
+                  first,
+                  "'first' should be interested.");
+    assert_equals(document.activeElement,
+                  first,
+                  "'first' should be focused.");
   }, 'Spat Nav state updates correctly when clicking on form elements.');
 </script>
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state.html
index 5925dc8c..6501c24 100644
--- a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state.html
+++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-form-state.html
@@ -13,72 +13,64 @@
 </form>
 
 <script>
-  async_test((t) => {
+  function notCalled() {
+    assert_false(true, "Should not be called");
+  };
+
+  let initialState = snavCallback();
+  promise_test(async () => {
+
     let first = document.getElementById("first");
     let second = document.getElementById("second");
     let third = document.getElementById("third");
 
-    let initialState = snavCallback();
+    await snav.rAF();
 
-    async function runTest() {
-      assert_equals(document.activeElement,
-                    first,
-                    "'first' should start focused.");
-      assert_equals(window.internals.interestedElement,
-                    first,
-                    "'first' should start interested.");
+    assert_equals(document.activeElement,
+                  first,
+                  "'first' should start focused.");
+    assert_equals(window.internals.interestedElement,
+                  first,
+                  "'first' should start interested.");
 
-      await initialState;
-      assert_true(mockSnavService.canExitFocus,
-                  "Should be able to exit focus.");
-      assert_true(mockSnavService.canSelectElement,
-                  "Should be able to select element.");
-      assert_true(mockSnavService.hasNextFormElement,
-                  "Should be able to move to next form element.");
+    await initialState;
+    assert_true(mockSnavService.canExitFocus,
+                "Should be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_true(mockSnavService.hasNextFormElement,
+                "Should be able to move to next form element.");
 
-      mockSnavService.callback = notCalled;
-      eventSender.keyDown('Tab');
-      assert_equals(document.activeElement,
-                    second,
-                    "'second' should be focused.");
+    mockSnavService.callback = notCalled;
+    eventSender.keyDown('Tab');
+    assert_equals(document.activeElement,
+                  second,
+                  "'second' should be focused.");
 
-      await snav.rAF();
+    await snav.rAF();
 
-      eventSender.keyDown('Tab');
-      assert_equals(document.activeElement,
-                    third,
-                    "'third' should be focused.");
+    eventSender.keyDown('Tab');
+    assert_equals(document.activeElement,
+                  third,
+                  "'third' should be focused.");
 
-      await snavCallback();
-      assert_true(mockSnavService.canExitFocus,
-                  "Should be able to exit focus.");
-      assert_true(mockSnavService.canSelectElement,
-                  "Should be able to select element.");
-      assert_false(mockSnavService.hasNextFormElement,
-                   "Should be able to move to next form element.");
+    await snavCallback();
+    assert_true(mockSnavService.canExitFocus,
+                "Should be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_false(mockSnavService.hasNextFormElement,
+                 "Should be able to move to next form element.");
 
-      eventSender.keyDown('Escape');
+    eventSender.keyDown('Escape');
 
-      await snavCallback();
-      assert_false(mockSnavService.canExitFocus,
-                   "Should be able to exit focus.");
-      assert_true(mockSnavService.canSelectElement,
-                  "Should be able to select element.");
-      assert_false(mockSnavService.hasNextFormElement,
-                   "Should be able to move to next form element.");
-
-      t.done();
-    };
-
-    t.step_timeout(() => {
-      runTest();
-    }, 0);
-
-    function notCalled() {
-      t.step_timeout(() => {
-        assert_false(true, "Should not be called");
-      }, 0);
-    };
+    await snavCallback();
+    assert_false(mockSnavService.canExitFocus,
+                 "Should be able to exit focus.");
+    assert_true(mockSnavService.canSelectElement,
+                "Should be able to select element.");
+    assert_false(mockSnavService.hasNextFormElement,
+                 "Should be able to move to next form element.");
 
   }, 'Spat Nav state updates correctly for form elements.');
 </script>
diff --git a/third_party/blink/web_tests/virtual/passive-fingerprinting/README.md b/third_party/blink/web_tests/virtual/passive-fingerprinting/README.md
new file mode 100644
index 0000000..6531fac
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/passive-fingerprinting/README.md
@@ -0,0 +1,2 @@
+# This suite runs the User-Agent tests in http/tests/navigation with
+# --enable-features=FreezeUserAgent.
diff --git a/third_party/blink/web_tests/virtual/passive-fingerprinting/http/tests/navigation/README.txt b/third_party/blink/web_tests/virtual/passive-fingerprinting/http/tests/navigation/README.txt
new file mode 100644
index 0000000..6531fac
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/passive-fingerprinting/http/tests/navigation/README.txt
@@ -0,0 +1,2 @@
+# This suite runs the User-Agent tests in http/tests/navigation with
+# --enable-features=FreezeUserAgent.
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
index d90c5cc..b33ccd69 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCPeerConnection-removeTrack.https-expected.txt
@@ -11,5 +11,6 @@
 FAIL Calling removeTrack with currentDirection sendonly should set direction to inactive promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 FAIL Calling removeTrack with currentDirection recvonly should not change direction promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
 FAIL Calling removeTrack with currentDirection inactive should not change direction promise_test: Unhandled rejection with value: object "InvalidStateError: Failed to execute 'addTransceiver' on 'RTCPeerConnection': This operation is only supported in 'unified-plan'. 'unified-plan' will become the default behavior in the future, but it is currently experimental. To try it out, construct the RTCPeerConnection with sdpSemantics:'unified-plan' present in the RTCConfiguration argument."
+FAIL Calling removeTrack on a stopped transceiver should be a no-op promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'stop' of undefined"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
index 8cf9b13e..2cbd0e7 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/RTCRtpTransceiver.https-expected.txt
@@ -35,5 +35,6 @@
 FAIL checkRollbackAndSetRemoteOfferWithDifferentType promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setLocalDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 FAIL checkRemoteRollback promise_test: Unhandled rejection with value: object "TypeError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': The provided value 'rollback' is not a valid enum value of type RTCSdpType."
 FAIL checkMsectionReuse promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'mid' of undefined"
+FAIL checkStopAfterCreateOfferWithReusedMsection promise_test: Unhandled rejection with value: object "TypeError: Cannot read property 'stop' of undefined"
 Harness: the test ran to completion.
 
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 1d789ad..f12bfe2 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
@@ -10630,7 +10630,10 @@
     getter onblur
     getter onend
     getter onfocus
-    getter onresetpose
+    getter oninputsourceschange
+    getter onselect
+    getter onselectend
+    getter onselectstart
     getter renderState
     getter viewerSpace
     method cancelAnimationFrame
@@ -10644,7 +10647,10 @@
     setter onblur
     setter onend
     setter onfocus
-    setter onresetpose
+    setter oninputsourceschange
+    setter onselect
+    setter onselectend
+    setter onselectstart
 interface XRSessionEvent : Event
     attribute @@toStringTag
     getter session
diff --git a/third_party/blink/web_tests/xr/events_session_resetpose.html b/third_party/blink/web_tests/xr/events_referenceSpace_reset.html
similarity index 78%
rename from third_party/blink/web_tests/xr/events_session_resetpose.html
rename to third_party/blink/web_tests/xr/events_referenceSpace_reset.html
index 0fdc5e9..5bbf824a 100644
--- a/third_party/blink/web_tests/xr/events_session_resetpose.html
+++ b/third_party/blink/web_tests/xr/events_referenceSpace_reset.html
@@ -29,9 +29,17 @@
     outputContext: getOutputContext()
   });
 
-  let eventWatcher = new EventWatcher(
-    t, session, ["resetpose", "watcherdone"]);
-  let eventPromise = eventWatcher.wait_for(["resetpose", "watcherdone"]);
+  let resetPromise = session.requestReferenceSpace(
+      {type: "stationary", subtype: "eye-level"})
+  .then((refSpace) => {
+    let eventWatcher = new EventWatcher(
+        t, refSpace, ["reset", "watcherdone"]);
+    refSpace.addEventListener("reset", (event) => {
+      assert_equals(event.referenceSpace, refSpace);
+      refSpace.dispatchEvent(watcherDone);
+    }, false);
+    return eventWatcher.wait_for(["reset", "watcherdone"]);
+  });
 
   // Need to have a valid pose or input events don't process.
   fakeDeviceController.setXRPresentationFrameData(VALID_POSE_MATRIX, [{
@@ -45,21 +53,12 @@
     }]);
   fakeDeviceController.setResetPose(true);
 
-  function onPoseReset(event) {
-    t.step( () => {
-      assert_equals(event.session, session);
-      session.dispatchEvent(watcherDone);
-    });
-  }
-
-  session.addEventListener("resetpose", onPoseReset, false);
-
   // Trigger the reset pose.
   session.requestAnimationFrame(() => {
     session.requestAnimationFrame(() => {});
   });
 
-  return eventPromise;
+  return resetPromise;
 };
 
 xr_session_promise_test(
diff --git a/third_party/inspector_protocol/README.chromium b/third_party/inspector_protocol/README.chromium
index 18e9dd0..176cbed9 100644
--- a/third_party/inspector_protocol/README.chromium
+++ b/third_party/inspector_protocol/README.chromium
@@ -2,7 +2,7 @@
 Short Name: inspector_protocol
 URL: https://chromium.googlesource.com/deps/inspector_protocol/
 Version: 0
-Revision: 13b84fe7332fe39a8aca39c5eba2ade9375bbb42
+Revision: 8c3f1afc2dc5b8588bc2dc5f12a93255383d7236
 License: BSD
 License File: LICENSE
 Security Critical: no
diff --git a/third_party/inspector_protocol/code_generator.py b/third_party/inspector_protocol/code_generator.py
index 18777d0f..1e12343e 100755
--- a/third_party/inspector_protocol/code_generator.py
+++ b/third_party/inspector_protocol/code_generator.py
@@ -5,7 +5,7 @@
 
 import os.path
 import sys
-import optparse
+import argparse
 import collections
 import functools
 import re
@@ -17,6 +17,13 @@
 
 import pdl
 
+try:
+    unicode
+except NameError:
+    # Define unicode for Py3
+    def unicode(s, *_):
+        return s
+
 # Path handling for libraries and templates
 # Paths have to be normalized because Jinja uses the exact template path to
 # determine the hash used in the cache filename, and we need a pre-caching step
@@ -53,28 +60,17 @@
         return collections.namedtuple('X', keys)(*values)
 
     try:
-        cmdline_parser = optparse.OptionParser()
-        cmdline_parser.add_option("--output_base")
-        cmdline_parser.add_option("--jinja_dir")
-        cmdline_parser.add_option("--config")
-        cmdline_parser.add_option("--config_value", action="append", type="string")
-        arg_options, _ = cmdline_parser.parse_args()
+        cmdline_parser = argparse.ArgumentParser()
+        cmdline_parser.add_argument("--output_base", type=unicode, required=True)
+        cmdline_parser.add_argument("--jinja_dir", type=unicode, required=True)
+        cmdline_parser.add_argument("--config", type=unicode, required=True)
+        cmdline_parser.add_argument("--config_value", default=[], action="append")
+        arg_options = cmdline_parser.parse_args()
         jinja_dir = arg_options.jinja_dir
-        if not jinja_dir:
-            raise Exception("jinja directory must be specified")
-        jinja_dir = jinja_dir.decode('utf8')
         output_base = arg_options.output_base
-        if not output_base:
-            raise Exception("Base output directory must be specified")
-        output_base = output_base.decode('utf8')
         config_file = arg_options.config
-        if not config_file:
-            raise Exception("Config file name must be specified")
-        config_file = config_file.decode('utf8')
         config_base = os.path.dirname(config_file)
         config_values = arg_options.config_value
-        if not config_values:
-            config_values = []
     except Exception:
         # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
         exc = sys.exc_info()[1]
diff --git a/third_party/inspector_protocol/convert_protocol_to_json.py b/third_party/inspector_protocol/convert_protocol_to_json.py
index 96048f7..f98bebcd 100755
--- a/third_party/inspector_protocol/convert_protocol_to_json.py
+++ b/third_party/inspector_protocol/convert_protocol_to_json.py
@@ -4,10 +4,8 @@
 # found in the LICENSE file.
 
 import argparse
-import collections
 import json
 import os.path
-import re
 import sys
 
 import pdl
diff --git a/third_party/inspector_protocol/encoding/encoding.cc b/third_party/inspector_protocol/encoding/encoding.cc
index 14e8668..3196de5 100644
--- a/third_party/inspector_protocol/encoding/encoding.cc
+++ b/third_party/inspector_protocol/encoding/encoding.cc
@@ -802,27 +802,35 @@
           SetToken(CBORTokenTag::INT32, token_start_length);
           return;
         case MajorType::STRING: {  // STRING8.
-          if (!success || remainder.size() < static_cast<int64_t>(
-                                                 token_start_internal_value_)) {
+          if (!success) {
             SetError(Error::CBOR_INVALID_STRING8);
             return;
           }
           auto length =
               static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          if (remainder.size() < token_start_length + length) {
+            SetError(Error::CBOR_INVALID_STRING8);
+            return;
+          }
           SetToken(CBORTokenTag::STRING8, token_start_length + length);
           return;
         }
         case MajorType::BYTE_STRING: {  // STRING16.
-          if (!success ||
-              remainder.size() <
-                  static_cast<int64_t>(token_start_internal_value_) ||
-              // Must be divisible by 2 since UTF16 is 2 bytes per character.
-              token_start_internal_value_ & 1) {
+          if (!success) {
             SetError(Error::CBOR_INVALID_STRING16);
             return;
           }
           auto length =
               static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          if (remainder.size() < token_start_length + length) {
+            SetError(Error::CBOR_INVALID_STRING16);
+            return;
+          }
+          if (length & 1) {
+            // Must be divisible by 2 since UTF16 is 2 bytes per character.
+            SetError(Error::CBOR_INVALID_STRING16);
+            return;
+          }
           SetToken(CBORTokenTag::STRING16, token_start_length + length);
           return;
         }
@@ -1477,8 +1485,10 @@
   void Parse(const Char* start, std::size_t length) {
     start_pos_ = start;
     const Char* end = start + length;
-    const Char* tokenEnd;
+    const Char* tokenEnd = nullptr;
     ParseValue(start, end, &tokenEnd, 0);
+    if (error_)
+      return;
     if (tokenEnd != end) {
       HandleError(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, tokenEnd);
     }
@@ -1695,7 +1705,7 @@
       if (IsSpaceOrNewLine(*start)) {
         ++start;
       } else if (*start == '/') {
-        const Char* comment_end;
+        const Char* comment_end = nullptr;
         if (!SkipComment(start, end, &comment_end))
           break;
         start = comment_end;
@@ -1907,8 +1917,8 @@
       HandleError(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, start);
       return;
     }
-    const Char* token_start;
-    const Char* token_end;
+    const Char* token_start = nullptr;
+    const Char* token_end = nullptr;
     Token token = ParseToken(start, end, &token_start, &token_end);
     switch (token) {
       case NoInput:
diff --git a/third_party/inspector_protocol/encoding/encoding_test.cc b/third_party/inspector_protocol/encoding/encoding_test.cc
index 7b0acf1..d444c92 100644
--- a/third_party/inspector_protocol/encoding/encoding_test.cc
+++ b/third_party/inspector_protocol/encoding/encoding_test.cc
@@ -445,7 +445,9 @@
   std::vector<TestCase> tests{
       {TestCase{{2 << 5 | 1, 'a'},
                 "length must be divisible by 2 (but it's 1)"},
-       TestCase{{2 << 5 | 29}, "additional info = 29 isn't recognized"}}};
+       TestCase{{2 << 5 | 29}, "additional info = 29 isn't recognized"},
+       TestCase{{2 << 5 | 9, 1, 2, 3, 4, 5, 6, 7, 8},
+                "length (9) points just past the end of the test case"}}};
   for (const TestCase& test : tests) {
     SCOPED_TRACE(test.msg);
     CBORTokenizer tokenizer(SpanFrom(test.data));
@@ -483,6 +485,23 @@
   EXPECT_EQ(CBORTokenTag::DONE, tokenizer.TokenTag());
 }
 
+TEST(EncodeDecodeString8Test, ErrorCases) {
+  struct TestCase {
+    std::vector<uint8_t> data;
+    std::string msg;
+  };
+  std::vector<TestCase> tests{
+      {TestCase{{3 << 5 | 29}, "additional info = 29 isn't recognized"},
+       TestCase{{3 << 5 | 9, 1, 2, 3, 4, 5, 6, 7, 8},
+                "length (9) points just past the end of the test case"}}};
+  for (const TestCase& test : tests) {
+    SCOPED_TRACE(test.msg);
+    CBORTokenizer tokenizer(SpanFrom(test.data));
+    EXPECT_EQ(CBORTokenTag::ERROR_VALUE, tokenizer.TokenTag());
+    EXPECT_EQ(Error::CBOR_INVALID_STRING8, tokenizer.Status().error);
+  }
+}
+
 TEST(EncodeFromLatin1Test, ConvertsToUTF8IfNeeded) {
   std::vector<std::pair<std::string, std::string>> examples = {
       {"Hello, world.", "Hello, world."},
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_cc.template b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
index 94bcd88..639b39bb 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_cc.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_cc.template
@@ -237,75 +237,6 @@
       new base::RefCountedBytes(data, size)));
 }
 
-namespace {
-int32_t ReadEnvelopeSize(const uint8_t* in) {
-  return (in[0] << 24) + (in[1] << 16) + (in[2] << 8) + in[3];
-}
-
-void WriteEnvelopeSize(uint32_t value, uint8_t* out) {
-  *(out++) = (value >> 24) & 0xFF;
-  *(out++) = (value >> 16) & 0xFF;
-  *(out++) = (value >> 8) & 0xFF;
-  *(out++) = (value) & 0xFF;
-}
-
-}
-
-bool AppendStringValueToMapBinary(base::StringPiece in,
-    base::StringPiece key, base::StringPiece value, std::string* out) {
-  if (in.size() < 1 + 1 + 4 + 1 + 1)
-    return false;
-  const uint8_t* envelope = reinterpret_cast<const uint8_t*>(in.data());
-  if (cbor::InitialByteForEnvelope() != envelope[0])
-    return false;
-  if (cbor::InitialByteFor32BitLengthByteString() != envelope[1])
-    return false;
-  if (cbor::EncodeIndefiniteLengthMapStart() != envelope[6])
-    return false;
-
-  uint32_t envelope_size = ReadEnvelopeSize(envelope + 2);
-  if (envelope_size + 2 + 4 != in.size())
-    return false;
-  if (cbor::EncodeStop() != static_cast<uint8_t>(*in.rbegin()))
-    return false;
-
-  std::vector<uint8_t> encoded_entry;
-  encoded_entry.reserve(1 + 4 + key.size() + 1 + 4 + value.size());
-  span<uint8_t> key_span(
-      reinterpret_cast<const uint8_t*>(key.data()), key.size());
-  cbor::EncodeString8(key_span, &encoded_entry);
-  span<uint8_t> value_span(
-      reinterpret_cast<const uint8_t*>(value.data()), value.size());
-  cbor::EncodeString8(value_span, &encoded_entry);
-
-  out->clear();
-  out->reserve(in.size() + encoded_entry.size());
-  out->append(in.begin(), in.end() - 1);
-  out->append(reinterpret_cast<const char*>(encoded_entry.data()),
-      encoded_entry.size());
-  out->append(1, static_cast<char>(cbor::EncodeStop()));
-  std::size_t new_size = envelope_size + out->size() - in.size();
-  if (new_size > static_cast<std::size_t>(
-      std::numeric_limits<uint32_t>::max())) {
-    return false;
-  }
-  WriteEnvelopeSize(new_size, reinterpret_cast<uint8_t*>(&*out->begin() + 2));
-  return true;
-}
-
-bool AppendStringValueToMapJSON(base::StringPiece in,
-    base::StringPiece key, base::StringPiece value, std::string* out) {
-  if (!in.length() || *in.rbegin() != '}')
-    return false;
-  std::string suffix =
-      base::StringPrintf(", \"%s\": \"%s\"}", key.begin(), value.begin());
-  out->clear();
-  out->reserve(in.length() + suffix.length() - 1);
-  out->append(in.data(), in.length() - 1);
-  out->append(suffix);
-  return true;
-}
-
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}
 {% endfor %}
diff --git a/third_party/inspector_protocol/lib/base_string_adapter_h.template b/third_party/inspector_protocol/lib/base_string_adapter_h.template
index 082c7c0..8bf3c355 100644
--- a/third_party/inspector_protocol/lib/base_string_adapter_h.template
+++ b/third_party/inspector_protocol/lib/base_string_adapter_h.template
@@ -136,12 +136,6 @@
 
 std::unique_ptr<Value> toProtocolValue(const base::Value* value, int depth);
 std::unique_ptr<base::Value> toBaseValue(Value* value, int depth);
-
-bool AppendStringValueToMapBinary(base::StringPiece in,
-    base::StringPiece key, base::StringPiece value, std::string* out);
-bool AppendStringValueToMapJSON(base::StringPiece in,
-    base::StringPiece key, base::StringPiece value, std::string* out);
-
 {% for namespace in config.protocol.namespace %}
 } // namespace {{namespace}}
 {% endfor %}
diff --git a/third_party/inspector_protocol/lib/encoding_cpp.template b/third_party/inspector_protocol/lib/encoding_cpp.template
index 03038fe..8c76aad 100644
--- a/third_party/inspector_protocol/lib/encoding_cpp.template
+++ b/third_party/inspector_protocol/lib/encoding_cpp.template
@@ -809,27 +809,35 @@
           SetToken(CBORTokenTag::INT32, token_start_length);
           return;
         case MajorType::STRING: {  // STRING8.
-          if (!success || remainder.size() < static_cast<int64_t>(
-                                                 token_start_internal_value_)) {
+          if (!success) {
             SetError(Error::CBOR_INVALID_STRING8);
             return;
           }
           auto length =
               static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          if (remainder.size() < token_start_length + length) {
+            SetError(Error::CBOR_INVALID_STRING8);
+            return;
+          }
           SetToken(CBORTokenTag::STRING8, token_start_length + length);
           return;
         }
         case MajorType::BYTE_STRING: {  // STRING16.
-          if (!success ||
-              remainder.size() <
-                  static_cast<int64_t>(token_start_internal_value_) ||
-              // Must be divisible by 2 since UTF16 is 2 bytes per character.
-              token_start_internal_value_ & 1) {
+          if (!success) {
             SetError(Error::CBOR_INVALID_STRING16);
             return;
           }
           auto length =
               static_cast<std::ptrdiff_t>(token_start_internal_value_);
+          if (remainder.size() < token_start_length + length) {
+            SetError(Error::CBOR_INVALID_STRING16);
+            return;
+          }
+          if (length & 1) {
+            // Must be divisible by 2 since UTF16 is 2 bytes per character.
+            SetError(Error::CBOR_INVALID_STRING16);
+            return;
+          }
           SetToken(CBORTokenTag::STRING16, token_start_length + length);
           return;
         }
@@ -1484,8 +1492,10 @@
   void Parse(const Char* start, std::size_t length) {
     start_pos_ = start;
     const Char* end = start + length;
-    const Char* tokenEnd;
+    const Char* tokenEnd = nullptr;
     ParseValue(start, end, &tokenEnd, 0);
+    if (error_)
+      return;
     if (tokenEnd != end) {
       HandleError(Error::JSON_PARSER_UNPROCESSED_INPUT_REMAINS, tokenEnd);
     }
@@ -1702,7 +1712,7 @@
       if (IsSpaceOrNewLine(*start)) {
         ++start;
       } else if (*start == '/') {
-        const Char* comment_end;
+        const Char* comment_end = nullptr;
         if (!SkipComment(start, end, &comment_end))
           break;
         start = comment_end;
@@ -1914,8 +1924,8 @@
       HandleError(Error::JSON_PARSER_STACK_LIMIT_EXCEEDED, start);
       return;
     }
-    const Char* token_start;
-    const Char* token_end;
+    const Char* token_start = nullptr;
+    const Char* token_end = nullptr;
     Token token = ParseToken(start, end, &token_start, &token_end);
     switch (token) {
       case NoInput:
diff --git a/third_party/inspector_protocol/pdl.py b/third_party/inspector_protocol/pdl.py
index 43111e9..03d11b39 100644
--- a/third_party/inspector_protocol/pdl.py
+++ b/third_party/inspector_protocol/pdl.py
@@ -74,20 +74,20 @@
         if len(trimLine) == 0:
             continue
 
-        match = re.compile('^(experimental )?(deprecated )?domain (.*)').match(line)
+        match = re.compile(r'^(experimental )?(deprecated )?domain (.*)').match(line)
         if match:
             domain = createItem({'domain' : match.group(3)}, match.group(1), match.group(2))
             protocol['domains'].append(domain)
             continue
 
-        match = re.compile('^  depends on ([^\s]+)').match(line)
+        match = re.compile(r'^  depends on ([^\s]+)').match(line)
         if match:
             if 'dependencies' not in domain:
                 domain['dependencies'] = []
             domain['dependencies'].append(match.group(1))
             continue
 
-        match = re.compile('^  (experimental )?(deprecated )?type (.*) extends (array of )?([^\s]+)').match(line)
+        match = re.compile(r'^  (experimental )?(deprecated )?type (.*) extends (array of )?([^\s]+)').match(line)
         if match:
             if 'types' not in domain:
                 domain['types'] = []
@@ -96,7 +96,7 @@
             domain['types'].append(item)
             continue
 
-        match = re.compile('^  (experimental )?(deprecated )?(command|event) (.*)').match(line)
+        match = re.compile(r'^  (experimental )?(deprecated )?(command|event) (.*)').match(line)
         if match:
             list = []
             if match.group(3) == 'command':
@@ -114,7 +114,7 @@
             list.append(item)
             continue
 
-        match = re.compile('^      (experimental )?(deprecated )?(optional )?(array of )?([^\s]+) ([^\s]+)').match(line)
+        match = re.compile(r'^      (experimental )?(deprecated )?(optional )?(array of )?([^\s]+) ([^\s]+)').match(line)
         if match:
             param = createItem({}, match.group(1), match.group(2), match.group(6))
             if match.group(3):
@@ -125,36 +125,36 @@
             subitems.append(param)
             continue
 
-        match = re.compile('^    (parameters|returns|properties)').match(line)
+        match = re.compile(r'^    (parameters|returns|properties)').match(line)
         if match:
             subitems = item[match.group(1)] = []
             continue
 
-        match = re.compile('^    enum').match(line)
+        match = re.compile(r'^    enum').match(line)
         if match:
             enumliterals = item['enum'] = []
             continue
 
-        match = re.compile('^version').match(line)
+        match = re.compile(r'^version').match(line)
         if match:
             continue
 
-        match = re.compile('^  major (\d+)').match(line)
+        match = re.compile(r'^  major (\d+)').match(line)
         if match:
             protocol['version']['major'] = match.group(1)
             continue
 
-        match = re.compile('^  minor (\d+)').match(line)
+        match = re.compile(r'^  minor (\d+)').match(line)
         if match:
             protocol['version']['minor'] = match.group(1)
             continue
 
-        match = re.compile('^    redirect ([^\s]+)').match(line)
+        match = re.compile(r'^    redirect ([^\s]+)').match(line)
         if match:
             item['redirect'] = match.group(1)
             continue
 
-        match = re.compile('^      (  )?[^\s]+$').match(line)
+        match = re.compile(r'^      (  )?[^\s]+$').match(line)
         if match:
             # enum literal
             enumliterals.append(trimLine)
diff --git a/third_party/node/PRESUBMIT.py b/third_party/node/PRESUBMIT.py
new file mode 100644
index 0000000..e07cb6fe
--- /dev/null
+++ b/third_party/node/PRESUBMIT.py
@@ -0,0 +1,23 @@
+# 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.
+
+
+def CheckChangeOnUpload(*args):
+  return _CommonChecks(*args)
+
+
+def CheckChangeOnCommit(*args):
+  return _CommonChecks(*args)
+
+
+def _CommonChecks(input_api, output_api):
+  cwd = input_api.PresubmitLocalPath()
+  path = input_api.os_path
+  files = [path.basename(f.LocalPath()) for f in input_api.AffectedFiles()]
+
+  if any(f for f in files if f.startswith('clean_json_attrs')):
+    tests = [path.join(cwd, 'clean_json_attrs_test.py')]
+    return input_api.canned_checks.RunUnitTests(input_api, output_api, tests)
+
+  return []
diff --git a/third_party/node/clean_json_attrs.py b/third_party/node/clean_json_attrs.py
new file mode 100755
index 0000000..0ee0026
--- /dev/null
+++ b/third_party/node/clean_json_attrs.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+
+import json
+import os
+import re
+
+
+def Clean(start_dir, attr_pattern, file_pattern):
+  cleaned = False
+
+  def _remove_attrs(json_dict, attr_pattern):
+    assert isinstance(json_dict, dict)
+
+    removed = False
+
+    for key, val in json_dict.items():
+      if isinstance(val, dict):
+        if _remove_attrs(val, attr_pattern):
+          removed = True
+      elif re.search(attr_pattern, key):
+        del json_dict[key]
+        removed = True
+
+    return removed
+
+  for root, dirs, files in os.walk(start_dir):
+    for f in files:
+      if not re.search(file_pattern, f):
+        continue
+
+      path = os.path.join(root, f)
+      json_dict = json.loads(open(path).read())
+      if not _remove_attrs(json_dict, attr_pattern):
+        continue
+
+      with open(path, 'w') as new_contents:
+        new_contents.write(json.dumps(json_dict))
+      cleaned = True
+
+  return cleaned
+
+
+if __name__ == '__main__':
+  import argparse
+  import sys
+  parser = argparse.ArgumentParser(
+      description='Recursively removes attributes from JSON files')
+  parser.add_argument('--attr_pattern', type=str, required=True,
+      help='A regex of attributes to remove')
+  parser.add_argument('--file_pattern', type=str, required=True,
+      help='A regex of files to clean')
+  parser.add_argument('start_dir', type=str,
+      help='A directory to start scanning')
+  args = parser.parse_args(sys.argv[1:])
+  Clean(start_dir=args.start_dir, attr_pattern=args.attr_pattern,
+        file_pattern=args.file_pattern)
diff --git a/third_party/node/clean_json_attrs_test.py b/third_party/node/clean_json_attrs_test.py
new file mode 100755
index 0000000..a77c098
--- /dev/null
+++ b/third_party/node/clean_json_attrs_test.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+import clean_json_attrs
+import json
+import os
+import shutil
+import tempfile
+import unittest
+
+class CleanJsonAttrs(unittest.TestCase):
+  def setUp(self):
+    self._start_dir = tempfile.mkdtemp(dir=os.path.dirname(__file__))
+    self._kwargs = {
+        'file_pattern': 'package\.json',
+        'attr_pattern': '^_',
+        'start_dir': self._start_dir
+    }
+
+  def tearDown(self):
+    assert self._start_dir
+    shutil.rmtree(self._start_dir)
+
+  def _read_temp_file(self, filename):
+    return json.loads(open(os.path.join(self._start_dir, filename)).read())
+
+  def _write_temp_file(self, filename, json_dict):
+    with open(os.path.join(self._start_dir, filename), 'w') as f:
+      f.write(json.dumps(json_dict))
+
+  def testAttrPattern(self):
+    self._write_temp_file('package.json', {
+        'delete_me': True,
+        'ignore_me': True,
+        'version': '2.3.4',
+    })
+    args = self._kwargs.copy()
+    args['attr_pattern'] = '^delete'
+    self.assertTrue(clean_json_attrs.Clean(**args))
+    json_dict = self._read_temp_file('package.json')
+    self.assertEquals(['ignore_me', 'version'], sorted(json_dict.keys()))
+
+  def testFilePattern(self):
+    self._write_temp_file('clean_me.json', {'_where': '/a/b/c'})
+    self._write_temp_file('ignore_me.json', {'_args': ['/a/b/c']})
+    args = self._kwargs.copy()
+    args['file_pattern'] = '^clean_'
+    self.assertTrue(clean_json_attrs.Clean(**args))
+    self.assertEquals([], self._read_temp_file('clean_me.json').keys())
+    self.assertEquals(['_args'], self._read_temp_file('ignore_me.json').keys())
+
+  def testNestedKeys(self):
+    self._write_temp_file('package.json', {
+        '_args': ['/some/path/'],
+        'nested': {
+            '_keys': [],
+            'also': {
+                '_get': 'scanned',
+            },
+        },
+        '_where': '/some/path',
+        'version': '2.0.0'
+    })
+    self.assertTrue(clean_json_attrs.Clean(**self._kwargs))
+    json_dict = self._read_temp_file('package.json')
+    self.assertEquals(['nested', 'version'], sorted(json_dict.keys()))
+    self.assertEquals(['also'], json_dict['nested'].keys())
+    self.assertEquals([], json_dict['nested']['also'].keys())
+
+  def testNothingToRemove(self):
+    self._write_temp_file('package.json', {'version': '2.0.0'})
+    self.assertFalse(clean_json_attrs.Clean(**self._kwargs))
+    self.assertEquals(['version'], self._read_temp_file('package.json').keys())
+
+  def testSimple(self):
+    self._write_temp_file('package.json', {
+        '_args': ['/some/path/'],
+        'version': '2.0.0',
+        '_where': '/some/path'
+    })
+    self.assertTrue(clean_json_attrs.Clean(**self._kwargs))
+    self.assertEquals(['version'], self._read_temp_file('package.json').keys())
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/third_party/node/node_modules.tar.gz.sha1 b/third_party/node/node_modules.tar.gz.sha1
index ae1b6eb..11a944c 100644
--- a/third_party/node/node_modules.tar.gz.sha1
+++ b/third_party/node/node_modules.tar.gz.sha1
@@ -1 +1 @@
-f7f479efd86894f51e85d120ddc4cb7c827c0ef0
+2dd750e768cec597fc018509009637819ae4549c
diff --git a/third_party/node/update_npm_deps b/third_party/node/update_npm_deps
index a708c95..0482489b 100755
--- a/third_party/node/update_npm_deps
+++ b/third_party/node/update_npm_deps
@@ -24,6 +24,10 @@
 rsync -c --delete -r -q --include-from="npm_include.txt" --exclude-from="npm_exclude.txt" \
       --prune-empty-dirs "node_modules/" "node_modules_filtered/"
 
+# `npm install` leaves a bunch of local paths in _where and _args.
+# This is undesired. See: https://github.com/npm/npm/issues/10393
+python clean_json_attrs.py --attr_pattern="^_" --file_pattern="^package\.json$" "node_modules_filtered/"
+
 echo -e "\n---------------------------------------------------------"
 echo "Before filtering:" size: $(du -h node_modules/ | tail -n1 | cut -f1) ", files: " $(find node_modules/ -type f | wc -l)
 rm -r node_modules
diff --git a/tools/chrome_proxy/webdriver/bypass.py b/tools/chrome_proxy/webdriver/bypass.py
index 1558fa1..2c4d752 100644
--- a/tools/chrome_proxy/webdriver/bypass.py
+++ b/tools/chrome_proxy/webdriver/bypass.py
@@ -59,30 +59,130 @@
 
   # Verify that CORS requests receive a block-once from the data reduction
   # proxy by checking that those requests are retried without data reduction
-  # proxy.
+  # proxy. CORS tests needs to be verified with and without OutOfBlinkCors
+  # feature, since this feature affects sending CORS blocked response headers to
+  # the renderer in different ways.
   def testCorsBypass(self):
+    self.VerifyCorsTestWithOutOfBlinkCors(True)
+
+  def testCorsBypassWithoutOutOfBlinkCors(self):
+    # Verifies CORS behavior without OutOfBlinkCors feature. This feature is
+    # currently under experimentation and once it is fully enabled this test can
+    # be removed.
+    self.VerifyCorsTestWithOutOfBlinkCors(False)
+
+  def VerifyProxyServesPageWithoutBypass(self, test_driver):
+    drp_responses = 0
+    test_driver.LoadURL('http://check.googlezip.net/test.html')
+    for response in test_driver.GetHTTPResponses():
+      self.assertHasProxyHeaders(response)
+      drp_responses += 1
+    self.assertNotEqual(0, drp_responses)
+    test_driver.SleepUntilHistogramHasEntry('PageLoad.Clients.'
+              'DataReductionProxy.ParseTiming.NavigationToFirstContentfulPaint')
+    self.assertEqual({},
+      test_driver.GetHistogram('DataReductionProxy.BlockTypePrimary'))
+    self.assertEqual({},
+      test_driver.GetHistogram('DataReductionProxy.BlockTypeFallback'))
+    self.assertEqual({},
+      test_driver.GetHistogram('DataReductionProxy.BypassTypePrimary'))
+    self.assertEqual({},
+      test_driver.GetHistogram('DataReductionProxy.BypassTypeFallback'))
+
+  def VerifyCorsTestWithOutOfBlinkCors(self, is_out_of_blink_cors_feature_on):
     with TestDriver() as test_driver:
       test_driver.AddChromeArg('--enable-spdy-proxy-auth')
+      if is_out_of_blink_cors_feature_on:
+        test_driver.EnableChromeFeature('OutOfBlinkCors')
+      else:
+        test_driver.DisableChromeFeature('OutOfBlinkCors')
+
+      # The CORS test page makes a cross-origin XHR request to a resource for
+      # which DRP requests to bypass proxy for the current request. This 502
+      # block-once bypass will not be received by the DRP bypass logic in the
+      # renderer if proper response headers (Access-Control-Allow-Origin and
+      # Access-Control-Allow-Headers) are not present.
+      # This test verifies that the bypass logic received one block-once bypass,
+      # and the request is retried without DRP. The 502 bypass response cannot
+      # be verified to contain proper response headers set by the DRP since only
+      # the retried response will be picked up by the webdriver.
       test_driver.LoadURL('http://www.gstatic.com/chrome/googlezip/cors/')
 
-      # Navigate to a different page to verify that later requests are not
-      # blocked.
-      test_driver.LoadURL('http://check.googlezip.net/test.html')
-
+      test_driver.SleepUntilHistogramHasEntry(
+        'DataReductionProxy.BlockTypePrimary')
+      # Verify that one request received block-once(bucket=0), and no other
+      # bypasses or fallbacks are received. Explicit checks for response headers
+      # content-type=text/plain, Access-Control-Allow-Origin,
+      # Access-Control-Allow-Headers, Via, Chrome-Proxy cannot be added, since
+      # webdriver does not get the headers for 502 response. However, since
+      # BlockTypePrimary is checked for one block-once entry, we know the DRP
+      # bypass logic has picked it up.
+      blocked = test_driver.GetHistogram('DataReductionProxy.BlockTypePrimary')
+      self.assertEqual(1, blocked['count'])
+      self.assertEqual(blocked['buckets'][0]['low'], 0)
+      self.assertEqual({},
+        test_driver.GetHistogram('DataReductionProxy.BlockTypeFallback'))
+      self.assertEqual({},
+        test_driver.GetHistogram('DataReductionProxy.BypassTypePrimary'))
+      self.assertEqual({},
+        test_driver.GetHistogram('DataReductionProxy.BypassTypeFallback'))
       cors_requests = 0
       same_origin_requests = 0
       for response in test_driver.GetHTTPResponses():
-        # The origin header implies that |response| is a CORS request.
-        if ('origin' not in response.request_headers):
+        # The cross-origin XHR request is a CORS request.
+        if response.request_type == 'XHR':
+          self.assertNotHasChromeProxyViaHeader(response)
+          self.assertEqual(200, response.status)
+          cors_requests = cors_requests + 1
+        else:
           self.assertHasProxyHeaders(response)
           same_origin_requests = same_origin_requests + 1
-        else:
-          self.assertNotHasChromeProxyViaHeader(response)
-          cors_requests = cors_requests + 1
       # Verify that both CORS and same origin requests were seen.
       self.assertNotEqual(0, same_origin_requests)
       self.assertNotEqual(0, cors_requests)
 
+      # Navigate to a different page to verify that later requests are not
+      # blocked.
+      self.VerifyProxyServesPageWithoutBypass(test_driver)
+
+  # Tests that data reduction proxy bypasses are not blocked by CORB. Since the
+  # bypass/fallback handling is in the renderer process, CORB failures will skip
+  # the bypasses/fallbacks and the resource will not be retried without data
+  # reduction proxy.
+  def testBypassNotBlockedByCorb(self):
+    with TestDriver() as test_driver:
+      test_driver.AddChromeArg('--enable-spdy-proxy-auth')
+
+      # The CORB test page loads an <img> to a cross-origin resource for which
+      # DRP requests to bypass proxy for the current request. This 502
+      # block-once bypass will not be received by the DRP bypass logic in the
+      # renderer, if CORB blocks it based on mislabeled content-type or the
+      # actual type observed from sniffing the body.
+      test_driver.LoadURL('http://www.gstatic.com/chrome/googlezip/corb.html')
+      drp_responses = 0
+      for response in test_driver.GetHTTPResponses():
+          if response.ResponseHasViaHeader():
+            self.assertHasProxyHeaders(response)
+            drp_responses += 1
+      self.assertNotEqual(0, drp_responses)
+      test_driver.SleepUntilHistogramHasEntry(
+        'DataReductionProxy.BlockTypePrimary')
+      # Verify that one request received block-once (bucket=0), and no other
+      # bypasses or fallbacks are received.
+      blocked = test_driver.GetHistogram('DataReductionProxy.BlockTypePrimary')
+      self.assertEqual(1, blocked['count'])
+      self.assertEqual(blocked['buckets'][0]['low'], 0)
+      self.assertEqual({},
+        test_driver.GetHistogram('DataReductionProxy.BlockTypeFallback'))
+      self.assertEqual({},
+        test_driver.GetHistogram('DataReductionProxy.BypassTypePrimary'))
+      self.assertEqual({},
+        test_driver.GetHistogram('DataReductionProxy.BypassTypeFallback'))
+
+      # Navigate to a different page to verify that later requests are not
+      # blocked.
+      self.VerifyProxyServesPageWithoutBypass(test_driver)
+
   # Verify that when an origin times out using Data Saver, the request is
   # fetched directly and data saver is bypassed only for one request.
   def testOriginTimeoutBlockOnce(self):
diff --git a/tools/chrome_proxy/webdriver/common.py b/tools/chrome_proxy/webdriver/common.py
index 34f526b..09cc0aa 100644
--- a/tools/chrome_proxy/webdriver/common.py
+++ b/tools/chrome_proxy/webdriver/common.py
@@ -316,7 +316,7 @@
       })
       if not self._flags.android:
         chrome_options.add_experimental_option('mobileEmulation',
-          {'deviceName': 'Google Nexus 5'})
+          {'deviceName': 'Pixel 2'})
 
     self._chrome_args.add(
       '--enable-features=%s' % ','.join(self._enable_features))
@@ -507,13 +507,26 @@
       url: The URL to navigate to.
       timeout: The time in seconds to load the page before timing out.
     """
+    # Reduce some flakiness by checking if we should ensure the proxy has fully
+    # initialized first.
+    if not self._driver:
+      self._StartDriver()
+
+    disabled_config_service = False
+    for arg in self._chrome_args:
+      if 'DataReductionProxyConfigService/Disabled' in arg:
+        disabled_config_service = True
+    if (not disabled_config_service and
+        '--enable-spdy-proxy-auth' in self._chrome_args and
+        'DataReductionProxyEnabledWithNetworkService' in self._enable_features):
+      self._driver.get('data:,')
+      self.SleepUntilHistogramHasEntry(
+        'DataReductionProxy.ConfigService.FetchResponseCode', sleep_intervals=5)
     self._url = url
     if (len(urlparse.urlparse(url).netloc) == 0 and
         len(urlparse.urlparse(url).scheme) == 0):
       self._logger.warn('Invalid URL: "%s". Did you forget to prepend '
         '"http://"? See RFC 1808 for more information', url)
-    if not self._driver:
-      self._StartDriver()
     self._driver.set_page_load_timeout(timeout)
     self._logger.debug('Set page load timeout to %f seconds', timeout)
     self._driver.get(self._url)
@@ -581,7 +594,7 @@
     Returns:
       A dictionary object containing information about the histogram.
     """
-    js_query = 'statsCollectionController.getBrowserHistogram("%s")' % histogram
+    js_query = 'statsCollectionController.getHistogram("%s")' % histogram
     string_response = self.ExecuteJavascriptStatement(js_query, timeout)
     self._logger.debug('Got %s histogram=%s', histogram, string_response)
     return json.loads(string_response)
@@ -731,8 +744,9 @@
         'request_type': params['type'] if 'type' in params else '',
         'redirect_chain': [],
       }
-      for request in all_requests[params['requestId']][:-1]:
-        http_response_dict['redirect_chain'].append(request['request']['url'])
+      if params['requestId'] in all_requests:
+        for request in all_requests[params['requestId']][:-1]:
+          http_response_dict['redirect_chain'].append(request['request']['url'])
       return HTTPResponse(**http_response_dict)
 
     for message in self.GetPerformanceLogs():
diff --git a/tools/chrome_proxy/webdriver/compression_regression.py b/tools/chrome_proxy/webdriver/compression_regression.py
deleted file mode 100644
index 3fc3129..0000000
--- a/tools/chrome_proxy/webdriver/compression_regression.py
+++ /dev/null
@@ -1,388 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import datetime
-import json
-import math
-import subprocess
-import time
-
-import common
-from common import TestDriver
-from common import IntegrationTest
-from decorators import NotAndroid
-from decorators import Slow
-
-# The maximum number of data points that will be saved.
-MAX_DATA_POINTS = 365
-
-# The number of days in the past to compute the average of for regression
-# alerting.
-ALERT_WINDOW = 31
-
-# The amount of tolerable difference a single data point can be away from the
-# average without alerting. This is a percentage from 0.0 to 1.0 inclusive.
-# 3% was chosen because over the course of the first month no change was seen to
-# 8 decimal places. Erring on the more sensitive side to begin with is also
-# better so we get a better feel for the timing and degree of regressions.
-THRESHOLD = 0.03
-
-# The format to use when recording dates in the DATA_FILE
-DATE_FORMAT = '%Y-%m-%d'
-
-# The persistant storage for compression data is kept in Google Storage with
-# this bucket name.
-BUCKET = 'chrome_proxy_compression'
-
-# The data file name in the Google Storage bucket, above. The data file is also
-# saved locally under the same name.
-DATA_FILE = 'compression_data.json'
-
-class CompressionRegression(IntegrationTest):
-  """This class is responsible for alerting the Chrome Proxy team to regression
-  in the compression metrics of the proxy. At present, this class will simply
-  gather data and save it to a Google Storage bucket. Once enough data has been
-  gathered to form a reasonable model, alerting will be added to check for
-  regression.
-
-  Before running the test, this class will fetch the JSON data file from Google
-  Storage in a subprocess and store it on the local disk with the same file
-  name. The data is then read from that file. After running the test, if the
-  data has changed the file will be uploaded back to Google Storage.
-
-  The JSON data object and data dict object used widely in this class has the
-  following structure:
-  {
-    "2017-02-29": {
-      "html": 0.314,
-      "jpg": 0.1337,
-      "png": 0.1234,
-      "mp4": 0.9876
-    }
-  }
-  where keys are date stamps in the form "YYYY-MM-DD", and each key in the child
-  object is the resource type with its compression value.
-
-  Also frequently referenced is the compression_average dict object, which
-  contains the compression data just now gathered from Chrome in
-  getCurrentCompressionMetrics(). That object has the following structure:
-  {
-    "test/html": 0.314,
-    "image/jpg": 0.1337,
-    "image/png": 0.1234,
-    "video/mp4": 0.9876
-  }
-  where keys are the content type with its compression value.
-
-  Due to the complexity of several methods in this class, a number of local
-  unit tests can be found at the bottom of this file.
-
-  Please note that while this test uses the IntegrationTest framework, it is
-  classified as a regression test.
-  """
-
-  @Slow
-  @NotAndroid
-  def testCompression(self):
-      """This function is the main test function for regression compression
-      checking and facilitates the test with all of the helper functions'
-      behavior.
-      """
-      compression_average = self.getCurrentCompressionMetricsWithRetry()
-      self.fetchFromGoogleStorage()
-      data = {}
-      with open(DATA_FILE, 'r') as data_fp:
-        data = json.load(data_fp)
-      if self.updateDataObject(compression_average, data):
-        with open(DATA_FILE, 'w') as data_fp:
-          json.dump(data, data_fp)
-        self.uploadToGoogleStorage()
-
-  def getCurrentCompressionMetricsWithRetry(self, max_attempts=10):
-    """This function allows some number of attempts to be tried to fetch
-    compressed responses. Sometimes, the proxy will not have compressed results
-    available immediately, especially for video resources.
-
-    Args:
-      max_attempts: the maximum number of attempts to try to fetch compressed
-        resources.
-    Returns:
-      a dict object mapping resource type to compression
-    """
-    attempts = 0
-    while attempts < max_attempts:
-      try:
-        return self.getCurrentCompressionMetrics()
-      except Exception as e:
-        attempts += 1
-        time.sleep(2)
-    if attempts >= max_attempts:
-      raise Exception("Didn't get good response after %d attempts" % attempts)
-
-  def getCurrentCompressionMetrics(self):
-    """This function uses the ChromeDriver framework to open Chrome and navigate
-    to a number of static resources of different types, like jpg, png, mp4, gif,
-    html. Multiple resources of a single type are supported. This function will
-    check that each resource was fetched via the Chrome Proxy, and then compute
-    the compression as a percentage from the Content-Length and OFCL in
-    Chrome-Proxy headers where compression = 1 - (cl / ofcl). The function will
-    then return the average compression for each of the resource types.
-
-    Returns:
-      a dict object mapping resource type to compression
-    """
-    def AddToCompression(compression, key, value):
-      if key in compression:
-        compression[key].append(value)
-      else:
-        compression[key] = [value]
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('http://check.googlezip.net/metrics/local.gif')
-      t.LoadURL('http://check.googlezip.net/metrics/local.png')
-      t.LoadURL('http://check.googlezip.net/metrics/local.jpg')
-      t.LoadURL(
-        'http://check.googlezip.net/cacheable/video/buck_bunny_tiny.html')
-      compression = {}
-      for response in t.GetHTTPResponses():
-        # Check that the response was proxied.
-        self.assertHasProxyHeaders(response)
-        # Compute compression metrics.
-        cl = response.response_headers['content-length']
-        ofcl = getChromeProxyOFCL(response)
-        content_type = response.response_headers['content-type']
-        compression_rate = 1.0 - (float(cl) / float(ofcl))
-        if 'html' in response.response_headers['content-type']:
-          AddToCompression(compression, 'html', compression_rate)
-        else:
-          resource = response.url[response.url.rfind('/'):]
-          AddToCompression(compression, resource[resource.rfind('.') + 1:],
-            compression_rate)
-      # Compute the average compression for each resource type.
-      compression_average = {}
-      for resource_type in compression:
-        compression_average[resource_type] = (sum(compression[resource_type]) /
-          float(len(compression[resource_type])))
-      return compression_average
-
-    # Returns the ofcl value in chrome-proxy header.
-    def getChromeProxyOFCL(self, response):
-      self.assertIn('chrome-proxy', response.response_headers)
-      chrome_proxy_header = response.response_headers['chrome-proxy']
-      self.assertIn('ofcl=', chrome_proxy_header)
-      return chrome_proxy_header.split('ofcl=', 1)[1].split(',', 1)[0]
-
-
-  def updateDataObject(self, compression_average, data,
-      today=datetime.date.today()):
-    """This function handles the updating of the data object when new data is
-    available. Given the existing data object, the results of the
-    getCurrentCompressionMetrics() func, and a date object, it will check if
-    data exists for today. If it does, the method will do nothing and return
-    False. Otherwise, it will update the data object with the compression data.
-    If needed, it will also find the least recent entry in the data object and
-    remove it.
-
-    Args:
-      compression_average: the compression data from
-        getCurrentCompressionMetrics()
-      data: all saved results from previous runs
-      today: a date object, specifiable here for testing purposes.
-    Returns:
-      True iff the data object was changed
-    """
-    datestamp = today.strftime(DATE_FORMAT)
-    # Check if this data has already been recorded.
-    if datestamp in data:
-      return False
-    # Append new data, removing the least recent if needed.
-    data[datestamp] = compression_average
-    if len(data) > MAX_DATA_POINTS:
-      min_date = None
-      for date_str in data:
-        date = datetime.date(*[int(d) for d in date_str.split('-')])
-        if min_date == None or date < min_date:
-          min_date = date
-      del data[min_date.strftime(DATE_FORMAT)]
-    return True
-
-  def checkForRegression(self, data, compression_average):
-    """This function checks whether the current data point in
-    compression_average falls outside an allowable tolerance for the last
-    ALERT_WINDOW days of data points in data. If so, an expection will be
-    rasied.
-
-    Args:
-      data: all saved results from previous runs
-      compression_average: the most recent data point
-    """
-    # Restructure data to be easily summable.
-    data_sum_rt = {}
-    for date in sorted(data, reverse=True):
-      for resource_type in data[date]:
-        if resource_type not in data_sum_rt:
-          data_sum_rt[resource_type] = []
-        data_sum_rt[resource_type].append(data[date][resource_type])
-    # Compute average over ALERT_WINDOW if there is enough data points.
-    # Data average will contain average compression ratios (eg: 1 - cl / ofcl).
-    data_average = {}
-    for resource_type in data_sum_rt:
-      if len(data_sum_rt[resource_type]) >= ALERT_WINDOW:
-        data_average[resource_type] = sum(
-          data_sum_rt[resource_type][:ALERT_WINDOW]) / ALERT_WINDOW
-    # Check regression, raising an exception if anything is detected.
-    for resource_type in compression_average:
-      if resource_type in data_average:
-        expected = data_average[resource_type]
-        actual = compression_average[resource_type]
-        # Going over the max is ok, better compression is better.
-        min_allowable = expected - THRESHOLD
-        if actual < min_allowable:
-          raise Exception('%s compression has regressed to %f' %
-            (resource_type, actual))
-
-  def uploadToGoogleStorage(self):
-    """This function uses the gsutil command to upload the local data file to
-    Google Storage.
-    """
-    gs_location = 'gs://%s/%s' % (BUCKET, DATA_FILE)
-    cmd = ['gsutil', 'cp', DATA_FILE, gs_location]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    stdout, stderr = proc.communicate()
-    if proc.returncode:
-      raise Exception('Uploading to Google Storage failed! output: %s %s' %
-        (stdout, stderr))
-
-  def fetchFromGoogleStorage(self):
-    """This function uses the gsutil command to fetch the local data file from
-    Google Storage.
-    """
-    gs_location = 'gs://%s/%s' % (BUCKET, DATA_FILE)
-    cmd = ['gsutil', 'cp', gs_location, DATA_FILE]
-    proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    stdout, stderr = proc.communicate()
-    if proc.returncode:
-      raise Exception('Fetching to Google Storage failed! output: %s %s' %
-        (stdout, stderr))
-
-  def test0UpdateDataObject_NoUpdate(self):
-    """This unit test asserts that the updateDataObject() function doesn't
-    update the data object when today is already contained in the data object.
-    """
-    data = { '2017-02-06': {'hello': 'world'}}
-    new_data = {'Benoit': 'Mandelbrot'}
-    test_day = datetime.date(2017, 02, 06)
-    changed = self.updateDataObject(new_data, data, today=test_day)
-    self.assertFalse(changed, "No data should have been recorded!")
-
-  def test0UpdateDataObject_Update(self):
-    """This unit test asserts that the updateDataObject() function updates the
-    data object when there is new data available, also removing the least recent
-    data point.
-    """
-    start_date = datetime.date(2017, 2, 6)
-    data = {}
-    for i in range(MAX_DATA_POINTS):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'hello': 'world'}
-    new_data = {'Benoit': 'Mandelbrot'}
-    test_day = datetime.date(2017, 02, 06) + datetime.timedelta(
-      days=(MAX_DATA_POINTS))
-    changed = self.updateDataObject(new_data, data, today=test_day)
-    self.assertTrue(changed, "Data should have been recorded!")
-    self.assertNotIn('2017-02-06', data)
-    self.assertIn(test_day.strftime(DATE_FORMAT), data)
-
-  def test0CheckForRegressionAverageRecent(self):
-    """Make sure the checkForRegression() uses only the most recent data points.
-    """
-    data = {}
-    start_date = datetime.date(2017, 2, 6)
-    for i in range(2 * ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.1}
-    start_date = datetime.date(2017, 2, 6) + datetime.timedelta(days=(2 *
-      ALERT_WINDOW))
-    for i in range(ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.9}
-    # Expect no exception since the most recent data should have been used.
-    self.checkForRegression(data, {'mp4': 0.9})
-
-  def test0CheckForRegressionOnlySufficientData(self):
-    """Make sure the checkForRegression() only checks resource types that have
-    at least ALERT_WINDOW many data points.
-    """
-    data = {}
-    start_date = datetime.date(2017, 2, 6)
-    for i in range(2 * ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.1}
-    start_date = datetime.date(2017, 2, 6) + datetime.timedelta(days=(2 *
-      ALERT_WINDOW))
-    for i in range(ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.9}
-    for i in range(ALERT_WINDOW / 2):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'html': 0.3}
-    # Expect no exception since the html should have been ignored for not having
-    # enough data points.
-    self.checkForRegression(data, {'mp4': 0.9, 'html': 0.1})
-
-  def test0CheckForRegressionMismatchResourceTypes(self):
-    """Make sure resource types that appear in only one of compression_average,
-    data are not used or expected.
-    """
-    # Check using an extra resource type in the compression_average object.
-    data = {}
-    start_date = datetime.date(2017, 2, 6)
-    for i in range(ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.9}
-    self.checkForRegression(data, {'mp4': 0.9, 'html': 0.2})
-    # Check using an extra resource type in the data object.
-    data = {}
-    start_date = datetime.date(2017, 2, 6)
-    for i in range(ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.9, 'html': 0.2}
-    self.checkForRegression(data, {'mp4': 0.9})
-
-  def test0CheckForRegressionNoAlert(self):
-    """Make sure checkForRegression does not alert when a new data point falls
-    on the threshold.
-    """
-    data = {}
-    start_date = datetime.date(2017, 2, 6)
-    for i in range(ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.9}
-    self.checkForRegression(data, {'mp4': (0.9 - THRESHOLD)})
-
-  def test0CheckForRegressionAlert(self):
-    """Make sure checkForRegression does alert when a new data point falls
-    outside of the threshold.
-    """
-    data = {}
-    start_date = datetime.date(2017, 2, 6)
-    for i in range(ALERT_WINDOW):
-      date_obj = start_date + datetime.timedelta(days=i)
-      datestamp = date_obj.strftime(DATE_FORMAT)
-      data[datestamp] = {'mp4': 0.9}
-    self.assertRaises(Exception, self.checkForRegression, data, {'mp4':
-      (0.9 - THRESHOLD - 0.01)})
-
-
-if __name__ == '__main__':
-  IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/safebrowsing.py b/tools/chrome_proxy/webdriver/safebrowsing.py
index 4bb099b..9ae575c 100644
--- a/tools/chrome_proxy/webdriver/safebrowsing.py
+++ b/tools/chrome_proxy/webdriver/safebrowsing.py
@@ -48,15 +48,5 @@
         self.assertEqual(1, unsafe_resources['count'])
         self.assertEqual(1, unsafe_resources['buckets'][0]['count'])
 
-  @NotAndroid
-  def testSafeBrowsingOff(self):
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.LoadURL('http://testsafebrowsing.appspot.com/s/malware.html')
-      responses = t.GetHTTPResponses()
-      self.assertEqual(1, len(responses))
-      for response in responses:
-        self.assertHasProxyHeaders(response)
-
 if __name__ == '__main__':
   IntegrationTest.RunAllTests()
diff --git a/tools/chrome_proxy/webdriver/smoke.py b/tools/chrome_proxy/webdriver/smoke.py
index 2685422..92c1236 100644
--- a/tools/chrome_proxy/webdriver/smoke.py
+++ b/tools/chrome_proxy/webdriver/smoke.py
@@ -54,35 +54,6 @@
       histogram = t.GetHistogram('DataReductionProxy.BypassTypePrimary', 5)
       self.assertEqual(histogram, {})
 
-  # Ensure Chrome does not use DataSaver when disabled via feature.
-  @ChromeVersionEqualOrAfterM(74)
-  def testCheckPageWithDataSaverFeatureDisabled(self):
-    with TestDriver() as t:
-      t.AddChromeArg('--enable-spdy-proxy-auth')
-      t.EnableChromeFeature('NetworkService')
-      t.DisableChromeFeature('DataReductionProxyEnabledWithNetworkService')
-      t.LoadURL('http://check.googlezip.net/test.html')
-      responses = t.GetHTTPResponses()
-      self.assertNotEqual(0, len(responses))
-      num_chrome_proxy_request_headers = 0
-      num_chrome_proxy_response_headers = 0
-      for response in responses:
-        self.assertNotHasChromeProxyViaHeader(response)
-        if ('chrome-proxy' in response.request_headers):
-          num_chrome_proxy_request_headers += 1
-        if ('chrome-proxy' in response.response_headers):
-          num_chrome_proxy_response_headers += 1
-      self.assertEqual(num_chrome_proxy_request_headers, 0)
-      self.assertEqual(num_chrome_proxy_response_headers, 0)
-      self.assertEqual(t.GetHistogram(
-        'DataReductionProxy.ConfigService.FetchResponseCode'), {})
-      self.assertEqual(t.GetHistogram(
-        'DataReductionProxy.WarmupURL.FetchSuccessful'), {})
-      self.assertEqual(t.GetHistogram(
-        'DataReductionProxy.BlockTypePrimary'), {})
-      self.assertEqual(t.GetHistogram(
-        'DataReductionProxy.BypassTypePrimary'), {})
-
   # Ensure Chrome uses DataSaver in normal mode.
   def testCheckPageWithNormalMode(self):
     with TestDriver() as t:
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py
index 90170c0..1577a05 100644
--- a/tools/chrome_proxy/webdriver/video.py
+++ b/tools/chrome_proxy/webdriver/video.py
@@ -8,6 +8,7 @@
 from common import TestDriver
 from common import IntegrationTest
 from common import ParseFlags
+from decorators import AndroidOnly
 from decorators import Slow
 from decorators import ChromeVersionEqualOrAfterM
 
@@ -168,6 +169,7 @@
   # Check that the compressed video can be seeked. Use a slow network to ensure
   # the entire video isn't downloaded before we have a chance to seek.
   @Slow
+  @AndroidOnly
   def testVideoSeeking(self):
     with TestDriver(control_network_connection=True) as t:
       t.SetNetworkConnection("2G")
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 225e631..e37eebc 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -3995,8 +3995,11 @@
 </histogram>
 
 <histogram name="Apps.AppListPageSwitcherSource"
-    enum="AppListPageSwitcherSource">
+    enum="AppListPageSwitcherSource" expires_after="2020-05-01">
+<!-- Name completed by histogram_suffixes name="TabletOrClamshellMode" -->
+
   <owner>newcomer@chromium.org</owner>
+  <owner>mmourgos@chromium.org</owner>
   <summary>
     The source used to switch pages in the app list's app grid. Logged when the
     page switch succeeds.
@@ -143328,6 +143331,8 @@
 <histogram_suffixes name="AppListTabletModeTransition" separator=".">
   <suffix name="DragReleaseHide" label="Release drag to hide the app list"/>
   <suffix name="DragReleaseShow" label="Release drag to show the app list"/>
+  <suffix name="EnterOverview" label="Enter overview mode in tablet"/>
+  <suffix name="ExitOverview" label="Exit overview mode in tablet"/>
   <suffix name="HideLauncherForWindow"
       label="Active a window to hide the app list"/>
   <suffix name="PressAppListButtonShow"
@@ -156231,6 +156236,7 @@
   <suffix name="ClamshellMode" label="Clamshell Mode Enabled"/>
   <suffix name="TabletMode" label="Tablet Mode Enabled"/>
   <affected-histogram name="Apps.AppListFolderNameLength"/>
+  <affected-histogram name="Apps.AppListPageSwitcherSource"/>
   <affected-histogram name="Apps.AppListSearchBoxActivated"/>
   <affected-histogram name="Apps.AppListSearchQueryLength"/>
   <affected-histogram name="Apps.AppListSearchResultOpenTypeV2"/>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index e0c94f87..923535d 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -105,6 +105,12 @@
       page was interactive.
     </summary>
   </metric>
+  <metric name="AdCpuTime">
+    <summary>
+      Amount of CPU wall time inside of ad iframes over the duration of a page
+      load, while the page is in the foreground. Measured in milliseconds.
+    </summary>
+  </metric>
   <metric name="AdJavascriptBytes">
     <summary>
       Amount of bytes used to load ad resources with a supported javascript mime
@@ -4390,6 +4396,12 @@
   <summary>
     Core metrics associated with web page loads.
   </summary>
+  <metric name="CpuTime">
+    <summary>
+      Amount of CPU wall time over the duration of a page load, while the page
+      is in the foreground. Measured in milliseconds.
+    </summary>
+  </metric>
   <metric name="DocumentTiming.NavigationToDOMContentLoadedEventFired">
     <summary>
       Measures the time in milliseconds from navigation timing's navigation
diff --git a/tools/perf/contrib/cluster_telemetry/generic_trace.py b/tools/perf/contrib/cluster_telemetry/generic_trace.py
new file mode 100644
index 0000000..653bb36
--- /dev/null
+++ b/tools/perf/contrib/cluster_telemetry/generic_trace.py
@@ -0,0 +1,103 @@
+# 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.
+
+from core import path_util
+path_util.AddTracingToPath()
+from core import perf_benchmark
+
+from contrib.cluster_telemetry import ct_benchmarks_util
+from contrib.cluster_telemetry import page_set as ct_page_set
+import page_sets
+from telemetry import benchmark
+from telemetry import timeline
+from telemetry.page import legacy_page_test
+from telemetry.value import scalar
+
+from tracing.trace_data import trace_data as trace_data_module
+
+
+class _GenericTraceMeasurement(legacy_page_test.LegacyPageTest):
+
+  def __init__(self, options):
+    super(_GenericTraceMeasurement, self).__init__()
+    self._trace_categories = ','.join(options.trace_categories)
+    trace_names = ','.join(options.trace_names).split(',')
+    self._trace_names = [name for name in trace_names if name]
+
+  def WillNavigateToPage(self, page, tab):
+    config = timeline.tracing_config.TracingConfig()
+    config.enable_chrome_trace = True
+    config.chrome_trace_config.category_filter.AddFilterString(
+        self._trace_categories)
+    tab.browser.platform.tracing_controller.StartTracing(config)
+
+  def ValidateAndMeasurePage(self, page, tab, results):
+    trace_data = tab.browser.platform.tracing_controller.StopTracing()
+    for trace in trace_data.GetTracesFor(trace_data_module.CHROME_TRACE_PART):
+      for event in trace['traceEvents']:
+        # We collect data from duration begin, complete, instant and count
+        # events. See benchmark documentation for details.
+        if event['ph'] not in ('B', 'X', 'I', 'C'):
+          continue
+        if self._trace_names and event['name'] not in self._trace_names:
+          continue
+        for arg_name, arg_value in event.get('args', {}).iteritems():
+          if not isinstance(arg_value, int):
+            continue
+          value_name = '/'.join([event['cat'], event['name'], arg_name])
+          results.AddValue(scalar.ScalarValue(
+              results.current_page, value_name, 'count', arg_value))
+
+
+class _GenericTraceBenchmark(perf_benchmark.PerfBenchmark):
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    parser.add_option('--trace-categories', default=[], action='append',
+                      help='Trace categories to enable')
+    parser.add_option('--trace-names', default=[], action='append',
+                      help='Names of trace event to collect '
+                           'If not specified, all trace events in the enabled '
+                           'categories will be collected')
+
+  @classmethod
+  def ProcessCommandLineArgs(cls, parser, args):
+    if not args.trace_categories:
+      parser.error('--trace-categories is required')
+
+  def CreatePageTest(self, options):
+    return _GenericTraceMeasurement(options)
+
+
+@benchmark.Info(emails=['wangxianzhu@chromium.org'],
+                documentation_url='https://bit.ly/2IMIMoI')
+# For local verification.
+class GenericTraceTop25(_GenericTraceBenchmark):
+  page_set = page_sets.StaticTop25PageSet
+
+  @classmethod
+  def Name(cls):
+    return 'generic_trace.top25'
+
+
+@benchmark.Info(emails=['wangxianzhu@chromium.org'],
+                documentation_url='https://bit.ly/2IMIMoI')
+class GenericTraceClusterTelemetry(_GenericTraceBenchmark):
+  @classmethod
+  def Name(cls):
+    return 'generic_trace_ct'
+
+  @classmethod
+  def AddBenchmarkCommandLineArgs(cls, parser):
+    _GenericTraceBenchmark.AddBenchmarkCommandLineArgs(parser)
+    ct_benchmarks_util.AddBenchmarkCommandLineArgs(parser)
+
+  @classmethod
+  def ProcessCommandLineArgs(cls, parser, args):
+    _GenericTraceBenchmark.ProcessCommandLineArgs(parser, args)
+    ct_benchmarks_util.ValidateCommandLineArgs(parser, args)
+
+  def CreateStorySet(self, options):
+    return ct_page_set.CTPageSet(
+        options.urls_list, options.user_agent, options.archive_data_file)
+
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 4cab5a4..74b7406 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -130,6 +130,7 @@
       }
     ],
     'platform': 'android-chrome',
+      'browser': 'bin/monochrome_64_32_bundle',
     'dimension': {
       'pool': 'chrome.tests.perf-fyi',
       'os': 'Android',
@@ -968,6 +969,8 @@
   # For trybot testing we always use the reference build
   if tester_config.get('testing', False):
     browser_name = 'reference'
+  elif 'browser' in tester_config:
+    browser_name = 'exact'
   elif tester_config['platform'] == 'android':
     browser_name = 'android-chromium'
   elif tester_config['platform'].startswith('android-'):
@@ -984,7 +987,13 @@
     '--upload-results'
   ]
 
-  if browser_name.startswith('android-webview'):
+  if 'browser' in tester_config:
+    test_args.append('--browser-executable=../../out/Release/%s' %
+                     tester_config['browser'])
+    if tester_config['platform'].startswith('android'):
+      test_args.append('--device=android')
+
+  if tester_config['platform'].startswith('android-webview'):
     test_args.append(
         '--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk')
 
diff --git a/tools/perf/core/perf_data_generator_unittest.py b/tools/perf/core/perf_data_generator_unittest.py
index 3f326e7..7697b49 100644
--- a/tools/perf/core/perf_data_generator_unittest.py
+++ b/tools/perf/core/perf_data_generator_unittest.py
@@ -97,6 +97,61 @@
       }
     self.assertEquals(returned_test, expected_generated_test)
 
+  def testGeneratePerformanceTestSuiteExact(self):
+    swarming_dimensions = [
+        {'os': 'SkyNet', 'pool': 'T-RIP'}
+    ]
+    test_config = {
+        'platform': 'android-webview',
+        'browser': 'bin/monochrome_64_32_bundle',
+        'dimension': swarming_dimensions,
+    }
+    test = {
+        'isolate': 'performance_test_suite',
+        'extra_args': [
+            '--run-ref-build',
+            '--test-shard-map-filename=shard_map.json',
+          ],
+        'num_shards': 26
+    }
+    returned_test = perf_data_generator.generate_performance_test(
+        test_config, test)
+
+    expected_generated_test = {
+        'override_compile_targets': ['performance_test_suite'],
+        'isolate_name': 'performance_test_suite',
+        'args': ['-v', '--browser=exact', '--upload-results',
+                 '--browser-executable=../../out/Release'
+                 '/bin/monochrome_64_32_bundle',
+                 '--device=android',
+                 '--webview-embedder-apk=../../out/Release'
+                 '/apks/SystemWebViewShell.apk',
+                 '--run-ref-build',
+                 '--test-shard-map-filename=shard_map.json'],
+        'trigger_script': {
+          'args': [
+            '--multiple-dimension-script-verbose',
+            'True'
+          ],
+          'requires_simultaneous_shard_dispatch': True,
+          'script': '//testing/trigger_scripts/perf_device_trigger.py'
+        },
+        'merge': {
+          'script': '//tools/perf/process_perf_results.py'
+        },
+        'swarming': {
+          'ignore_task_failure': False,
+          'can_use_on_swarming_builders': True,
+          'expiration': 7200,
+          'io_timeout': 1800,
+          'hard_timeout': 36000,
+          'dimension_sets': [[{'os': 'SkyNet', 'pool': 'T-RIP'}]],
+          'shards': 26
+        },
+        'name': 'performance_test_suite'
+      }
+    self.assertEquals(returned_test, expected_generated_test)
+
   def testGeneratePerformanceTestSuiteWebview(self):
     swarming_dimensions = [
         {'os': 'SkyNet', 'pool': 'T-RIP'}
diff --git a/tools/perf/core/perf_json_config_validator.py b/tools/perf/core/perf_json_config_validator.py
index df7cd111..7ace5f3 100644
--- a/tools/perf/core/perf_json_config_validator.py
+++ b/tools/perf/core/perf_json_config_validator.py
@@ -81,17 +81,18 @@
   browser_options = _ParseBrowserFlags(test_config['args'])
   if 'WebView' in builder_name or 'webview' in builder_name:
     if browser_options.browser not in (
-        'android-webview', 'android-webview-google'):
+        'android-webview', 'android-webview-google', 'exact'):
       raise ValueError(
-          "%s must use 'android-webview' or 'android-webview-google' browser" %
-          builder_name)
+          "%s must use 'android-webview', 'android-webview-google' or 'exact' "
+          "browser" % builder_name)
     if not browser_options.webview_embedder_apk:
       raise ValueError('%s must set --webview-embedder-apk flag' % builder_name)
   elif 'Android' in builder_name or 'android' in builder_name:
-    if browser_options.browser not in ('android-chromium', 'android-chrome'):
+    if browser_options.browser not in (
+        'android-chromium', 'android-chrome', 'exact'):
       raise ValueError(
-          "%s must use 'android-chromium' or 'android-chrome' browser" %
-          builder_name)
+          "%s must use 'android-chromium', 'android-chrome' or 'exact' "
+          "browser" % builder_name)
   elif builder_name in ('win-10-perf', 'Win 7 Nvidia GPU Perf'):
     if browser_options.browser != 'release_x64':
       raise ValueError("%s must use 'release_x64' browser type" %
diff --git a/tools/perf/validate_wpr_archives b/tools/perf/validate_wpr_archives
index 431d14f..8f10330 100755
--- a/tools/perf/validate_wpr_archives
+++ b/tools/perf/validate_wpr_archives
@@ -33,7 +33,8 @@
       'skpicture_printer',
       'cros_tab_switching.typical_24',
       'multipage_skpicture_printer',
-      'leak_detection.cluster_telemetry']
+      'leak_detection.cluster_telemetry',
+      'generic_trace_ct']
 
   for benchmark in benchmark_finders.GetAllBenchmarks():
     if benchmark.Name() in benchmarks_to_skip:
diff --git a/ui/accessibility/PRESUBMIT.py b/ui/accessibility/PRESUBMIT.py
index b5bb4259..bfcbecf 100644
--- a/ui/accessibility/PRESUBMIT.py
+++ b/ui/accessibility/PRESUBMIT.py
@@ -7,7 +7,7 @@
 import os, re, json
 
 AX_MOJOM = 'ui/accessibility/ax_enums.mojom'
-AUTOMATION_IDL = 'chrome/common/extensions/api/automation.idl'
+AUTOMATION_IDL = 'extensions/common/api/automation.idl'
 
 AX_JS_FILE = 'chrome/browser/resources/accessibility/accessibility.js'
 AX_MODE_HEADER = 'ui/accessibility/ax_mode.h'
diff --git a/ui/aura/mus/window_port_mus_unittest.cc b/ui/aura/mus/window_port_mus_unittest.cc
index 24b601d..3fa766f 100644
--- a/ui/aura/mus/window_port_mus_unittest.cc
+++ b/ui/aura/mus/window_port_mus_unittest.cc
@@ -125,7 +125,6 @@
   ASSERT_TRUE(current_id.is_valid());
   viz::ParentLocalSurfaceIdAllocator* parent_allocator =
       WindowPortMusTestHelper(&window).GetParentLocalSurfaceIdAllocator();
-  parent_allocator->Reset(current_id);
   parent_allocator->GenerateId();
   const viz::LocalSurfaceId& updated_id =
       parent_allocator->GetCurrentLocalSurfaceIdAllocation().local_surface_id();
diff --git a/ui/base/ui_base_features.cc b/ui/base/ui_base_features.cc
index b409030..e11dfd4 100644
--- a/ui/base/ui_base_features.cc
+++ b/ui/base/ui_base_features.cc
@@ -125,13 +125,8 @@
 const base::Feature kMashOopViz = {"MashOopViz",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Runs the window service in-process. Launch bug https://crbug.com/909816
 const base::Feature kSingleProcessMash = {"SingleProcessMash",
-#if defined(OS_CHROMEOS)
-                                          base::FEATURE_ENABLED_BY_DEFAULT};
-#else
                                           base::FEATURE_DISABLED_BY_DEFAULT};
-#endif
 
 #if defined(OS_CHROMEOS)
 // Connecting the client and IME engine via Mojo. https://crbug.com/937167
diff --git a/ui/base/ui_base_paths.cc b/ui/base/ui_base_paths.cc
index b3974de..11ead86 100644
--- a/ui/base/ui_base_paths.cc
+++ b/ui/base/ui_base_paths.cc
@@ -65,7 +65,7 @@
       if (!base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &cur))
         return false;
 #else
-      if (!base::PathService::Get(base::DIR_MODULE, &cur))
+      if (!base::PathService::Get(base::DIR_ASSETS, &cur))
         return false;
 #endif
       cur = cur.AppendASCII("ui_test.pak");
diff --git a/ui/events/blink/BUILD.gn b/ui/events/blink/BUILD.gn
index c95af4cf..1e825e93 100644
--- a/ui/events/blink/BUILD.gn
+++ b/ui/events/blink/BUILD.gn
@@ -5,12 +5,23 @@
 import("//build/config/jumbo.gni")
 import("//build/config/ui.gni")
 
+jumbo_component("blink_features") {
+  defines = [ "IS_BLINK_FEATURES_IMPL" ]
+
+  sources = [
+    "blink_features.cc",
+    "blink_features.h",
+  ]
+
+  deps = [
+    "//base",
+  ]
+}
+
 jumbo_source_set("blink") {
   sources = [
     "blink_event_util.cc",
     "blink_event_util.h",
-    "blink_features.cc",
-    "blink_features.h",
     "compositor_thread_event_queue.cc",
     "compositor_thread_event_queue.h",
     "did_overscroll_params.cc",
@@ -42,6 +53,10 @@
     "web_input_event_traits.h",
   ]
 
+  public_deps = [
+    ":blink_features",
+  ]
+
   deps = [
     "//cc:cc",
     "//third_party/blink/public:blink_headers",
diff --git a/ui/events/blink/blink_features.cc b/ui/events/blink/blink_features.cc
index 6e0e530..d9b953b8 100644
--- a/ui/events/blink/blink_features.cc
+++ b/ui/events/blink/blink_features.cc
@@ -30,4 +30,17 @@
 
 const base::Feature kDontSendKeyEventsToJavascript{
     "DontSendKeyEventsToJavascript", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kSkipBrowserTouchFilter{"SkipBrowserTouchFilter",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+const char kSkipBrowserTouchFilterTypeParamName[] = "type";
+const char kSkipBrowserTouchFilterTypeParamValueDiscrete[] = "discrete";
+const char kSkipBrowserTouchFilterTypeParamValueAll[] = "all";
+const char kSkipBrowserTouchFilterFilteringProcessParamName[] =
+    "skip_filtering_process";
+const char kSkipBrowserTouchFilterFilteringProcessParamValueBrowser[] =
+    "browser";
+const char
+    kSkipBrowserTouchFilterFilteringProcessParamValueBrowserAndRenderer[] =
+        "browser_and_renderer";
 }
diff --git a/ui/events/blink/blink_features.h b/ui/events/blink/blink_features.h
index 3c648d5..38f3732 100644
--- a/ui/events/blink/blink_features.h
+++ b/ui/events/blink/blink_features.h
@@ -5,45 +5,78 @@
 #ifndef UI_EVENTS_BLINK_BLINK_FEATURES_H_
 #define UI_EVENTS_BLINK_BLINK_FEATURES_H_
 
+#include "base/component_export.h"
 #include "base/feature_list.h"
 
 namespace features {
 
 // Enables resampling GestureScroll events on compositor thread.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kResamplingScrollEvents;
 
 // This flag is used to set field parameters to choose predictor we use when
 // resampling is disabled. It's used for gatherig accuracy metrics on finch
 // without enabling resampling. It does not have any effect when the resampling
 // flag is enabled.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kScrollPredictorTypeChoice;
 
 // This feature allows native ET_MOUSE_EXIT events to be passed
 // through to blink as mouse leave events. Traditionally these events were
 // converted to mouse move events due to a number of inconsistencies on
 // the native platforms. crbug.com/450631
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kSendMouseLeaveEvents;
 
 // When enabled, this feature prevents Blink from changing the hover state and
 // dispatching mouse enter/exit events for elements under the mouse after the
 // layout under the mouse cursor is changed.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kUpdateHoverFromLayoutChangeAtBeginFrame;
 
 // When enabled, this feature prevents Blink from changing the hover state and
 // dispatching mouse enter/exit events for elements under the mouse as the page
 // is scrolled.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kUpdateHoverFromScrollAtBeginFrame;
 
 // Enables handling touch events in compositor using impl side touch action
 // knowledge.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kCompositorTouchAction;
 
 // Enables fallback cursor mode for dpad devices.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kFallbackCursorMode;
 
 // When enabled, this feature prevent blink sending key event to web unless it
 // is on installed PWA.
+COMPONENT_EXPORT(BLINK_FEATURES)
 extern const base::Feature kDontSendKeyEventsToJavascript;
+
+// Skips the browser touch event filter, ensuring that events that reach the
+// queue and would otherwise be filtered out will instead be passed onto the
+// renderer compositor process as long as the page hasn't timed out. If
+// skip_filtering_process is browser_and_renderer, also skip the renderer cc
+// touch event filter, ensuring that events will be passed onto the renderer
+// main thread. Which event types will be always forwarded is controlled by the
+// "type" FeatureParam,
+// which can be either "discrete" (default) or "all".
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const base::Feature kSkipBrowserTouchFilter;
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const char kSkipBrowserTouchFilterTypeParamName[];
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const char kSkipBrowserTouchFilterTypeParamValueDiscrete[];
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const char kSkipBrowserTouchFilterTypeParamValueAll[];
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const char kSkipBrowserTouchFilterFilteringProcessParamName[];
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const char kSkipBrowserTouchFilterFilteringProcessParamValueBrowser[];
+COMPONENT_EXPORT(BLINK_FEATURES)
+extern const char
+    kSkipBrowserTouchFilterFilteringProcessParamValueBrowserAndRenderer[];
 }
 
 #endif  // UI_EVENTS_BLINK_BLINK_FEATURES_H_
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index b2e2ff67c..96db4e8b 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -13,6 +13,7 @@
 #include "base/command_line.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -182,6 +183,24 @@
   compositor_event_queue_ = std::make_unique<CompositorThreadEventQueue>();
   scroll_predictor_ = std::make_unique<ScrollPredictor>(
       base::FeatureList::IsEnabled(features::kResamplingScrollEvents));
+
+  if (base::FeatureList::IsEnabled(features::kSkipBrowserTouchFilter) &&
+      GetFieldTrialParamValueByFeature(
+          features::kSkipBrowserTouchFilter,
+          features::kSkipBrowserTouchFilterFilteringProcessParamName) ==
+          features::
+              kSkipBrowserTouchFilterFilteringProcessParamValueBrowserAndRenderer) {
+    // Skipping filtering for touch events on renderer process is enabled.
+    // Always skip filtering discrete events.
+    skip_touch_filter_discrete_ = true;
+    if (GetFieldTrialParamValueByFeature(
+            features::kSkipBrowserTouchFilter,
+            features::kSkipBrowserTouchFilterTypeParamName) ==
+        features::kSkipBrowserTouchFilterTypeParamValueAll) {
+      // The experiment config also specifies to skip touchmove events.
+      skip_touch_filter_all_ = true;
+    }
+  }
 }
 
 InputHandlerProxy::~InputHandlerProxy() {}
diff --git a/ui/events/blink/input_handler_proxy.h b/ui/events/blink/input_handler_proxy.h
index 99fbc64..3275b97 100644
--- a/ui/events/blink/input_handler_proxy.h
+++ b/ui/events/blink/input_handler_proxy.h
@@ -239,6 +239,12 @@
   // tests and to allow testing both Blink and CC input handling paths.
   bool force_input_to_main_thread_;
 
+  // These flags are set for the SkipBrowserTouchFilter experiment. The
+  // experiment either skips filtering discrete (touch start/end) events to the
+  // main thread, or all events (touch start/end/move).
+  bool skip_touch_filter_discrete_ = false;
+  bool skip_touch_filter_all_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(InputHandlerProxy);
 };
 
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 71cc0244..708e4f71 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -647,7 +647,6 @@
 
   data = [
     "test/data/",
-    "$root_out_dir/ui_test.pak",
   ]
 
   if (!is_ios) {
@@ -692,6 +691,7 @@
       "mac/coordinate_conversion_unittest.mm",
       "mojo/struct_traits_unittest.cc",
       "nine_image_painter_unittest.cc",
+      "paint_vector_icon_unittest.cc",
       "path_mac_unittest.mm",
       "platform_font_mac_unittest.mm",
       "range/range_mac_unittest.mm",
@@ -706,16 +706,13 @@
       "transform_util_unittest.cc",
       "utf16_indexing_unittest.cc",
     ]
+    data += [ "$root_out_dir/ui_test.pak" ]
   }
 
   if (is_linux || is_android || is_fuchsia) {
     sources += [ "platform_font_skia_unittest.cc" ]
   }
 
-  if (!is_ios) {
-    sources += [ "paint_vector_icon_unittest.cc" ]
-  }
-
   deps = [
     ":gfx",
     ":test_support",
@@ -745,6 +742,10 @@
     "//ui/resources:ui_test_pak",
   ]
 
+  if (is_mac || is_ios) {
+    deps += [ "//ui/resources:ui_test_pak_bundle_data" ]
+  }
+
   if (!is_mac && !is_ios) {
     sources += [
       "interpolated_transform_unittest.cc",
diff --git a/ui/message_center/views/notification_view_md.cc b/ui/message_center/views/notification_view_md.cc
index 022ed60..c73a739 100644
--- a/ui/message_center/views/notification_view_md.cc
+++ b/ui/message_center/views/notification_view_md.cc
@@ -1225,7 +1225,7 @@
 }
 
 void NotificationViewMD::ToggleInlineSettings(const ui::Event& event) {
-  if (!weak_ptr_factory_.GetWeakPtr() || !settings_row_)
+  if (!settings_row_)
     return;
 
   bool inline_settings_visible = !settings_row_->visible();
@@ -1242,12 +1242,15 @@
   dont_block_button_->SetChecked(true);
 
   SetSettingMode(inline_settings_visible);
-  SetExpanded(!inline_settings_visible);
 
-  // Check |this| is valid before continuing, because SetExpanded() might
-  // cause |this| to be deleted.
-  if (!weak_ptr_factory_.GetWeakPtr())
-    return;
+  // Grab a weak pointer before calling SetExpanded() as it might cause |this|
+  // to be deleted.
+  {
+    auto weak_ptr = weak_ptr_factory_.GetWeakPtr();
+    SetExpanded(!inline_settings_visible);
+    if (!weak_ptr)
+      return;
+  }
 
   PreferredSizeChanged();
 
diff --git a/ui/strings/ui_strings.grd b/ui/strings/ui_strings.grd
index 910e125..73be52c 100644
--- a/ui/strings/ui_strings.grd
+++ b/ui/strings/ui_strings.grd
@@ -879,6 +879,9 @@
       <message name="IDS_APP_LIST_START_ASSISTANT" desc="Tooltip for the button that starts Google Assistant from the search box in the app list.">
         Start Google Assistant
       </message>
+      <message name="IDS_APP_LIST_START_ASSISTANT_VOICE_QUERY" desc="Tooltip for the button that starts Google Assistant voice query from the search box in the app list.">
+        Start Google Assistant voice query
+      </message>
       <message name="IDS_APP_LIST_PAGE_SWITCHER" desc="Tooltip for page switcher for each page in fullscreen view which shows all apps.">
         Page <ph name="selected_page">$1<ex>1</ex></ph> of <ph name="total_page_num">$2<ex>3</ex></ph>
       </message>
diff --git a/ui/views/widget/root_view.cc b/ui/views/widget/root_view.cc
index 5b7654d..ace5071 100644
--- a/ui/views/widget/root_view.cc
+++ b/ui/views/widget/root_view.cc
@@ -32,11 +32,6 @@
 
 namespace {
 
-enum EventType {
-  EVENT_ENTER,
-  EVENT_EXIT
-};
-
 class MouseEnterExitEvent : public ui::MouseEvent {
  public:
   MouseEnterExitEvent(const ui::MouseEvent& event, ui::EventType type)
diff --git a/ui/webui/resources/cr_elements/cr_icons_css.html b/ui/webui/resources/cr_elements/cr_icons_css.html
index 7a99559..6350c34 100644
--- a/ui/webui/resources/cr_elements/cr_icons_css.html
+++ b/ui/webui/resources/cr_elements/cr_icons_css.html
@@ -137,17 +137,6 @@
 
       :-webkit-any(paper-icon-button-light,
                    cr-icon-button,
-                   .cr-icon).icon-toolbar-menu {
-        background-image: url(../images/icon_toolbar_menu.svg);
-      }
-      :host-context([dark]) :-webkit-any(paper-icon-button-light,
-                                         cr-icon-button,
-                                         .cr-icon).icon-toolbar-menu {
-        background-image: url(../images/dark/icon_toolbar_menu.svg);
-      }
-
-      :-webkit-any(paper-icon-button-light,
-                   cr-icon-button,
                    .cr-icon).icon-more-vert {
         background-image: url(../images/icon_more_vert.svg);
       }
diff --git a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
index 11b4018..9504afa 100644
--- a/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
+++ b/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html
@@ -144,6 +144,17 @@
         padding: 0;
         width: 20px;
       }
+
+      #menuButton {
+        -webkit-mask-image: url(../../images/icon_toolbar_menu.svg);
+        -webkit-mask-position: center;
+        -webkit-mask-repeat: no-repeat;
+        background: currentColor;
+      }
+
+      :host-context([dark]) #menuButton {
+        -webkit-mask-image: url(../../images/dark/icon_toolbar_menu.svg);
+      }
     </style>
     <div id="leftContent">
       <div id="leftSpacer">