diff --git a/.gitignore b/.gitignore
index f9873bb..8a02255 100644
--- a/.gitignore
+++ b/.gitignore
@@ -265,6 +265,7 @@
 /tools/json_schema_compiler/test/json_schema_compiler_tests.xml
 /tools/metrics/actions/actions.old.xml
 /tools/metrics/histograms/histograms.before.pretty-print.xml
+/tools/metrics/histograms/enums.before.pretty-print.xml
 /tools/page_cycler/acid3
 /tools/swarming_client
 /tools/tryserver
diff --git a/DEPS b/DEPS
index dc23976..9657762 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,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': '68300c270916b2740fccdbe6c6dce8f085e83316',
+  'skia_revision': 'f3ac64df17419f7fa6af2eeed5092638e956e196',
   # 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': '1e6d83a22470cb8b04ed423ceeaafc591c45132f',
+  'v8_revision': '2428efd5f811501d51f9bbd7ddf4aa5f927e3390',
   # 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.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': '91b8302dec04ca4ddc1f91545d192350665580cf',
+  'pdfium_revision': '893e730d5c4d58fc67a5b335d5b7a601262f457e',
   # 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.
@@ -165,7 +165,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': 'c829a63538ba53b1f31e3d2eb2e2fdd6f390619a',
+  'catapult_revision': '42016a47fa2b5e8b2bdb90615385a67d16589499',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -539,7 +539,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd81364a25e1e01848eddbd45a2e5fb2b9598bbb8',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '3190ae3f2fd39e2fb98b30912fc6a948bb049317',
       'condition': 'checkout_linux',
   },
 
@@ -564,7 +564,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'ad463c9517e348df1ea5cb5f0f9a615365f52bf6',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '254538b955bd353e28da028e09c1f808367a4bf4',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1034,7 +1034,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '21dbf06b5aa6c7dc8cf56314d4a3f96f57956c53',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '625efe6dfe5b5681a2d8d3d5ecaa0c5ac9edd6ee',
+    Var('webrtc_git') + '/src.git' + '@' + '6031e69d34ff60080f2ef796bda9eb7b189e1a3f',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 4e1a7a9f..2623a194 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -100,6 +100,14 @@
       background_task_runner, io_task_runner);
 }
 
+base::FilePath GetCacheDirForAw() {
+  FilePath cache_path;
+  base::PathService::Get(base::DIR_CACHE, &cache_path);
+  cache_path =
+      cache_path.Append(FILE_PATH_LITERAL("org.chromium.android_webview"));
+  return cache_path;
+}
+
 }  // namespace
 
 AwBrowserContext::AwBrowserContext(const FilePath path)
@@ -133,10 +141,7 @@
 }
 
 void AwBrowserContext::PreMainMessageLoopRun(net::NetLog* net_log) {
-  FilePath cache_path;
-  base::PathService::Get(base::DIR_CACHE, &cache_path);
-  cache_path =
-      cache_path.Append(FILE_PATH_LITERAL("org.chromium.android_webview"));
+  FilePath cache_path = GetCacheDirForAw();
 
   browser_policy_connector_.reset(new AwBrowserPolicyConnector());
 
@@ -251,6 +256,10 @@
   return context_storage_path_;
 }
 
+base::FilePath AwBrowserContext::GetCachePath() const {
+  return GetCacheDirForAw();
+}
+
 bool AwBrowserContext::IsOffTheRecord() const {
   // Android WebView does not support off the record profile yet.
   return false;
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index 80b40be..7fc8783 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -92,6 +92,7 @@
 
   // content::BrowserContext implementation.
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
   bool IsOffTheRecord() const override;
   content::ResourceContext* GetResourceContext() override;
   content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index cdaea7f..35e2af9 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -876,9 +876,9 @@
 
     private void initWebContents(ViewAndroidDelegate viewDelegate,
             InternalAccessDelegate internalDispatcher, WebContents webContents,
-            WindowAndroid windowAndroid) {
+            WindowAndroid windowAndroid, WebContentsInternalsHolder internalsHolder) {
         webContents.initialize(
-                mContext, PRODUCT_VERSION, viewDelegate, internalDispatcher, windowAndroid);
+                PRODUCT_VERSION, viewDelegate, internalDispatcher, windowAndroid, internalsHolder);
         mViewEventSink = ViewEventSink.from(mWebContents);
         mViewEventSink.setHideKeyboardOnBlur(false);
         SelectionPopupController controller = SelectionPopupController.fromWebContents(webContents);
@@ -1162,12 +1162,11 @@
         mWindowAndroid = getWindowAndroid(mContext);
         mViewAndroidDelegate =
                 new AwViewAndroidDelegate(mContainerView, mContentsClient, mScrollOffsetManager);
+        mWebContentsInternalsHolder = new WebContentsInternalsHolder(this);
         initWebContents(mViewAndroidDelegate, mInternalAccessAdapter, mWebContents,
-                mWindowAndroid.getWindowAndroid());
+                mWindowAndroid.getWindowAndroid(), mWebContentsInternalsHolder);
         nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge,
                 mIoThreadClient, mInterceptNavigationDelegate, mAutofillProvider);
-        mWebContentsInternalsHolder = new WebContentsInternalsHolder(this);
-        mWebContents.setInternalsHolder(mWebContentsInternalsHolder);
         GestureListenerManager.fromWebContents(mWebContents)
                 .addListener(new AwGestureStateListener());
 
diff --git a/apps/saved_files_service.cc b/apps/saved_files_service.cc
index 1279b2f3..1047ef6 100644
--- a/apps/saved_files_service.cc
+++ b/apps/saved_files_service.cc
@@ -67,7 +67,7 @@
 
   std::unique_ptr<base::DictionaryValue> file_entry_dict =
       std::make_unique<base::DictionaryValue>();
-  file_entry_dict->Set(kFileEntryPath, CreateFilePathValue(file_entry.path));
+  file_entry_dict->SetKey(kFileEntryPath, CreateFilePathValue(file_entry.path));
   file_entry_dict->SetBoolean(kFileEntryIsDirectory, file_entry.is_directory);
   file_entry_dict->SetInteger(kFileEntrySequenceNumber,
                               file_entry.sequence_number);
diff --git a/ash/accelerators/accelerator_confirmation_dialog.cc b/ash/accelerators/accelerator_confirmation_dialog.cc
index 0c32270..dfda806a 100644
--- a/ash/accelerators/accelerator_confirmation_dialog.cc
+++ b/ash/accelerators/accelerator_confirmation_dialog.cc
@@ -38,13 +38,13 @@
 
   // Parent the dialog widget to the LockSystemModalContainer to ensure that it
   // gets displayed on lock/signin screen.
-  gfx::NativeView parent = Shell::GetContainer(
-      ash::Shell::GetPrimaryRootWindow(), kShellWindowId_SystemModalContainer);
-  if (Shell::Get()->session_controller()->IsUserSessionBlocked())
-    parent = Shell::GetContainer(ash::Shell::GetPrimaryRootWindow(),
-                                 kShellWindowId_LockSystemModalContainer);
-
-  views::Widget* widget = CreateDialogWidget(this, nullptr, parent);
+  views::Widget* widget = CreateDialogWidget(
+      this, nullptr,
+      Shell::GetContainer(
+          ash::Shell::GetPrimaryRootWindow(),
+          Shell::Get()->session_controller()->IsUserSessionBlocked()
+              ? kShellWindowId_LockSystemModalContainer
+              : kShellWindowId_SystemModalContainer));
   widget->Show();
 }
 
diff --git a/ash/system/bluetooth/bluetooth_feature_pod_controller.cc b/ash/system/bluetooth/bluetooth_feature_pod_controller.cc
index 5d81781..709eb56 100644
--- a/ash/system/bluetooth/bluetooth_feature_pod_controller.cc
+++ b/ash/system/bluetooth/bluetooth_feature_pod_controller.cc
@@ -5,6 +5,7 @@
 #include "ash/system/bluetooth/bluetooth_feature_pod_controller.h"
 
 #include "ash/resources/vector_icons/vector_icons.h"
+#include "ash/session/session_controller.h"
 #include "ash/shell.h"
 #include "ash/strings/grit/ash_strings.h"
 #include "ash/system/bluetooth/tray_bluetooth_helper.h"
@@ -59,6 +60,18 @@
   if (!is_available)
     return;
 
+  // Bluetooth power setting is always mutable in login screen before any
+  // user logs in. The changes will affect local state preferences.
+  //
+  // Otherwise, the bluetooth setting should be mutable only if:
+  // * the active user is the primary user, and
+  // * the session is not in lock screen
+  // The changes will affect the primary user's preferences.
+  SessionController* session_controller = Shell::Get()->session_controller();
+  button_->SetEnabled(!session_controller->IsActiveUserSessionStarted() ||
+                      (session_controller->IsUserPrimary() &&
+                       !session_controller->IsScreenLocked()));
+
   bool is_enabled =
       Shell::Get()->tray_bluetooth_helper()->GetBluetoothEnabled();
   button_->SetToggled(is_enabled);
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h
index 5d01892..14bef6e 100644
--- a/ash/system/tray/tray_constants.h
+++ b/ash/system/tray/tray_constants.h
@@ -143,12 +143,16 @@
     SkColorSetA(kUnifiedMenuIconColor, 0xa3);
 constexpr SkColor kUnifiedMenuIconColorDisabled =
     SkColorSetA(kUnifiedMenuIconColor, 0xa3);
+constexpr SkColor kUnifiedMenuTextColorDisabled =
+    SkColorSetA(kUnifiedMenuTextColor, 0xa3);
 constexpr SkColor kUnifiedMenuButtonColor =
     SkColorSetA(kUnifiedMenuIconColor, 0x14);
 constexpr SkColor kUnifiedMenuSeparatorColor =
     SkColorSetA(kUnifiedMenuIconColor, 0x23);
 constexpr SkColor kUnifiedMenuButtonColorActive =
     SkColorSetRGB(0x25, 0x81, 0xdf);
+constexpr SkColor kUnifiedMenuButtonColorDisabled =
+    SkColorSetA(kUnifiedMenuButtonColor, 0xa);
 constexpr SkColor kUnifiedNotificationSeparatorColor =
     SkColorSetRGB(0xdf, 0xe0, 0xe0);
 constexpr SkColor kUnifiedFeaturePodHoverColor =
diff --git a/ash/system/unified/collapse_button.cc b/ash/system/unified/collapse_button.cc
index fcd5581..3bae80f 100644
--- a/ash/system/unified/collapse_button.cc
+++ b/ash/system/unified/collapse_button.cc
@@ -94,7 +94,8 @@
 void CustomShapeButton::PaintCustomShapePath(gfx::Canvas* canvas) {
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-  flags.setColor(kUnifiedMenuButtonColor);
+  flags.setColor(enabled() ? kUnifiedMenuButtonColor
+                           : kUnifiedMenuButtonColorDisabled);
   flags.setStyle(cc::PaintFlags::kFill_Style);
 
   canvas->DrawPath(CreateCustomShapePath(GetLocalBounds()), flags);
@@ -102,9 +103,7 @@
 
 CollapseButton::CollapseButton(views::ButtonListener* listener)
     : CustomShapeButton(listener) {
-  SetImage(
-      views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(kUnifiedMenuExpandIcon, kUnifiedMenuIconColor));
+  OnEnabledChanged();
 }
 
 CollapseButton::~CollapseButton() = default;
@@ -119,6 +118,14 @@
   SchedulePaint();
 }
 
+void CollapseButton::OnEnabledChanged() {
+  SetImage(views::Button::STATE_NORMAL,
+           gfx::CreateVectorIcon(kUnifiedMenuExpandIcon,
+                                 enabled() ? kUnifiedMenuIconColor
+                                           : kUnifiedMenuIconColorDisabled));
+  SchedulePaint();
+}
+
 gfx::Size CollapseButton::CalculatePreferredSize() const {
   return gfx::Size(kTrayItemSize, kTrayItemSize * 3 / 2);
 }
diff --git a/ash/system/unified/collapse_button.h b/ash/system/unified/collapse_button.h
index e02a601..c2997e10 100644
--- a/ash/system/unified/collapse_button.h
+++ b/ash/system/unified/collapse_button.h
@@ -47,6 +47,7 @@
   void SetExpandedAmount(double expanded_amount);
 
   // CustomShapeButton:
+  void OnEnabledChanged() override;
   gfx::Size CalculatePreferredSize() const override;
   SkPath CreateCustomShapePath(const gfx::Rect& bounds) const override;
   void PaintButtonContents(gfx::Canvas* canvas) override;
diff --git a/ash/system/unified/feature_pod_button.cc b/ash/system/unified/feature_pod_button.cc
index 3e01314..6ddf986 100644
--- a/ash/system/unified/feature_pod_button.cc
+++ b/ash/system/unified/feature_pod_button.cc
@@ -53,8 +53,16 @@
   gfx::Rect rect(GetContentsBounds());
   cc::PaintFlags flags;
   flags.setAntiAlias(true);
-  flags.setColor(toggled_ ? kUnifiedMenuButtonColorActive
-                          : kUnifiedMenuButtonColor);
+
+  SkColor color = kUnifiedMenuButtonColor;
+  if (enabled()) {
+    if (toggled_)
+      color = kUnifiedMenuButtonColorActive;
+  } else {
+    color = kUnifiedMenuButtonColorDisabled;
+  }
+  flags.setColor(color);
+
   flags.setStyle(cc::PaintFlags::kFill_Style);
   canvas->DrawCircle(gfx::PointF(rect.CenterPoint()), rect.width() / 2, flags);
 
@@ -104,15 +112,13 @@
 
   ConfigureFeaturePodLabel(label_);
   ConfigureFeaturePodLabel(sub_label_);
-  label_->SetEnabledColor(kUnifiedMenuTextColor);
-  sub_label_->SetEnabledColor(kUnifiedMenuSecondaryTextColor);
   sub_label_->SetVisible(false);
 
   detailed_view_arrow_->set_can_process_events_within_subtree(false);
-  detailed_view_arrow_->SetImage(
-      gfx::CreateVectorIcon(kUnifiedMenuMoreIcon, kUnifiedMenuIconColor));
   detailed_view_arrow_->SetVisible(false);
 
+  OnEnabledChanged();
+
   AddChildView(label_);
   AddChildView(detailed_view_arrow_);
   AddChildView(sub_label_);
@@ -142,6 +148,17 @@
       arrow_size));
 }
 
+void FeaturePodLabelButton::OnEnabledChanged() {
+  label_->SetEnabledColor(enabled() ? kUnifiedMenuTextColor
+                                    : kUnifiedMenuTextColorDisabled);
+  sub_label_->SetEnabledColor(enabled() ? kUnifiedMenuSecondaryTextColor
+                                        : kUnifiedMenuTextColorDisabled);
+  detailed_view_arrow_->SetImage(gfx::CreateVectorIcon(
+      kUnifiedMenuMoreIcon,
+      enabled() ? kUnifiedMenuIconColor : kUnifiedMenuIconColorDisabled));
+  SchedulePaint();
+}
+
 gfx::Size FeaturePodLabelButton::CalculatePreferredSize() const {
   // Minimum width of the button
   int width = kUnifiedFeaturePodLabelWidth + GetInsets().width();
@@ -243,6 +260,9 @@
 void FeaturePodButton::SetVectorIcon(const gfx::VectorIcon& icon) {
   icon_button_->SetImage(views::Button::STATE_NORMAL,
                          gfx::CreateVectorIcon(icon, kUnifiedMenuIconColor));
+  icon_button_->SetImage(
+      views::Button::STATE_DISABLED,
+      gfx::CreateVectorIcon(icon, kUnifiedMenuIconColorDisabled));
 }
 
 void FeaturePodButton::SetLabel(const base::string16& label) {
@@ -291,6 +311,12 @@
   label_button_->RequestFocus();
 }
 
+void FeaturePodButton::OnEnabledChanged() {
+  icon_button_->SetEnabled(enabled());
+  label_button_->SetEnabled(enabled());
+  SchedulePaint();
+}
+
 void FeaturePodButton::ButtonPressed(views::Button* sender,
                                      const ui::Event& event) {
   if (sender == label_button_) {
diff --git a/ash/system/unified/feature_pod_button.h b/ash/system/unified/feature_pod_button.h
index 040bba3c..137cd27 100644
--- a/ash/system/unified/feature_pod_button.h
+++ b/ash/system/unified/feature_pod_button.h
@@ -65,6 +65,7 @@
 
   // views::Button:
   void Layout() override;
+  void OnEnabledChanged() override;
   gfx::Size CalculatePreferredSize() const override;
   std::unique_ptr<views::InkDrop> CreateInkDrop() override;
   std::unique_ptr<views::InkDropRipple> CreateInkDropRipple() const override;
@@ -127,6 +128,7 @@
   void SetVisible(bool visible) override;
   bool HasFocus() const override;
   void RequestFocus() override;
+  void OnEnabledChanged() override;
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
diff --git a/ash/system/unified/top_shortcuts_view.cc b/ash/system/unified/top_shortcuts_view.cc
index 6125f38..ab4bada 100644
--- a/ash/system/unified/top_shortcuts_view.cc
+++ b/ash/system/unified/top_shortcuts_view.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/top_shortcuts_view.h"
 
+#include "ash/accessibility/accessibility_controller.h"
 #include "ash/public/cpp/ash_view_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/session/session_controller.h"
@@ -176,9 +177,15 @@
 
   collapse_button_ = new CollapseButton(this);
   AddChildView(collapse_button_);
+
+  OnAccessibilityStatusChanged();
+
+  Shell::Get()->accessibility_controller()->AddObserver(this);
 }
 
-TopShortcutsView::~TopShortcutsView() = default;
+TopShortcutsView::~TopShortcutsView() {
+  Shell::Get()->accessibility_controller()->RemoveObserver(this);
+}
 
 void TopShortcutsView::SetExpandedAmount(double expanded_amount) {
   collapse_button_->SetExpandedAmount(expanded_amount);
@@ -209,4 +216,9 @@
     controller_->ToggleExpanded();
 }
 
+void TopShortcutsView::OnAccessibilityStatusChanged() {
+  collapse_button_->SetEnabled(
+      !Shell::Get()->accessibility_controller()->IsSpokenFeedbackEnabled());
+}
+
 }  // namespace ash
diff --git a/ash/system/unified/top_shortcuts_view.h b/ash/system/unified/top_shortcuts_view.h
index a8d29a66..68c0c3f 100644
--- a/ash/system/unified/top_shortcuts_view.h
+++ b/ash/system/unified/top_shortcuts_view.h
@@ -5,6 +5,7 @@
 #ifndef ASH_SYSTEM_UNIFIED_TOP_SHORTCUTS_VIEW_H_
 #define ASH_SYSTEM_UNIFIED_TOP_SHORTCUTS_VIEW_H_
 
+#include "ash/accessibility/accessibility_observer.h"
 #include "ash/ash_export.h"
 #include "ui/views/controls/button/button.h"
 #include "ui/views/view.h"
@@ -40,7 +41,8 @@
 
 // Top shortcuts view shown on the top of UnifiedSystemTrayView.
 class ASH_EXPORT TopShortcutsView : public views::View,
-                                    public views::ButtonListener {
+                                    public views::ButtonListener,
+                                    public AccessibilityObserver {
  public:
   explicit TopShortcutsView(UnifiedSystemTrayController* controller);
   ~TopShortcutsView() override;
@@ -55,6 +57,9 @@
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
 
+  // AccessibilityObserver:
+  void OnAccessibilityStatusChanged() override;
+
  private:
   friend class TopShortcutsViewTest;
 
diff --git a/ash/system/unified/unified_system_tray_controller.cc b/ash/system/unified/unified_system_tray_controller.cc
index c8af0b4..1b42652 100644
--- a/ash/system/unified/unified_system_tray_controller.cc
+++ b/ash/system/unified/unified_system_tray_controller.cc
@@ -62,7 +62,7 @@
     : model_(model),
       bubble_(bubble),
       animation_(std::make_unique<gfx::SlideAnimation>(this)) {
-  animation_->Reset(model->expanded_on_open() ? 1.0 : 0.0);
+  animation_->Reset(model->IsExpandedOnOpen() ? 1.0 : 0.0);
   animation_->SetSlideDuration(kExpandAnimationDurationMs);
   animation_->SetTweenType(gfx::Tween::EASE_IN_OUT);
 }
@@ -71,7 +71,7 @@
 
 UnifiedSystemTrayView* UnifiedSystemTrayController::CreateView() {
   DCHECK(!unified_view_);
-  unified_view_ = new UnifiedSystemTrayView(this, model_->expanded_on_open());
+  unified_view_ = new UnifiedSystemTrayView(this, model_->IsExpandedOnOpen());
   InitFeaturePods();
 
   volume_slider_controller_ =
diff --git a/ash/system/unified/unified_system_tray_controller_unittest.cc b/ash/system/unified/unified_system_tray_controller_unittest.cc
index 23d93fd..b6ecf67 100644
--- a/ash/system/unified/unified_system_tray_controller_unittest.cc
+++ b/ash/system/unified/unified_system_tray_controller_unittest.cc
@@ -100,7 +100,7 @@
 };
 
 TEST_F(UnifiedSystemTrayControllerTest, ToggleExpanded) {
-  EXPECT_TRUE(model()->expanded_on_open());
+  EXPECT_TRUE(model()->IsExpandedOnOpen());
   const int expanded_height = view()->GetPreferredSize().height();
 
   controller()->ToggleExpanded();
@@ -108,7 +108,7 @@
 
   const int collapsed_height = view()->GetPreferredSize().height();
   EXPECT_LT(collapsed_height, expanded_height);
-  EXPECT_FALSE(model()->expanded_on_open());
+  EXPECT_FALSE(model()->IsExpandedOnOpen());
 }
 
 TEST_F(UnifiedSystemTrayControllerTest, PreferredSizeChanged) {
diff --git a/ash/system/unified/unified_system_tray_model.cc b/ash/system/unified/unified_system_tray_model.cc
index 2cad65b..afb57ba 100644
--- a/ash/system/unified/unified_system_tray_model.cc
+++ b/ash/system/unified/unified_system_tray_model.cc
@@ -4,6 +4,7 @@
 
 #include "ash/system/unified/unified_system_tray_model.h"
 
+#include "ash/accessibility/accessibility_controller.h"
 #include "ash/shell.h"
 #include "ash/system/brightness_control_delegate.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -86,6 +87,11 @@
   observers_.RemoveObserver(observer);
 }
 
+bool UnifiedSystemTrayModel::IsExpandedOnOpen() const {
+  return expanded_on_open_ ||
+         Shell::Get()->accessibility_controller()->IsSpokenFeedbackEnabled();
+}
+
 void UnifiedSystemTrayModel::DisplayBrightnessChanged(float brightness,
                                                       bool by_user) {
   display_brightness_ = brightness;
diff --git a/ash/system/unified/unified_system_tray_model.h b/ash/system/unified/unified_system_tray_model.h
index 6b6ad630..07e5796c 100644
--- a/ash/system/unified/unified_system_tray_model.h
+++ b/ash/system/unified/unified_system_tray_model.h
@@ -31,7 +31,8 @@
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
 
-  bool expanded_on_open() const { return expanded_on_open_; }
+  bool IsExpandedOnOpen() const;
+
   float display_brightness() const { return display_brightness_; }
   float keyboard_brightness() const { return keyboard_brightness_; }
 
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc
index f117283..21d21b11 100644
--- a/ash/wallpaper/wallpaper_view.cc
+++ b/ash/wallpaper/wallpaper_view.cc
@@ -196,7 +196,8 @@
     }
     case WALLPAPER_LAYOUT_TILE: {
       canvas->TileImageInt(wallpaper, 0, 0, 0, 0, width(), height(), 1.0f,
-                           &flags);
+                           SkShader::kRepeat_TileMode,
+                           SkShader::kRepeat_TileMode, &flags);
       break;
     }
     case WALLPAPER_LAYOUT_STRETCH: {
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 94e90b1..0da4dfa 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -821,6 +821,7 @@
     "system_monitor/system_monitor.h",
     "task/cancelable_task_tracker.cc",
     "task/cancelable_task_tracker.h",
+    "task/sequence_manager/associated_thread_id.h",
     "task/sequence_manager/enqueue_order.cc",
     "task/sequence_manager/enqueue_order.h",
     "task/sequence_manager/graceful_queue_shutdown_helper.cc",
@@ -843,6 +844,8 @@
     "task/sequence_manager/task_queue_selector.cc",
     "task/sequence_manager/task_queue_selector.h",
     "task/sequence_manager/task_queue_selector_logic.h",
+    "task/sequence_manager/task_queue_task_runner.cc",
+    "task/sequence_manager/task_queue_task_runner.h",
     "task/sequence_manager/task_time_observer.h",
     "task/sequence_manager/thread_controller.h",
     "task/sequence_manager/thread_controller_impl.cc",
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 3723960a..368deea 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -344,13 +344,16 @@
 
 void MessageLoop::SetTaskRunner(
     scoped_refptr<SingleThreadTaskRunner> task_runner) {
-  DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
-
   DCHECK(task_runner);
-  DCHECK(task_runner->BelongsToCurrentThread());
-  DCHECK(!unbound_task_runner_);
-  task_runner_ = std::move(task_runner);
-  SetThreadTaskRunnerHandle();
+  if (!unbound_task_runner_) {
+    DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
+    DCHECK(task_runner->BelongsToCurrentThread());
+    task_runner_ = std::move(task_runner);
+    SetThreadTaskRunnerHandle();
+  } else {
+    // ThreadTaskRunnerHandle will be set during BindToCurrentThread().
+    task_runner_ = std::move(task_runner);
+  }
 }
 
 void MessageLoop::ClearTaskRunnerForTesting() {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 7c31a12..efb0ce48 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -165,11 +165,8 @@
     return task_runner_;
   }
 
-  // Sets a new TaskRunner for this message loop. The message loop must already
-  // have been bound to a thread prior to this call, and the task runner must
-  // belong to that thread. Note that changing the task runner will also affect
-  // the ThreadTaskRunnerHandle for the target thread. Must be called on the
-  // thread to which the message loop is bound.
+  // Sets a new TaskRunner for this message loop. If the message loop was
+  // already bound, this must be called on the thread to which it is bound.
   void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
 
   // Clears task_runner() and the ThreadTaskRunnerHandle for the target thread.
diff --git a/base/task/sequence_manager/associated_thread_id.h b/base/task/sequence_manager/associated_thread_id.h
new file mode 100644
index 0000000..3b55722
--- /dev/null
+++ b/base/task/sequence_manager/associated_thread_id.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_
+#define BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+namespace sequence_manager {
+namespace internal {
+
+// TODO(eseckler): Make this owned by SequenceManager once the TaskQueue
+// refactor has happened (https://crbug.com/865411).
+struct BASE_EXPORT AssociatedThreadId
+    : public base::RefCountedThreadSafe<AssociatedThreadId> {
+ public:
+  PlatformThreadId thread_id = kInvalidThreadId;
+  // TODO(eseckler): Replace thread_checker with sequence_checker everywhere.
+  THREAD_CHECKER(thread_checker);
+  SEQUENCE_CHECKER(sequence_checker);
+
+  static scoped_refptr<AssociatedThreadId> CreateUnbound() {
+    return MakeRefCounted<AssociatedThreadId>();
+  }
+
+  static scoped_refptr<AssociatedThreadId> CreateBound() {
+    auto associated_thread = MakeRefCounted<AssociatedThreadId>();
+    associated_thread->BindToCurrentThread();
+    return associated_thread;
+  }
+
+  // Rebind the associated thread to the current thread. This allows creating
+  // the SequenceManager and TaskQueues on a different thread/sequence than the
+  // one it will manage. Should only be called once.
+  void BindToCurrentThread() {
+    DCHECK_EQ(kInvalidThreadId, thread_id);
+    thread_id = PlatformThread::CurrentId();
+
+    // Rebind the thread and sequence checkers to the current thread/sequence.
+    DETACH_FROM_THREAD(thread_checker);
+    DCHECK_CALLED_ON_VALID_THREAD(thread_checker);
+
+    DETACH_FROM_SEQUENCE(sequence_checker);
+    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker);
+  }
+
+  // TODO(eseckler): Add a method that checks that we are either bound already
+  // or on the thread which created us and use it in any_thread() accessors.
+
+ private:
+  friend class base::RefCountedThreadSafe<AssociatedThreadId>;
+  ~AssociatedThreadId() = default;
+};
+
+}  // namespace internal
+}  // namespace sequence_manager
+}  // namespace base
+
+#endif  // BASE_TASK_SEQUENCE_MANAGER_ASSOCIATED_THREAD_ID_H_
diff --git a/base/task/sequence_manager/sequence_manager.h b/base/task/sequence_manager/sequence_manager.h
index 41e56ec..b198189 100644
--- a/base/task/sequence_manager/sequence_manager.h
+++ b/base/task/sequence_manager/sequence_manager.h
@@ -52,6 +52,24 @@
 
   virtual ~SequenceManager() = default;
 
+  // Binds the SequenceManager and its TaskQueues to the current thread. Should
+  // only be called once. Note that CreateSequenceManagerOnCurrentThread()
+  // performs this initialization automatically.
+  virtual void BindToCurrentThread() = 0;
+
+  // Initializes the SequenceManager on the bound thread. Should only be called
+  // once and only after the ThreadController's dependencies were initialized.
+  // Note that CreateSequenceManagerOnCurrentThread() performs this
+  // initialization automatically.
+  //
+  // TODO(eseckler): This currently needs to be separate from
+  // BindToCurrentThread() as it requires that the MessageLoop is bound
+  // (otherwise we can't add a NestingObserver), while BindToCurrentThread()
+  // requires that the MessageLoop has not yet been bound (binding the
+  // MessageLoop would fail if its TaskRunner, i.e. the default task queue, had
+  // not yet been bound). Reconsider this API once we get rid of MessageLoop.
+  virtual void CompleteInitializationOnBoundThread() = 0;
+
   // TODO(kraynov): Bring back CreateOnCurrentThread static method here
   // when the move is done. It's not here yet to reduce PLATFORM_EXPORT
   // macros hacking during the move.
@@ -126,6 +144,17 @@
 BASE_EXPORT std::unique_ptr<SequenceManager>
 CreateSequenceManagerOnCurrentThread();
 
+// Create a SequenceManager for a future thread using the provided MessageLoop.
+// The SequenceManager can be initialized on the current thread and then needs
+// to be bound and initialized on the target thread by calling
+// BindToCurrentThread() and CompleteInitializationOnBoundThread() during the
+// thread's startup.
+//
+// Implementation is located in sequence_manager_impl.cc. TODO(scheduler-dev):
+// Remove when we get rid of MessageLoop.
+BASE_EXPORT std::unique_ptr<SequenceManager> CreateUnboundSequenceManager(
+    MessageLoop* message_loop);
+
 }  // namespace sequence_manager
 }  // namespace base
 
diff --git a/base/task/sequence_manager/sequence_manager_impl.cc b/base/task/sequence_manager/sequence_manager_impl.cc
index a19a26d5..4b9ed06c 100644
--- a/base/task/sequence_manager/sequence_manager_impl.cc
+++ b/base/task/sequence_manager/sequence_manager_impl.cc
@@ -31,6 +31,11 @@
   return internal::SequenceManagerImpl::CreateOnCurrentThread();
 }
 
+std::unique_ptr<SequenceManager> CreateUnboundSequenceManager(
+    MessageLoop* message_loop) {
+  return internal::SequenceManagerImpl::CreateUnbound(message_loop);
+}
+
 namespace internal {
 
 namespace {
@@ -67,14 +72,13 @@
 
 SequenceManagerImpl::SequenceManagerImpl(
     std::unique_ptr<internal::ThreadController> controller)
-    : graceful_shutdown_helper_(new internal::GracefulQueueShutdownHelper()),
+    : associated_thread_(controller->GetAssociatedThread()),
+      graceful_shutdown_helper_(new internal::GracefulQueueShutdownHelper()),
       controller_(std::move(controller)),
       metric_recording_settings_(InitializeMetricRecordingSettings()),
       memory_corruption_sentinel_(kMemoryCorruptionSentinelValue),
+      main_thread_only_(associated_thread_),
       weak_factory_(this) {
-  // TODO(altimin): Create a sequence checker here.
-  DCHECK(controller_->RunsTasksInCurrentSequence());
-
   TRACE_EVENT_WARMUP_CATEGORY("sequence_manager");
   TRACE_EVENT_WARMUP_CATEGORY(TRACE_DISABLED_BY_DEFAULT("sequence_manager"));
   TRACE_EVENT_WARMUP_CATEGORY(
@@ -89,10 +93,10 @@
   RegisterTimeDomain(main_thread_only().real_time_domain.get());
 
   controller_->SetSequencedTaskSource(this);
-  controller_->AddNestingObserver(this);
 }
 
 SequenceManagerImpl::~SequenceManagerImpl() {
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
       TRACE_DISABLED_BY_DEFAULT("sequence_manager"), "SequenceManager", this);
 
@@ -118,9 +122,11 @@
 
 SequenceManagerImpl::AnyThread::~AnyThread() = default;
 
-SequenceManagerImpl::MainThreadOnly::MainThreadOnly()
+SequenceManagerImpl::MainThreadOnly::MainThreadOnly(
+    const scoped_refptr<AssociatedThreadId>& associated_thread)
     : random_generator(RandUint64()),
       uniform_distribution(0.0, 1.0),
+      selector(associated_thread),
       real_time_domain(new internal::RealTimeDomain()) {}
 
 SequenceManagerImpl::MainThreadOnly::~MainThreadOnly() = default;
@@ -128,9 +134,26 @@
 // static
 std::unique_ptr<SequenceManagerImpl>
 SequenceManagerImpl::CreateOnCurrentThread() {
+  auto manager = CreateUnbound(MessageLoop::current());
+  manager->BindToCurrentThread();
+  manager->CompleteInitializationOnBoundThread();
+  return manager;
+}
+
+// static
+std::unique_ptr<SequenceManagerImpl> SequenceManagerImpl::CreateUnbound(
+    MessageLoop* message_loop) {
   return WrapUnique(
       new SequenceManagerImpl(internal::ThreadControllerImpl::Create(
-          MessageLoop::current(), DefaultTickClock::GetInstance())));
+          message_loop, DefaultTickClock::GetInstance())));
+}
+
+void SequenceManagerImpl::BindToCurrentThread() {
+  associated_thread_->BindToCurrentThread();
+}
+
+void SequenceManagerImpl::CompleteInitializationOnBoundThread() {
+  controller_->AddNestingObserver(this);
 }
 
 void SequenceManagerImpl::RegisterTimeDomain(TimeDomain* time_domain) {
@@ -148,7 +171,7 @@
 
 std::unique_ptr<internal::TaskQueueImpl>
 SequenceManagerImpl::CreateTaskQueueImpl(const TaskQueue::Spec& spec) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   TimeDomain* time_domain = spec.time_domain
                                 ? spec.time_domain
                                 : main_thread_only().real_time_domain.get();
@@ -204,7 +227,7 @@
     std::unique_ptr<internal::TaskQueueImpl> task_queue) {
   TRACE_EVENT1("sequence_manager", "SequenceManagerImpl::UnregisterTaskQueue",
                "queue_name", task_queue->GetName());
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
 
   main_thread_only().selector.RemoveQueue(task_queue.get());
 
@@ -313,7 +336,7 @@
 Optional<PendingTask> SequenceManagerImpl::TakeTaskImpl() {
   CHECK(Validate());
 
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   TRACE_EVENT0("sequence_manager", "SequenceManagerImpl::TakeTask");
 
   {
@@ -396,7 +419,7 @@
 }
 
 TimeDelta SequenceManagerImpl::DelayTillNextTask(LazyNow* lazy_now) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
 
   // If the selector has non-empty queues we trivially know there is immediate
   // work to be done.
@@ -554,32 +577,32 @@
 }
 
 void SequenceManagerImpl::SetWorkBatchSize(int work_batch_size) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK_GE(work_batch_size, 1);
   controller_->SetWorkBatchSize(work_batch_size);
 }
 
 void SequenceManagerImpl::AddTaskObserver(
     MessageLoop::TaskObserver* task_observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   main_thread_only().task_observers.AddObserver(task_observer);
 }
 
 void SequenceManagerImpl::RemoveTaskObserver(
     MessageLoop::TaskObserver* task_observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   main_thread_only().task_observers.RemoveObserver(task_observer);
 }
 
 void SequenceManagerImpl::AddTaskTimeObserver(
     TaskTimeObserver* task_time_observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   main_thread_only().task_time_observers.AddObserver(task_time_observer);
 }
 
 void SequenceManagerImpl::RemoveTaskTimeObserver(
     TaskTimeObserver* task_time_observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   main_thread_only().task_time_observers.RemoveObserver(task_time_observer);
 }
 
@@ -598,7 +621,7 @@
 SequenceManagerImpl::AsValueWithSelectorResult(
     bool should_run,
     internal::WorkQueue* selected_work_queue) const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   std::unique_ptr<trace_event::TracedValue> state(
       new trace_event::TracedValue());
   TimeTicks now = NowTicks();
@@ -641,7 +664,7 @@
 }
 
 void SequenceManagerImpl::OnTaskQueueEnabled(internal::TaskQueueImpl* queue) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK(queue->IsQueueEnabled());
   // Only schedule DoWork if there's something to do.
   if (queue->HasTaskToRunImmediately() && !queue->BlockedByFence())
diff --git a/base/task/sequence_manager/sequence_manager_impl.h b/base/task/sequence_manager/sequence_manager_impl.h
index f641d13a..ea8c53d7 100644
--- a/base/task/sequence_manager/sequence_manager_impl.h
+++ b/base/task/sequence_manager/sequence_manager_impl.h
@@ -12,6 +12,7 @@
 #include <set>
 #include <unordered_map>
 #include <utility>
+#include <vector>
 
 #include "base/atomic_sequence_num.h"
 #include "base/cancelable_callback.h"
@@ -25,6 +26,7 @@
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/lock.h"
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/enqueue_order.h"
 #include "base/task/sequence_manager/graceful_queue_shutdown_helper.h"
 #include "base/task/sequence_manager/moveable_auto_lock.h"
@@ -84,7 +86,19 @@
   // the current thread.
   static std::unique_ptr<SequenceManagerImpl> CreateOnCurrentThread();
 
+  // Create a SequenceManager for a future thread that will run the provided
+  // MessageLoop. The SequenceManager can be initialized on the current thread
+  // and then needs to be bound and initialized on the target thread by calling
+  // BindToCurrentThread() and CompleteInitializationOnBoundThread() during the
+  // thread's startup.
+  //
+  // This function should be called only once per MessageLoop.
+  static std::unique_ptr<SequenceManagerImpl> CreateUnbound(
+      MessageLoop* message_loop);
+
   // SequenceManager implementation:
+  void BindToCurrentThread() override;
+  void CompleteInitializationOnBoundThread() override;
   void SetObserver(Observer* observer) override;
   void AddTaskObserver(MessageLoop::TaskObserver* task_observer) override;
   void RemoveTaskObserver(MessageLoop::TaskObserver* task_observer) override;
@@ -136,6 +150,10 @@
   scoped_refptr<internal::GracefulQueueShutdownHelper>
   GetGracefulQueueShutdownHelper() const;
 
+  const scoped_refptr<AssociatedThreadId>& associated_thread() const {
+    return associated_thread_;
+  }
+
   WeakPtr<SequenceManagerImpl> GetWeakPtr();
 
  protected:
@@ -188,7 +206,8 @@
   };
 
   struct MainThreadOnly {
-    MainThreadOnly();
+    explicit MainThreadOnly(
+        const scoped_refptr<AssociatedThreadId>& associated_thread);
     ~MainThreadOnly();
 
     int nesting_depth = 0;
@@ -299,6 +318,8 @@
   TaskQueue::TaskTiming InitializeTaskTiming(
       internal::TaskQueueImpl* task_queue);
 
+  scoped_refptr<AssociatedThreadId> associated_thread_;
+
   const scoped_refptr<internal::GracefulQueueShutdownHelper>
       graceful_shutdown_helper_;
 
@@ -326,14 +347,13 @@
 
   int32_t memory_corruption_sentinel_;
 
-  THREAD_CHECKER(main_thread_checker_);
   MainThreadOnly main_thread_only_;
   MainThreadOnly& main_thread_only() {
-    DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     return main_thread_only_;
   }
   const MainThreadOnly& main_thread_only() const {
-    DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     return main_thread_only_;
   }
 
diff --git a/base/task/sequence_manager/sequence_manager_impl_unittest.cc b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
index 6550f825..5f007b2 100644
--- a/base/task/sequence_manager/sequence_manager_impl_unittest.cc
+++ b/base/task/sequence_manager/sequence_manager_impl_unittest.cc
@@ -176,7 +176,7 @@
   void SetUpWithMessagePump() {
     mock_clock_.Advance(TimeDelta::FromMilliseconds(1));
     start_time_ = mock_clock_.NowTicks();
-    manager_ = std::make_unique<SequenceManagerForTest>(
+    manager_ = SequenceManagerForTest::Create(
         std::make_unique<ThreadControllerWithMessagePumpImpl>(&mock_clock_));
     // ThreadControllerWithMessagePumpImpl doesn't provide a default tas runner.
     scoped_refptr<TaskQueue> default_task_queue =
@@ -3279,6 +3279,68 @@
   EXPECT_TRUE(run);
 }
 
+class ThreadForOffThreadInitializationTest : public Thread {
+ public:
+  ThreadForOffThreadInitializationTest()
+      : base::Thread("ThreadForOffThreadInitializationTest") {}
+
+  void SequenceManagerCreated(
+      base::sequence_manager::SequenceManager* sequence_manager) {
+    // This executes on the creating thread.
+    DCHECK_CALLED_ON_VALID_SEQUENCE(creating_sequence_checker_);
+
+    queue_ = sequence_manager->CreateTaskQueue<TestTaskQueue>(
+        TaskQueue::Spec("default"));
+
+    // TaskQueue should not run tasks on the creating thread.
+    EXPECT_FALSE(queue_->RunsTasksInCurrentSequence());
+
+    // Override the default task runner before the thread is started.
+    sequence_manager->SetDefaultTaskRunner(queue_);
+    EXPECT_EQ(queue_, message_loop()->task_runner());
+
+    // Post a task to the queue.
+    message_loop()->task_runner()->PostTask(
+        FROM_HERE,
+        Bind([](bool* did_run_task) { *did_run_task = true; }, &did_run_task_));
+  }
+
+ private:
+  void Init() override {
+    // Queue should already be bound to this thread.
+    EXPECT_TRUE(queue_->RunsTasksInCurrentSequence());
+    EXPECT_EQ(queue_, ThreadTaskRunnerHandle::Get());
+  }
+
+  void Run(base::RunLoop* run_loop) override {
+    // Run the posted task.
+    Thread::Run(run_loop);
+    EXPECT_TRUE(did_run_task_);
+  }
+
+  scoped_refptr<SingleThreadTaskRunner> original_task_runner_;
+  scoped_refptr<TaskQueue> queue_;
+  bool did_run_task_ = false;
+
+  SEQUENCE_CHECKER(creating_sequence_checker_);
+};
+
+// Verifies the integration of off-thread SequenceManager and MessageLoop
+// initialization when starting a base::Thread.
+TEST_P(SequenceManagerTestWithCustomInitialization, OffThreadInitialization) {
+  ThreadForOffThreadInitializationTest thread;
+
+  base::Thread::Options options;
+  options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
+  options.on_sequence_manager_created = base::BindRepeating(
+      &ThreadForOffThreadInitializationTest::SequenceManagerCreated,
+      base::Unretained(&thread));
+  ASSERT_TRUE(thread.StartWithOptions(options));
+
+  // Waits for the thread to complete execution.
+  thread.Stop();
+}
+
 }  // namespace sequence_manager_impl_unittest
 }  // namespace internal
 }  // namespace sequence_manager
diff --git a/base/task/sequence_manager/task_queue.cc b/base/task/sequence_manager/task_queue.cc
index 2d3d152..01e0a8b 100644
--- a/base/task/sequence_manager/task_queue.cc
+++ b/base/task/sequence_manager/task_queue.cc
@@ -4,9 +4,14 @@
 
 #include "base/task/sequence_manager/task_queue.h"
 
+#include <utility>
+
 #include "base/bind.h"
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/task/sequence_manager/task_queue_impl.h"
+#include "base/task/sequence_manager/task_queue_task_runner.h"
+#include "base/threading/thread_checker.h"
 #include "base/time/time.h"
 
 namespace base {
@@ -15,10 +20,13 @@
 TaskQueue::TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,
                      const TaskQueue::Spec& spec)
     : impl_(std::move(impl)),
-      thread_id_(PlatformThread::CurrentId()),
       sequence_manager_(impl_ ? impl_->GetSequenceManagerWeakPtr() : nullptr),
       graceful_queue_shutdown_helper_(
-          impl_ ? impl_->GetGracefulQueueShutdownHelper() : nullptr) {}
+          impl_ ? impl_->GetGracefulQueueShutdownHelper() : nullptr),
+      associated_thread_((impl_ && impl_->sequence_manager())
+                             ? impl_->sequence_manager()->associated_thread()
+                             : MakeRefCounted<internal::AssociatedThreadId>()) {
+}
 
 TaskQueue::~TaskQueue() {
   // scoped_refptr guarantees us that this object isn't used.
@@ -75,7 +83,7 @@
 TaskQueue::PostedTask::~PostedTask() = default;
 
 void TaskQueue::ShutdownTaskQueue() {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   AutoLock lock(impl_lock_);
   if (!impl_)
     return;
@@ -91,6 +99,11 @@
   sequence_manager_->UnregisterTaskQueueImpl(TakeTaskQueueImpl());
 }
 
+scoped_refptr<SingleThreadTaskRunner> TaskQueue::CreateTaskRunner(
+    int task_type) {
+  return MakeRefCounted<internal::TaskQueueTaskRunner>(this, task_type);
+}
+
 bool TaskQueue::RunsTasksInCurrentSequence() const {
   return IsOnMainThread();
 }
@@ -126,98 +139,98 @@
 
 std::unique_ptr<TaskQueue::QueueEnabledVoter>
 TaskQueue::CreateQueueEnabledVoter() {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return nullptr;
   return impl_->CreateQueueEnabledVoter(this);
 }
 
 bool TaskQueue::IsQueueEnabled() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return false;
   return impl_->IsQueueEnabled();
 }
 
 bool TaskQueue::IsEmpty() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return true;
   return impl_->IsEmpty();
 }
 
 size_t TaskQueue::GetNumberOfPendingTasks() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return 0;
   return impl_->GetNumberOfPendingTasks();
 }
 
 bool TaskQueue::HasTaskToRunImmediately() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return false;
   return impl_->HasTaskToRunImmediately();
 }
 
 Optional<TimeTicks> TaskQueue::GetNextScheduledWakeUp() {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return nullopt;
   return impl_->GetNextScheduledWakeUp();
 }
 
 void TaskQueue::SetQueuePriority(TaskQueue::QueuePriority priority) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->SetQueuePriority(priority);
 }
 
 TaskQueue::QueuePriority TaskQueue::GetQueuePriority() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return TaskQueue::QueuePriority::kLowPriority;
   return impl_->GetQueuePriority();
 }
 
 void TaskQueue::AddTaskObserver(MessageLoop::TaskObserver* task_observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->AddTaskObserver(task_observer);
 }
 
 void TaskQueue::RemoveTaskObserver(MessageLoop::TaskObserver* task_observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->RemoveTaskObserver(task_observer);
 }
 
 void TaskQueue::SetTimeDomain(TimeDomain* time_domain) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->SetTimeDomain(time_domain);
 }
 
 TimeDomain* TaskQueue::GetTimeDomain() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return nullptr;
   return impl_->GetTimeDomain();
 }
 
 void TaskQueue::SetBlameContext(trace_event::BlameContext* blame_context) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->SetBlameContext(blame_context);
 }
 
 void TaskQueue::InsertFence(InsertFencePosition position) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->InsertFence(position);
@@ -228,21 +241,21 @@
 }
 
 void TaskQueue::RemoveFence() {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   impl_->RemoveFence();
 }
 
 bool TaskQueue::HasActiveFence() {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return false;
   return impl_->HasActiveFence();
 }
 
 bool TaskQueue::BlockedByFence() const {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return false;
   return impl_->BlockedByFence();
@@ -256,7 +269,7 @@
 }
 
 void TaskQueue::SetObserver(Observer* observer) {
-  DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (!impl_)
     return;
   if (observer) {
@@ -271,7 +284,7 @@
 }
 
 bool TaskQueue::IsOnMainThread() const {
-  return thread_id_ == PlatformThread::CurrentId();
+  return associated_thread_->thread_id == PlatformThread::CurrentId();
 }
 
 Optional<MoveableAutoLock> TaskQueue::AcquireImplReadLockIfNeeded() const {
diff --git a/base/task/sequence_manager/task_queue.h b/base/task/sequence_manager/task_queue.h
index af6b4dd..53d78c7 100644
--- a/base/task/sequence_manager/task_queue.h
+++ b/base/task/sequence_manager/task_queue.h
@@ -5,6 +5,8 @@
 #ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_
 #define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_
 
+#include <memory>
+
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
@@ -25,6 +27,7 @@
 namespace sequence_manager {
 
 namespace internal {
+struct AssociatedThreadId;
 class GracefulQueueShutdownHelper;
 class SequenceManagerImpl;
 class TaskQueueImpl;
@@ -310,7 +313,13 @@
 
   void SetObserver(Observer* observer);
 
-  // SingleThreadTaskRunner implementation
+  // Create a task runner for this TaskQueue which will annotate all
+  // posted tasks with the given task type.
+  scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(int task_type);
+
+  // TODO(kraynov): Drop this implementation and introduce
+  // GetDefaultTaskRunner() method instead.
+  // SingleThreadTaskRunner implementation:
   bool RunsTasksInCurrentSequence() const override;
   bool PostDelayedTask(const Location& from_here,
                        OnceClosure task,
@@ -350,14 +359,12 @@
   mutable Lock impl_lock_;
   std::unique_ptr<internal::TaskQueueImpl> impl_;
 
-  const PlatformThreadId thread_id_;
-
   const WeakPtr<internal::SequenceManagerImpl> sequence_manager_;
 
   const scoped_refptr<internal::GracefulQueueShutdownHelper>
       graceful_queue_shutdown_helper_;
 
-  THREAD_CHECKER(main_thread_checker_);
+  scoped_refptr<internal::AssociatedThreadId> associated_thread_;
 
   DISALLOW_COPY_AND_ASSIGN(TaskQueue);
 };
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc
index 250e8c43..c67b8199 100644
--- a/base/task/sequence_manager/task_queue_impl.cc
+++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -44,7 +44,9 @@
                              TimeDomain* time_domain,
                              const TaskQueue::Spec& spec)
     : name_(spec.name),
-      thread_id_(PlatformThread::CurrentId()),
+      associated_thread_(sequence_manager
+                             ? sequence_manager->associated_thread()
+                             : AssociatedThreadId::CreateBound()),
       any_thread_(sequence_manager, time_domain),
       main_thread_only_(sequence_manager, this, time_domain),
       should_monitor_quiescence_(spec.should_monitor_quiescence),
@@ -180,7 +182,7 @@
 }
 
 bool TaskQueueImpl::RunsTasksInCurrentSequence() const {
-  return PlatformThread::CurrentId() == thread_id_;
+  return PlatformThread::CurrentId() == associated_thread_->thread_id;
 }
 
 TaskQueueImpl::PostTaskResult TaskQueueImpl::PostDelayedTask(
@@ -215,7 +217,7 @@
   // for details.
   CHECK(task.callback);
   DCHECK_GT(task.delay, TimeDelta());
-  if (PlatformThread::CurrentId() == thread_id_) {
+  if (PlatformThread::CurrentId() == associated_thread_->thread_id) {
     // Lock-free fast path for delayed tasks posted from the main thread.
     if (!main_thread_only().sequence_manager)
       return PostTaskResult::Fail(std::move(task));
@@ -276,7 +278,7 @@
 }
 
 void TaskQueueImpl::ScheduleDelayedWorkTask(Task pending_task) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   TimeTicks delayed_run_time = pending_task.delayed_run_time;
   TimeTicks time_domain_now = main_thread_only().time_domain->Now();
   if (delayed_run_time <= time_domain_now) {
@@ -460,7 +462,7 @@
 
   // It's only safe to access the work queues from the main thread.
   // TODO(alexclarke): We should find another way of tracing this
-  if (PlatformThread::CurrentId() != thread_id_)
+  if (PlatformThread::CurrentId() != associated_thread_->thread_id)
     return;
 
   AutoLock lock(immediate_incoming_queue_lock_);
@@ -590,7 +592,7 @@
     DCHECK(any_thread().time_domain);
     if (!any_thread().time_domain)
       return;
-    DCHECK(main_thread_checker_.CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     if (time_domain == main_thread_only().time_domain)
       return;
 
@@ -610,7 +612,7 @@
 }
 
 TimeDomain* TaskQueueImpl::GetTimeDomain() const {
-  if (PlatformThread::CurrentId() == thread_id_)
+  if (PlatformThread::CurrentId() == associated_thread_->thread_id)
     return main_thread_only().time_domain;
 
   AutoLock lock(any_thread_lock_);
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h
index b64dd9fd..07a99d14 100644
--- a/base/task/sequence_manager/task_queue_impl.h
+++ b/base/task/sequence_manager/task_queue_impl.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <queue>
 #include <set>
 
 #include "base/callback.h"
@@ -16,6 +17,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/pending_task.h"
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/enqueue_order.h"
 #include "base/task/sequence_manager/intrusive_heap.h"
 #include "base/task/sequence_manager/lazily_deallocated_deque.h"
@@ -301,6 +303,9 @@
   bool RequiresTaskTiming() const;
 
   WeakPtr<SequenceManagerImpl> GetSequenceManagerWeakPtr();
+  SequenceManagerImpl* sequence_manager() {
+    return main_thread_only().sequence_manager;
+  }
 
   scoped_refptr<GracefulQueueShutdownHelper> GetGracefulQueueShutdownHelper();
 
@@ -420,7 +425,7 @@
 
   const char* name_;
 
-  const PlatformThreadId thread_id_;
+  scoped_refptr<AssociatedThreadId> associated_thread_;
 
   mutable Lock any_thread_lock_;
   AnyThread any_thread_;
@@ -433,14 +438,13 @@
     return any_thread_;
   }
 
-  ThreadChecker main_thread_checker_;
   MainThreadOnly main_thread_only_;
   MainThreadOnly& main_thread_only() {
-    DCHECK(main_thread_checker_.CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     return main_thread_only_;
   }
   const MainThreadOnly& main_thread_only() const {
-    DCHECK(main_thread_checker_.CalledOnValidThread());
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     return main_thread_only_;
   }
 
diff --git a/base/task/sequence_manager/task_queue_selector.cc b/base/task/sequence_manager/task_queue_selector.cc
index 30a88bd..9e0e470 100644
--- a/base/task/sequence_manager/task_queue_selector.cc
+++ b/base/task/sequence_manager/task_queue_selector.cc
@@ -4,10 +4,14 @@
 
 #include "base/task/sequence_manager/task_queue_selector.h"
 
+#include <utility>
+
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/task/sequence_manager/work_queue.h"
+#include "base/threading/thread_checker.h"
 #include "base/trace_event/trace_event_argument.h"
 
 namespace base {
@@ -46,8 +50,10 @@
 
 }  // namespace
 
-TaskQueueSelector::TaskQueueSelector()
-    : prioritizing_selector_(this, "enabled"),
+TaskQueueSelector::TaskQueueSelector(
+    scoped_refptr<AssociatedThreadId> associated_thread)
+    : associated_thread_(std::move(associated_thread)),
+      prioritizing_selector_(this, "enabled"),
       immediate_starvation_count_(0),
       high_priority_starvation_score_(0),
       normal_priority_starvation_score_(0),
@@ -57,20 +63,20 @@
 TaskQueueSelector::~TaskQueueSelector() = default;
 
 void TaskQueueSelector::AddQueue(internal::TaskQueueImpl* queue) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK(queue->IsQueueEnabled());
   prioritizing_selector_.AddQueue(queue, TaskQueue::kNormalPriority);
 }
 
 void TaskQueueSelector::RemoveQueue(internal::TaskQueueImpl* queue) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (queue->IsQueueEnabled()) {
     prioritizing_selector_.RemoveQueue(queue);
   }
 }
 
 void TaskQueueSelector::EnableQueue(internal::TaskQueueImpl* queue) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK(queue->IsQueueEnabled());
   prioritizing_selector_.AddQueue(queue, queue->GetQueuePriority());
   if (task_queue_selector_observer_)
@@ -78,7 +84,7 @@
 }
 
 void TaskQueueSelector::DisableQueue(internal::TaskQueueImpl* queue) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK(!queue->IsQueueEnabled());
   prioritizing_selector_.RemoveQueue(queue);
 }
@@ -86,7 +92,7 @@
 void TaskQueueSelector::SetQueuePriority(internal::TaskQueueImpl* queue,
                                          TaskQueue::QueuePriority priority) {
   DCHECK_LT(priority, TaskQueue::kQueuePriorityCount);
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (queue->IsQueueEnabled()) {
     prioritizing_selector_.ChangeSetIndex(queue, priority);
   } else {
@@ -212,7 +218,8 @@
     TaskQueue::QueuePriority max_priority,
     WorkQueue** out_work_queue,
     bool* out_chose_delayed_over_immediate) {
-  DCHECK(task_queue_selector_->main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(
+      task_queue_selector_->associated_thread_->thread_checker);
   DCHECK_EQ(*out_chose_delayed_over_immediate, false);
 
   // Always service the control queue if it has any work.
@@ -289,7 +296,7 @@
 #endif
 
 bool TaskQueueSelector::SelectWorkQueueToService(WorkQueue** out_work_queue) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   bool chose_delayed_over_immediate = false;
   bool found_queue = prioritizing_selector_.SelectWorkQueueToService(
       TaskQueue::kQueuePriorityCount, out_work_queue,
@@ -360,7 +367,7 @@
 }
 
 void TaskQueueSelector::AsValueInto(trace_event::TracedValue* state) const {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   state->SetInteger("high_priority_starvation_score",
                     high_priority_starvation_score_);
   state->SetInteger("normal_priority_starvation_score",
@@ -375,7 +382,7 @@
 }
 
 bool TaskQueueSelector::AllEnabledWorkQueuesAreEmpty() const {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   for (TaskQueue::QueuePriority priority = TaskQueue::kControlPriority;
        priority < TaskQueue::kQueuePriorityCount;
        priority = NextPriority(priority)) {
diff --git a/base/task/sequence_manager/task_queue_selector.h b/base/task/sequence_manager/task_queue_selector.h
index 182158b..d3bd22d 100644
--- a/base/task/sequence_manager/task_queue_selector.h
+++ b/base/task/sequence_manager/task_queue_selector.h
@@ -12,17 +12,19 @@
 #include "base/pending_task.h"
 #include "base/task/sequence_manager/task_queue_selector_logic.h"
 #include "base/task/sequence_manager/work_queue_sets.h"
-#include "base/threading/thread_checker.h"
 
 namespace base {
 namespace sequence_manager {
 namespace internal {
 
+struct AssociatedThreadId;
+
 // TaskQueueSelector is used by the SchedulerHelper to enable prioritization
 // of particular task queues.
 class BASE_EXPORT TaskQueueSelector {
  public:
-  TaskQueueSelector();
+  explicit TaskQueueSelector(
+      scoped_refptr<AssociatedThreadId> associated_thread);
   ~TaskQueueSelector();
 
   // Called to register a queue that can be selected. This function is called
@@ -206,7 +208,7 @@
   // Returns true if there are pending tasks with priority |priority|.
   bool HasTasksWithPriority(TaskQueue::QueuePriority priority);
 
-  ThreadChecker main_thread_checker_;
+  scoped_refptr<AssociatedThreadId> associated_thread_;
 
   PrioritizingSelector prioritizing_selector_;
   size_t immediate_starvation_count_;
diff --git a/base/task/sequence_manager/task_queue_selector_unittest.cc b/base/task/sequence_manager/task_queue_selector_unittest.cc
index c3742a2..bf88408 100644
--- a/base/task/sequence_manager/task_queue_selector_unittest.cc
+++ b/base/task/sequence_manager/task_queue_selector_unittest.cc
@@ -6,7 +6,11 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <memory>
+#include <set>
+#include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/macros.h"
@@ -41,6 +45,7 @@
 
 class TaskQueueSelectorForTest : public TaskQueueSelector {
  public:
+  using TaskQueueSelector::TaskQueueSelector;
   using TaskQueueSelector::prioritizing_selector_for_test;
   using TaskQueueSelector::PrioritizingSelector;
   using TaskQueueSelector::SetImmediateStarvationCountForTest;
@@ -89,7 +94,9 @@
 class TaskQueueSelectorTest : public testing::Test {
  public:
   TaskQueueSelectorTest()
-      : test_closure_(BindRepeating(&TaskQueueSelectorTest::TestFunction)) {}
+      : test_closure_(BindRepeating(&TaskQueueSelectorTest::TestFunction)),
+        associated_thread_(AssociatedThreadId::CreateBound()),
+        selector_(associated_thread_) {}
   ~TaskQueueSelectorTest() override = default;
 
   TaskQueueSelectorForTest::PrioritizingSelector* prioritizing_selector() {
@@ -180,6 +187,7 @@
 
   const size_t kTaskQueueCount = 5;
   RepeatingClosure test_closure_;
+  scoped_refptr<AssociatedThreadId> associated_thread_;
   TaskQueueSelectorForTest selector_;
   std::unique_ptr<TimeDomain> time_domain_;
   std::vector<std::unique_ptr<TaskQueueImpl>> task_queues_;
@@ -758,7 +766,7 @@
 }
 
 TEST_F(TaskQueueSelectorTest, TestObserverWithOneBlockedQueue) {
-  TaskQueueSelectorForTest selector;
+  TaskQueueSelectorForTest selector(associated_thread_);
   MockObserver mock_observer;
   selector.SetTaskQueueSelectorObserver(&mock_observer);
 
@@ -785,7 +793,7 @@
 }
 
 TEST_F(TaskQueueSelectorTest, TestObserverWithTwoBlockedQueues) {
-  TaskQueueSelectorForTest selector;
+  TaskQueueSelectorForTest selector(associated_thread_);
   MockObserver mock_observer;
   selector.SetTaskQueueSelectorObserver(&mock_observer);
 
diff --git a/base/task/sequence_manager/task_queue_task_runner.cc b/base/task/sequence_manager/task_queue_task_runner.cc
new file mode 100644
index 0000000..150d347
--- /dev/null
+++ b/base/task/sequence_manager/task_queue_task_runner.cc
@@ -0,0 +1,40 @@
+// 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 "base/task/sequence_manager/task_queue_task_runner.h"
+
+#include "base/task/sequence_manager/task_queue.h"
+
+namespace base {
+namespace sequence_manager {
+namespace internal {
+
+TaskQueueTaskRunner::TaskQueueTaskRunner(scoped_refptr<TaskQueue> task_queue,
+                                         int task_type)
+    : task_queue_(task_queue), task_type_(task_type) {}
+
+TaskQueueTaskRunner::~TaskQueueTaskRunner() {}
+
+bool TaskQueueTaskRunner::PostDelayedTask(const Location& location,
+                                          OnceClosure callback,
+                                          TimeDelta delay) {
+  return task_queue_->PostTaskWithMetadata(TaskQueue::PostedTask(
+      std::move(callback), location, delay, Nestable::kNestable, task_type_));
+}
+
+bool TaskQueueTaskRunner::PostNonNestableDelayedTask(const Location& location,
+                                                     OnceClosure callback,
+                                                     TimeDelta delay) {
+  return task_queue_->PostTaskWithMetadata(
+      TaskQueue::PostedTask(std::move(callback), location, delay,
+                            Nestable::kNonNestable, task_type_));
+}
+
+bool TaskQueueTaskRunner::RunsTasksInCurrentSequence() const {
+  return task_queue_->RunsTasksInCurrentSequence();
+}
+
+}  // namespace internal
+}  // namespace sequence_manager
+}  // namespace base
diff --git a/base/task/sequence_manager/task_queue_task_runner.h b/base/task/sequence_manager/task_queue_task_runner.h
new file mode 100644
index 0000000..83cdb90
--- /dev/null
+++ b/base/task/sequence_manager/task_queue_task_runner.h
@@ -0,0 +1,47 @@
+// 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.
+
+#ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_TASK_RUNNER_H_
+#define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_TASK_RUNNER_H_
+
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+namespace sequence_manager {
+
+class TaskQueue;
+
+namespace internal {
+
+// TODO(kraynov): Post tasks to a TaskQueue solely using this task runner and
+// drop SingleThreadTaskRunner implementation in the TaskQueue class.
+// See https://crbug.com/865411.
+class BASE_EXPORT TaskQueueTaskRunner : public SingleThreadTaskRunner {
+ public:
+  // TODO(kraynov): Use TaskQueueTaskProxy that will be detachable
+  // from TaskQueue(Impl) when it's getting shutdown.
+  TaskQueueTaskRunner(scoped_refptr<TaskQueue> task_queue, int task_type);
+
+  bool PostDelayedTask(const Location& location,
+                       OnceClosure callback,
+                       TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const Location& location,
+                                  OnceClosure callback,
+                                  TimeDelta delay) override;
+  bool RunsTasksInCurrentSequence() const override;
+
+ private:
+  ~TaskQueueTaskRunner() override;  // Ref-counted.
+
+  scoped_refptr<TaskQueue> task_queue_;
+  const int task_type_;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskQueueTaskRunner);
+};
+
+}  // namespace internal
+}  // namespace sequence_manager
+}  // namespace base
+
+#endif  // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_TASK_RUNNER_H_
diff --git a/base/task/sequence_manager/test/sequence_manager_for_test.cc b/base/task/sequence_manager/test/sequence_manager_for_test.cc
index 3442957..81b974b 100644
--- a/base/task/sequence_manager/test/sequence_manager_for_test.cc
+++ b/base/task/sequence_manager/test/sequence_manager_for_test.cc
@@ -46,9 +46,22 @@
     MessageLoop* message_loop,
     scoped_refptr<SingleThreadTaskRunner> task_runner,
     const TickClock* clock) {
-  return std::make_unique<SequenceManagerForTest>(
-      std::make_unique<ThreadControllerForTest>(message_loop,
-                                                std::move(task_runner), clock));
+  std::unique_ptr<SequenceManagerForTest> manager(
+      new SequenceManagerForTest(std::make_unique<ThreadControllerForTest>(
+          message_loop, std::move(task_runner), clock)));
+  manager->BindToCurrentThread();
+  manager->CompleteInitializationOnBoundThread();
+  return manager;
+}
+
+// static
+std::unique_ptr<SequenceManagerForTest> SequenceManagerForTest::Create(
+    std::unique_ptr<internal::ThreadController> thread_controller) {
+  std::unique_ptr<SequenceManagerForTest> manager(
+      new SequenceManagerForTest(std::move(thread_controller)));
+  manager->BindToCurrentThread();
+  manager->CompleteInitializationOnBoundThread();
+  return manager;
 }
 
 size_t SequenceManagerForTest::ActiveQueuesCount() const {
diff --git a/base/task/sequence_manager/test/sequence_manager_for_test.h b/base/task/sequence_manager/test/sequence_manager_for_test.h
index 442c9a8..61f3be52 100644
--- a/base/task/sequence_manager/test/sequence_manager_for_test.h
+++ b/base/task/sequence_manager/test/sequence_manager_for_test.h
@@ -5,6 +5,8 @@
 #ifndef BASE_TASK_SEQUENCE_MANAGER_TEST_SEQUENCE_MANAGER_FOR_TEST_H_
 #define BASE_TASK_SEQUENCE_MANAGER_TEST_SEQUENCE_MANAGER_FOR_TEST_H_
 
+#include <memory>
+
 #include "base/single_thread_task_runner.h"
 #include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/time/tick_clock.h"
@@ -17,12 +19,9 @@
 
 class SequenceManagerForTest : public internal::SequenceManagerImpl {
  public:
-  explicit SequenceManagerForTest(
-      std::unique_ptr<internal::ThreadController> thread_controller);
-
   ~SequenceManagerForTest() override = default;
 
-  // Creates SequenceManagerImpl using ThreadControllerImpl constructed with
+  // Creates SequenceManagerForTest using ThreadControllerImpl constructed with
   // the given arguments. ThreadControllerImpl is slightly overridden to skip
   // nesting observers registration if message loop is absent.
   static std::unique_ptr<SequenceManagerForTest> Create(
@@ -30,6 +29,10 @@
       scoped_refptr<SingleThreadTaskRunner> task_runner,
       const TickClock* clock);
 
+  // Creates SequenceManagerForTest using the provided ThreadController.
+  static std::unique_ptr<SequenceManagerForTest> Create(
+      std::unique_ptr<internal::ThreadController> thread_controller);
+
   size_t ActiveQueuesCount() const;
   bool HasImmediateWork() const;
   size_t PendingTasksCount() const;
@@ -38,6 +41,10 @@
 
   using internal::SequenceManagerImpl::GetNextSequenceNumber;
   using internal::SequenceManagerImpl::WakeUpReadyDelayedQueues;
+
+ private:
+  explicit SequenceManagerForTest(
+      std::unique_ptr<internal::ThreadController> thread_controller);
 };
 
 }  // namespace sequence_manager
diff --git a/base/task/sequence_manager/thread_controller.h b/base/task/sequence_manager/thread_controller.h
index 53953060..0ba52d85 100644
--- a/base/task/sequence_manager/thread_controller.h
+++ b/base/task/sequence_manager/thread_controller.h
@@ -18,6 +18,7 @@
 namespace sequence_manager {
 namespace internal {
 
+struct AssociatedThreadId;
 class SequencedTaskSource;
 
 // Implementation of this interface is used by SequenceManager to schedule
@@ -66,16 +67,13 @@
   // with MessageLoop.
 
   virtual bool RunsTasksInCurrentSequence() = 0;
-
   virtual const TickClock* GetClock() = 0;
-
   virtual void SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner>) = 0;
-
   virtual void RestoreDefaultTaskRunner() = 0;
-
   virtual void AddNestingObserver(RunLoop::NestingObserver* observer) = 0;
-
   virtual void RemoveNestingObserver(RunLoop::NestingObserver* observer) = 0;
+  virtual const scoped_refptr<AssociatedThreadId>& GetAssociatedThread()
+      const = 0;
 };
 
 }  // namespace internal
diff --git a/base/task/sequence_manager/thread_controller_impl.cc b/base/task/sequence_manager/thread_controller_impl.cc
index efa80fb..5f6f933 100644
--- a/base/task/sequence_manager/thread_controller_impl.cc
+++ b/base/task/sequence_manager/thread_controller_impl.cc
@@ -4,6 +4,8 @@
 
 #include "base/task/sequence_manager/thread_controller_impl.h"
 
+#include <algorithm>
+
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
@@ -22,6 +24,7 @@
     const TickClock* time_source)
     : message_loop_(message_loop),
       task_runner_(task_runner),
+      associated_thread_(AssociatedThreadId::CreateUnbound()),
       message_loop_task_runner_(message_loop ? message_loop->task_runner()
                                              : nullptr),
       time_source_(time_source),
@@ -53,7 +56,7 @@
 
 void ThreadControllerImpl::SetSequencedTaskSource(
     SequencedTaskSource* sequence) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
   DCHECK(sequence);
   DCHECK(!sequence_);
   sequence_ = sequence;
@@ -78,7 +81,7 @@
 
 void ThreadControllerImpl::SetNextDelayedDoWork(LazyNow* lazy_now,
                                                 TimeTicks run_time) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
   DCHECK(sequence_);
 
   if (main_sequence_only().next_delayed_do_work == run_time)
@@ -143,7 +146,7 @@
 }
 
 void ThreadControllerImpl::DoWork(WorkType work_type) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
   DCHECK(sequence_);
 
   {
@@ -218,19 +221,24 @@
 
 void ThreadControllerImpl::AddNestingObserver(
     RunLoop::NestingObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
   nesting_observer_ = observer;
   RunLoop::AddNestingObserverOnCurrentThread(this);
 }
 
 void ThreadControllerImpl::RemoveNestingObserver(
     RunLoop::NestingObserver* observer) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
   DCHECK_EQ(observer, nesting_observer_);
   nesting_observer_ = nullptr;
   RunLoop::RemoveNestingObserverOnCurrentThread(this);
 }
 
+const scoped_refptr<AssociatedThreadId>&
+ThreadControllerImpl::GetAssociatedThread() const {
+  return associated_thread_;
+}
+
 void ThreadControllerImpl::OnBeginNestedRunLoop() {
   main_sequence_only().nesting_depth++;
   {
diff --git a/base/task/sequence_manager/thread_controller_impl.h b/base/task/sequence_manager/thread_controller_impl.h
index 794feefb..609c85c2 100644
--- a/base/task/sequence_manager/thread_controller_impl.h
+++ b/base/task/sequence_manager/thread_controller_impl.h
@@ -5,6 +5,8 @@
 #ifndef BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_IMPL_H_
 #define BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_IMPL_H_
 
+#include <memory>
+
 #include "base/cancelable_callback.h"
 #include "base/debug/task_annotator.h"
 #include "base/macros.h"
@@ -12,6 +14,7 @@
 #include "base/run_loop.h"
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/thread_controller.h"
 
 namespace base {
@@ -45,6 +48,7 @@
   void RestoreDefaultTaskRunner() override;
   void AddNestingObserver(RunLoop::NestingObserver* observer) override;
   void RemoveNestingObserver(RunLoop::NestingObserver* observer) override;
+  const scoped_refptr<AssociatedThreadId>& GetAssociatedThread() const override;
 
   // RunLoop::NestingObserver:
   void OnBeginNestedRunLoop() override;
@@ -99,14 +103,15 @@
     TimeTicks next_delayed_do_work = TimeTicks::Max();
   };
 
-  SEQUENCE_CHECKER(sequence_checker_);
+  scoped_refptr<AssociatedThreadId> associated_thread_;
+
   MainSequenceOnly main_sequence_only_;
   MainSequenceOnly& main_sequence_only() {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
     return main_sequence_only_;
   }
   const MainSequenceOnly& main_sequence_only() const {
-    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+    DCHECK_CALLED_ON_VALID_SEQUENCE(associated_thread_->sequence_checker);
     return main_sequence_only_;
   }
 
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 fbed88b..d8641649 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
@@ -15,7 +15,7 @@
 
 ThreadControllerWithMessagePumpImpl::ThreadControllerWithMessagePumpImpl(
     TickClock* time_source)
-    : main_thread_id_(PlatformThread::CurrentId()),
+    : associated_thread_(AssociatedThreadId::CreateUnbound()),
       pump_(new MessagePumpDefault()),
       time_source_(time_source) {
   RunLoop::RegisterDelegateForCurrentThread(this);
@@ -81,7 +81,7 @@
 }
 
 bool ThreadControllerWithMessagePumpImpl::RunsTasksInCurrentSequence() {
-  return main_thread_id_ == PlatformThread::CurrentId();
+  return associated_thread_->thread_id == PlatformThread::CurrentId();
 }
 
 void ThreadControllerWithMessagePumpImpl::SetDefaultTaskRunner(
@@ -109,6 +109,11 @@
   main_thread_only().nesting_observer = nullptr;
 }
 
+const scoped_refptr<AssociatedThreadId>&
+ThreadControllerWithMessagePumpImpl::GetAssociatedThread() const {
+  return associated_thread_;
+}
+
 bool ThreadControllerWithMessagePumpImpl::DoWork() {
   DCHECK(main_thread_only().task_source);
   bool task_ran = false;
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 c19a2e8..2a70c45 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
@@ -5,8 +5,11 @@
 #ifndef BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_WITH_MESSAGE_PUMP_IMPL_H_
 #define BASE_TASK_SEQUENCE_MANAGER_THREAD_CONTROLLER_WITH_MESSAGE_PUMP_IMPL_H_
 
+#include <memory>
+
 #include "base/debug/task_annotator.h"
 #include "base/message_loop/message_pump.h"
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/sequenced_task_source.h"
 #include "base/task/sequence_manager/thread_controller.h"
 #include "base/threading/platform_thread.h"
@@ -40,6 +43,7 @@
   void RestoreDefaultTaskRunner() override;
   void AddNestingObserver(RunLoop::NestingObserver* observer) override;
   void RemoveNestingObserver(RunLoop::NestingObserver* observer) override;
+  const scoped_refptr<AssociatedThreadId>& GetAssociatedThread() const override;
 
  private:
   friend class DoWorkScope;
@@ -81,24 +85,23 @@
   };
 
   MainThreadOnly& main_thread_only() {
-    DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     return main_thread_only_;
   }
 
   // Returns true if there's a DoWork running on the inner-most nesting layer.
   bool is_doing_work() const {
-    DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
+    DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
     return main_thread_only_.do_work_depth == main_thread_only_.run_depth &&
            main_thread_only_.do_work_depth != 0;
   }
 
+  scoped_refptr<AssociatedThreadId> associated_thread_;
   MainThreadOnly main_thread_only_;
-  const PlatformThreadId main_thread_id_;
   std::unique_ptr<MessagePump> pump_;
   debug::TaskAnnotator task_annotator_;
   TickClock* time_source_;  // Not owned.
 
-  THREAD_CHECKER(main_thread_checker_);
   DISALLOW_COPY_AND_ASSIGN(ThreadControllerWithMessagePumpImpl);
 };
 
diff --git a/base/task/sequence_manager/time_domain.cc b/base/task/sequence_manager/time_domain.cc
index 8f47eb3..f7d57be 100644
--- a/base/task/sequence_manager/time_domain.cc
+++ b/base/task/sequence_manager/time_domain.cc
@@ -4,17 +4,21 @@
 
 #include "base/task/sequence_manager/time_domain.h"
 
+#include "base/task/sequence_manager/associated_thread_id.h"
 #include "base/task/sequence_manager/sequence_manager_impl.h"
 #include "base/task/sequence_manager/task_queue_impl.h"
 #include "base/task/sequence_manager/work_queue.h"
+#include "base/threading/thread_checker.h"
 
 namespace base {
 namespace sequence_manager {
 
-TimeDomain::TimeDomain() : sequence_manager_(nullptr) {}
+TimeDomain::TimeDomain()
+    : sequence_manager_(nullptr),
+      associated_thread_(MakeRefCounted<internal::AssociatedThreadId>()) {}
 
 TimeDomain::~TimeDomain() {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
 }
 
 void TimeDomain::OnRegisterWithSequenceManager(
@@ -22,6 +26,7 @@
   DCHECK(sequence_manager);
   DCHECK(!sequence_manager_);
   sequence_manager_ = sequence_manager;
+  associated_thread_ = sequence_manager_->associated_thread();
 }
 
 SequenceManager* TimeDomain::sequence_manager() const {
@@ -42,7 +47,7 @@
 }
 
 void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK_EQ(queue->GetTimeDomain(), this);
   LazyNow lazy_now(CreateLazyNow());
   SetNextWakeUpForQueue(queue, nullopt, &lazy_now);
@@ -52,7 +57,7 @@
     internal::TaskQueueImpl* queue,
     Optional<internal::TaskQueueImpl::DelayedWakeUp> wake_up,
     LazyNow* lazy_now) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   DCHECK_EQ(queue->GetTimeDomain(), this);
   DCHECK(queue->IsQueueEnabled() || !wake_up);
 
@@ -98,7 +103,7 @@
 }
 
 void TimeDomain::WakeUpReadyDelayedQueues(LazyNow* lazy_now) {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   // Wake up any queues with pending delayed work.  Note std::multimap stores
   // the elements sorted by key, so the begin() iterator points to the earliest
   // queue to wake-up.
@@ -110,7 +115,7 @@
 }
 
 Optional<TimeTicks> TimeDomain::NextScheduledRunTime() const {
-  DCHECK(main_thread_checker_.CalledOnValidThread());
+  DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
   if (delayed_wake_up_queue_.empty())
     return nullopt;
   return delayed_wake_up_queue_.Min().wake_up.time;
diff --git a/base/task/sequence_manager/time_domain.h b/base/task/sequence_manager/time_domain.h
index e9e487b..685590ae 100644
--- a/base/task/sequence_manager/time_domain.h
+++ b/base/task/sequence_manager/time_domain.h
@@ -21,6 +21,7 @@
 class SequenceManager;
 
 namespace internal {
+struct AssociatedThreadId;
 class SequenceManagerImpl;
 class TaskQueueImpl;
 }  // namespace internal
@@ -129,7 +130,7 @@
   internal::SequenceManagerImpl* sequence_manager_;  // Not owned.
   internal::IntrusiveHeap<ScheduledDelayedWakeUp> delayed_wake_up_queue_;
 
-  ThreadChecker main_thread_checker_;
+  scoped_refptr<internal::AssociatedThreadId> associated_thread_;
   DISALLOW_COPY_AND_ASSIGN(TimeDomain);
 };
 
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
index 97e160f..cbdda7e 100644
--- a/base/threading/thread.cc
+++ b/base/threading/thread.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/task/sequence_manager/sequence_manager.h"
 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
 #include "base/threading/thread_id_name_manager.h"
 #include "base/threading/thread_local.h"
@@ -102,6 +103,12 @@
   message_loop_ = message_loop_owned.get();
   start_event_.Reset();
 
+  if (options.on_sequence_manager_created) {
+    sequence_manager_ =
+        sequence_manager::CreateUnboundSequenceManager(message_loop_);
+    options.on_sequence_manager_created.Run(sequence_manager_.get());
+  }
+
   // Hold |thread_lock_| while starting the new thread to synchronize with
   // Stop() while it's not guaranteed to be sequenced (until crbug/629139 is
   // fixed).
@@ -298,12 +305,25 @@
   PlatformThread::SetName(name_.c_str());
   ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
 
+  if (sequence_manager_) {
+    // Bind the SequenceManager before binding the MessageLoop, so that the
+    // TaskQueues are bound before the MessageLoop. This is required as one of
+    // the TaskQueues may have already replaced the MessageLoop's TaskRunner,
+    // and the MessageLoop's TaskRunner needs to be associated with this thread
+    // when we call MessageLoop::BindToCurrentThread().
+    sequence_manager_->BindToCurrentThread();
+  }
+
   // Lazily initialize the |message_loop| so that it can run on this thread.
   DCHECK(message_loop_);
   std::unique_ptr<MessageLoop> message_loop(message_loop_);
   message_loop_->BindToCurrentThread();
   message_loop_->SetTimerSlack(message_loop_timer_slack_);
 
+  if (sequence_manager_) {
+    sequence_manager_->CompleteInitializationOnBoundThread();
+  }
+
 #if defined(OS_POSIX) && !defined(OS_NACL)
   // Allow threads running a MessageLoopForIO to use FileDescriptorWatcher API.
   std::unique_ptr<FileDescriptorWatcher> file_descriptor_watcher;
@@ -348,6 +368,8 @@
   com_initializer.reset();
 #endif
 
+  sequence_manager_.reset();
+
   if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
     // Assert that RunLoop::QuitWhenIdle was called by ThreadQuitHelper. Don't
     // check for custom message pumps, because their shutdown might not allow
diff --git a/base/threading/thread.h b/base/threading/thread.h
index 9fbdcb8..d851bdf 100644
--- a/base/threading/thread.h
+++ b/base/threading/thread.h
@@ -28,6 +28,10 @@
 class MessagePump;
 class RunLoop;
 
+namespace sequence_manager {
+class SequenceManager;
+}  // namespace sequence_manager
+
 // IMPORTANT: Instead of creating a base::Thread, consider using
 // base::Create(Sequenced|SingleThread)TaskRunnerWithTraits().
 //
@@ -60,6 +64,8 @@
  public:
   struct BASE_EXPORT Options {
     typedef Callback<std::unique_ptr<MessagePump>()> MessagePumpFactory;
+    using SequenceManagerCreatedCallback =
+        RepeatingCallback<void(sequence_manager::SequenceManager*)>;
 
     Options();
     Options(MessageLoop::Type type, size_t size);
@@ -79,6 +85,12 @@
     // MessageLoop::Type to TYPE_CUSTOM.
     MessagePumpFactory message_pump_factory;
 
+    // If set, the Thread will create a SequenceManager on the MessageLoop and
+    // execute the provided callback right after it was created. The callback
+    // will be executed on the creator thread before the new Thread is started.
+    // It is typically used to create TaskQueues for the SequenceManager.
+    SequenceManagerCreatedCallback on_sequence_manager_created;
+
     // Specifies the maximum stack size that the thread is allowed to use.
     // This does not necessarily correspond to the thread's initial stack size.
     // A value of 0 indicates that the default maximum should be used.
@@ -334,6 +346,9 @@
   // cleanup logic as required.
   bool using_external_message_loop_ = false;
 
+  // Optionally stores a SequenceManager that manages Tasks on the MessageLoop.
+  std::unique_ptr<sequence_manager::SequenceManager> sequence_manager_;
+
   // Stores Options::timer_slack_ until the message loop has been bound to
   // a thread.
   TimerSlack message_loop_timer_slack_ = TIMER_SLACK_NONE;
diff --git a/base/unguessable_token_unittest.cc b/base/unguessable_token_unittest.cc
index b70cc724..80f50fa 100644
--- a/base/unguessable_token_unittest.cc
+++ b/base/unguessable_token_unittest.cc
@@ -71,10 +71,10 @@
 
 TEST(UnguessableTokenTest, VerifyValueSerialization) {
   UnguessableToken token = UnguessableToken::Create();
-  std::unique_ptr<Value> value = CreateUnguessableTokenValue(token);
+  Value value = CreateUnguessableTokenValue(token);
 
   UnguessableToken deserialized;
-  EXPECT_TRUE(GetValueAsUnguessableToken(*value, &deserialized));
+  EXPECT_TRUE(GetValueAsUnguessableToken(value, &deserialized));
   EXPECT_EQ(token, deserialized);
 }
 
diff --git a/base/value_conversions.cc b/base/value_conversions.cc
index 7e3fd94..e767097 100644
--- a/base/value_conversions.cc
+++ b/base/value_conversions.cc
@@ -32,8 +32,8 @@
 
 // |Value| internally stores strings in UTF-8, so we have to convert from the
 // system native code to UTF-8 and back.
-std::unique_ptr<Value> CreateFilePathValue(const FilePath& in_value) {
-  return std::make_unique<Value>(in_value.AsUTF8Unsafe());
+Value CreateFilePathValue(const FilePath& in_value) {
+  return Value(in_value.AsUTF8Unsafe());
 }
 
 bool GetValueAsFilePath(const Value& value, FilePath* file_path) {
@@ -47,9 +47,9 @@
 
 // |Value| does not support 64-bit integers, and doubles do not have enough
 // precision, so we store the 64-bit time value as a string instead.
-std::unique_ptr<Value> CreateTimeDeltaValue(const TimeDelta& time) {
+Value CreateTimeDeltaValue(const TimeDelta& time) {
   std::string string_value = base::Int64ToString(time.ToInternalValue());
-  return std::make_unique<Value>(string_value);
+  return Value(string_value);
 }
 
 bool GetValueAsTimeDelta(const Value& value, TimeDelta* time) {
@@ -62,14 +62,12 @@
   return true;
 }
 
-std::unique_ptr<Value> CreateUnguessableTokenValue(
-    const UnguessableToken& token) {
+Value CreateUnguessableTokenValue(const UnguessableToken& token) {
   UnguessableTokenRepresentation representation;
   representation.field.high = token.GetHighForSerialization();
   representation.field.low = token.GetLowForSerialization();
 
-  return std::make_unique<Value>(
-      HexEncode(representation.buffer, sizeof(representation.buffer)));
+  return Value(HexEncode(representation.buffer, sizeof(representation.buffer)));
 }
 
 bool GetValueAsUnguessableToken(const Value& value, UnguessableToken* token) {
diff --git a/base/value_conversions.h b/base/value_conversions.h
index bd095cdc..8595b80 100644
--- a/base/value_conversions.h
+++ b/base/value_conversions.h
@@ -18,15 +18,13 @@
 class Value;
 
 // The caller takes ownership of the returned value.
-BASE_EXPORT std::unique_ptr<Value> CreateFilePathValue(
-    const FilePath& in_value);
+BASE_EXPORT Value CreateFilePathValue(const FilePath& in_value);
 BASE_EXPORT bool GetValueAsFilePath(const Value& value, FilePath* file_path);
 
-BASE_EXPORT std::unique_ptr<Value> CreateTimeDeltaValue(const TimeDelta& time);
+BASE_EXPORT Value CreateTimeDeltaValue(const TimeDelta& time);
 BASE_EXPORT bool GetValueAsTimeDelta(const Value& value, TimeDelta* time);
 
-BASE_EXPORT std::unique_ptr<Value> CreateUnguessableTokenValue(
-    const UnguessableToken& token);
+BASE_EXPORT Value CreateUnguessableTokenValue(const UnguessableToken& token);
 BASE_EXPORT bool GetValueAsUnguessableToken(const Value& value,
                                             UnguessableToken* token);
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 71f8f18..24bf37b2 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -592,7 +592,9 @@
   # example by disabling the optimize configuration.
   # TODO(pcc): Make this conditional on is_official_build rather than on gn
   # flags for specific features.
-  if (!is_debug && use_thin_lto && current_toolchain == default_toolchain) {
+  if (!is_debug && use_thin_lto &&
+      (current_toolchain == default_toolchain ||
+       (is_android && current_toolchain == android_secondary_abi_toolchain))) {
     assert(use_lld || target_os == "chromeos",
            "gold plugin only supported with ChromeOS")
 
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 0b13302..cb8630d6 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -43,7 +43,7 @@
 
   # Enables support for ThinLTO, which links 3x-10x faster than full LTO. See
   # also http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html
-  use_thin_lto = is_cfi
+  use_thin_lto = is_cfi || (is_android && is_official_build)
 
   # Tell VS to create a PDB that references information in .obj files rather
   # than copying it all. This should improve linker performance. mspdbcmf.exe
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index ef9b186..cc33e48e 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -30,6 +30,9 @@
   void RenewTreePriority() override {}
   void PostDelayedAnimationTaskOnImplThread(const base::Closure& task,
                                             base::TimeDelta delay) override {}
+  void OnMemoryPressureOnImplThread(
+      base::MemoryPressureListener::MemoryPressureLevel level) override {}
+
   void DidActivateSyncTree() override {}
   void WillPrepareTiles() override {}
   void DidPrepareTiles() override {}
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 69bae67..c98091e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -354,7 +354,8 @@
   base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
   memory_pressure_listener_.reset(
       new base::MemoryPressureListener(base::BindRepeating(
-          &LayerTreeHostImpl::OnMemoryPressure, base::Unretained(this))));
+          &LayerTreeHostImplClient::OnMemoryPressureOnImplThread,
+          base::Unretained(client_))));
 
   SetDebugState(settings.initial_debug_state);
 }
@@ -2808,22 +2809,6 @@
     resource_pool_->OnPurgeMemory();
 }
 
-void LayerTreeHostImpl::OnMemoryPressure(
-    base::MemoryPressureListener::MemoryPressureLevel level) {
-  // Only work for low-end devices for now.
-  if (!base::SysInfo::IsLowEndDevice())
-    return;
-
-  switch (level) {
-    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
-    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
-      break;
-    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
-      OnPurgeMemory();
-      break;
-  }
-}
-
 void LayerTreeHostImpl::SetVisible(bool visible) {
   DCHECK(task_runner_provider_->IsImplThread());
 
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index ebf00deb..654713f 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -136,6 +136,11 @@
   virtual void WillPrepareTiles() = 0;
   virtual void DidPrepareTiles() = 0;
 
+  // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
+  // when the memory coordinator is enabled by default.
+  virtual void OnMemoryPressureOnImplThread(
+      base::MemoryPressureListener::MemoryPressureLevel level) = 0;
+
   // Called when page scale animation has completed on the impl thread.
   virtual void DidCompletePageScaleAnimationOnImplThread() = 0;
 
@@ -714,6 +719,9 @@
 
   void SetActiveURL(const GURL& url);
 
+  // Overriden from base::MemoryCoordinatorClient.
+  void OnPurgeMemory() override;
+
  protected:
   LayerTreeHostImpl(
       const LayerTreeSettings& settings,
@@ -873,14 +881,6 @@
   // active tree.
   void ActivateStateForImages();
 
-  // Overriden from base::MemoryCoordinatorClient.
-  void OnPurgeMemory() override;
-
-  // TODO(gyuyoung): OnMemoryPressure is deprecated. So this should be removed
-  // when the memory coordinator is enabled by default.
-  void OnMemoryPressure(
-      base::MemoryPressureListener::MemoryPressureLevel level);
-
   const LayerTreeSettings settings_;
   const bool is_synchronous_single_threaded_;
 
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index e68c5b7..f5c348f 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -197,6 +197,8 @@
   }
   void WillPrepareTiles() override {}
   void DidPrepareTiles() override {}
+  void OnMemoryPressureOnImplThread(
+      base::MemoryPressureListener::MemoryPressureLevel level) override {}
   void DidCompletePageScaleAnimationOnImplThread() override {
     did_complete_page_scale_animation_ = true;
   }
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 966124c..915d5e20 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -355,6 +355,20 @@
                                 proxy_main_weak_ptr_, base::Passed(&events)));
 }
 
+void ProxyImpl::OnMemoryPressureOnImplThread(
+    base::MemoryPressureListener::MemoryPressureLevel level) {
+  TRACE_EVENT0("cc", "ProxyImpl::OnMemoryPressureOnImplThread");
+  DCHECK(IsImplThread());
+  switch (level) {
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      break;
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      host_impl_->OnPurgeMemory();
+      break;
+  }
+}
+
 size_t ProxyImpl::CompositedAnimationsCount() const {
   return host_impl_->mutator_host()->CompositedAnimationsCount();
 }
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index a6b9fa2..a5545f4 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
 #include "base/memory/weak_ptr.h"
 #include "cc/base/completion_event.h"
 #include "cc/base/delayed_unique_notifier.h"
@@ -104,6 +105,8 @@
       uint32_t frame_token,
       std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
       const gfx::PresentationFeedback& feedback) override;
+  void OnMemoryPressureOnImplThread(
+      base::MemoryPressureListener::MemoryPressureLevel level) override;
 
   // SchedulerClient implementation
   bool WillBeginImplFrame(const viz::BeginFrameArgs& args) override;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 1d199d2f..d28f7e2 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -587,6 +587,20 @@
   }
 }
 
+void SingleThreadProxy::OnMemoryPressureOnImplThread(
+    base::MemoryPressureListener::MemoryPressureLevel level) {
+  TRACE_EVENT0("cc", "SingleThreadProxy::OnMemoryPressureOnImplThread");
+  switch (level) {
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      break;
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      DebugScopedSetImplThread impl(task_runner_provider_);
+      host_impl_->OnPurgeMemory();
+      break;
+  }
+}
+
 DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
   TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
 
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 0ff0f79..17865966 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -127,6 +127,9 @@
       std::vector<LayerTreeHost::PresentationTimeCallback> callbacks,
       const gfx::PresentationFeedback& feedback) override;
 
+  void OnMemoryPressureOnImplThread(
+      base::MemoryPressureListener::MemoryPressureLevel level) override;
+
   void RequestNewLayerTreeFrameSink();
 
   // Called by the legacy path where RenderWidget does the scheduling.
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 8fa7b13..cecbdf9 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -220,6 +220,7 @@
     "//components/autofill/android:autofill_java",
     "//components/background_task_scheduler:background_task_scheduler_java",
     "//components/bookmarks/common/android:bookmarks_java",
+    "//components/contextual_search:mojo_bindings_java",
     "//components/crash/android:java",
     "//components/dom_distiller/content/browser/android:dom_distiller_content_java",
     "//components/dom_distiller/core/android:dom_distiller_core_java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index 7c1b95a..a64dda2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -308,8 +308,8 @@
         }
 
         OverlayViewDelegate delegate = new OverlayViewDelegate(cv);
-        mWebContents.initialize(mActivity, ChromeVersionInfo.getProductVersion(), delegate, cv,
-                mActivity.getWindowAndroid());
+        mWebContents.initialize(ChromeVersionInfo.getProductVersion(), delegate, cv,
+                mActivity.getWindowAndroid(), WebContents.createDefaultInternalsHolder());
         ContentUtils.setUserAgentOverride(mWebContents);
 
         // Transfers the ownership of the WebContents to the native OverlayPanelContent.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index c4453e4..5af0f9e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -502,6 +502,16 @@
     }
 
     /**
+     * Maximizes the Contextual Search Panel.
+     * @param reason The {@code StateChangeReason} behind the maximization.
+     */
+    @Override
+    public void maximizePanel(@StateChangeReason int reason) {
+        mShouldPromoteToTabAfterMaximizing = false;
+        maximizePanel(reason);
+    }
+
+    /**
      * Maximizes the Contextual Search Panel, then promotes it to a regular Tab.
      * @param reason The {@code StateChangeReason} behind the maximization and promotion to tab.
      */
@@ -541,6 +551,11 @@
     }
 
     @Override
+    public void expandPanel(@StateChangeReason int reason) {
+        super.expandPanel(reason);
+    }
+
+    @Override
     public PanelState getPanelState() {
         // NOTE(pedrosimonetti): exposing superclass method to the interface.
         return super.getPanelState();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 23b546e..ec0fabd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -12,6 +12,7 @@
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
 
+import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
 import org.chromium.base.SysUtils;
 import org.chromium.base.VisibleForTesting;
@@ -56,6 +57,7 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.BrowserControlsState;
 import org.chromium.content_public.common.ContentUrlConstants;
+import org.chromium.contextual_search.mojom.OverlayPosition;
 import org.chromium.net.NetworkChangeNotifier;
 
 import java.net.MalformedURLException;
@@ -72,6 +74,9 @@
     // TODO(donnd): provide an inner class that implements some of these interfaces (like the
     // ContextualSearchTranslateInterface) rather than having the manager itself implement the
     // interface because that exposes all the public methods of that interface at the manager level.
+
+    private static final String TAG = "ContextualSearch";
+
     private static final String INTENT_URL_PREFIX = "intent:";
 
     // The animation duration of a URL being promoted to a tab when triggered by an
@@ -832,6 +837,40 @@
     }
 
     /**
+     * Called by JavaScript in the Overlay to change the position of the overlay.
+     * The panel cannot be changed to any opened position if it's not already opened.
+     * @param desiredPosition The desired position of the Overlay Panel expressed as an
+     *        OverlayPosition int (defined in contextual_search_js_api_service.mojom).
+     */
+    @CalledByNative
+    private void onChangeOverlayPosition(int desiredPosition) {
+        assert desiredPosition >= OverlayPosition.CLOSE
+                && desiredPosition <= OverlayPosition.MAXIMIZE;
+        // Ignore requests when the panel is not already open to prevent spam or abuse of the API.
+        if (!mSearchPanel.isShowing() || desiredPosition < OverlayPosition.CLOSE
+                || desiredPosition > OverlayPosition.MAXIMIZE) {
+            Log.w(TAG, "Unexpected request to set Overlay position to " + desiredPosition);
+            return;
+        }
+
+        // Set the position.
+        switch (desiredPosition) {
+            case OverlayPosition.CLOSE:
+                mSearchPanel.closePanel(StateChangeReason.UNKNOWN, true);
+                break;
+            case OverlayPosition.PEEK:
+                mSearchPanel.peekPanel(StateChangeReason.UNKNOWN);
+                break;
+            case OverlayPosition.EXPAND:
+                mSearchPanel.expandPanel(StateChangeReason.UNKNOWN);
+                break;
+            case OverlayPosition.MAXIMIZE:
+                mSearchPanel.maximizePanel(StateChangeReason.UNKNOWN);
+                break;
+        }
+    }
+
+    /**
      * Notifies that the Accessibility Mode state has changed.
      *
      * @param enabled Whether the Accessibility Mode is enabled.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/NearOomReductionInfoBar.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/NearOomReductionInfoBar.java
new file mode 100644
index 0000000..5d179eb
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/NearOomReductionInfoBar.java
@@ -0,0 +1,40 @@
+// 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.
+
+package org.chromium.chrome.browser.infobar;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.R;
+
+/**
+ * This InfoBar is shown to let the user know when the browser took action to
+ * reduce the content of the page using too much memory, potentially breaking it
+ * and offers them a way to decline the intervention.
+ * The native caller can handle user action through {@code InfoBar::ProcessButton(int action)}
+ */
+public class NearOomReductionInfoBar extends InfoBar {
+    @VisibleForTesting
+    public NearOomReductionInfoBar() {
+        super(R.drawable.infobar_chrome, null, null);
+    }
+
+    @Override
+    protected boolean usesCompactLayout() {
+        return true;
+    }
+
+    @Override
+    protected void createCompactLayoutContent(InfoBarCompactLayout layout) {
+        new InfoBarCompactLayout.MessageBuilder(layout)
+                .withText(R.string.near_oom_reduction_message)
+                .withLink(R.string.near_oom_reduction_decline, view -> onLinkClicked())
+                .buildAndInsert();
+    }
+
+    @CalledByNative
+    private static NearOomReductionInfoBar create() {
+        return new NearOomReductionInfoBar();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 8f0f3303..5e56a84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -1757,8 +1757,8 @@
         ContentView cv = ContentView.createContentView(mThemedApplicationContext, webContents);
         cv.setContentDescription(mThemedApplicationContext.getResources().getString(
                 R.string.accessibility_content_view));
-        webContents.initialize(mThemedApplicationContext, PRODUCT_VERSION,
-                new TabViewAndroidDelegate(this, cv), cv, getWindowAndroid());
+        webContents.initialize(PRODUCT_VERSION, new TabViewAndroidDelegate(this, cv), cv,
+                getWindowAndroid(), WebContents.createDefaultInternalsHolder());
         SelectionPopupController.fromWebContents(webContents)
                 .setActionModeCallback(new ChromeActionModeCallback(this, webContents));
         initBrowserComponents(webContents);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 7cfa8b68..fa729d55 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3626,6 +3626,12 @@
       <message name="IDS_NEAR_OOM_INTERVENTION_DECLINE" desc="The text of the button letting the user decline the browser's intervention, so that the page can resume what it was doing.">
          Resume
       </message>
+      <message name="IDS_NEAR_OOM_REDUCTION_MESSAGE" desc="The message stating that the browser removed some content of the page using too much memory.">
+         This page uses too much memory, so Chrome removed some content.
+      </message>
+      <message name="IDS_NEAR_OOM_REDUCTION_DECLINE" desc="The text of the button letting the user decline the browser's intervention, so that the page can be reloaded.">
+         Show original
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6a017e8..e7dce98 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -648,6 +648,7 @@
   "java/src/org/chromium/chrome/browser/infobar/IPHInfoBarSupport.java",
   "java/src/org/chromium/chrome/browser/infobar/FramebustBlockInfoBar.java",
   "java/src/org/chromium/chrome/browser/infobar/NearOomInfoBar.java",
+  "java/src/org/chromium/chrome/browser/infobar/NearOomReductionInfoBar.java",
   "java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java",
   "java/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfoBarDelegate.java",
   "java/src/org/chromium/chrome/browser/infobar/PreviewsInfoBar.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
index ce5e5f5b..bec8d3dd 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -31,6 +31,7 @@
 import org.chromium.content_public.browser.SelectionClient;
 import org.chromium.content_public.browser.SelectionPopupController;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
 import org.chromium.ui.touch_selection.SelectionEventType;
 
@@ -80,8 +81,10 @@
             super(activity, null);
             setSelectionController(new MockCSSelectionController(activity, this));
             WebContents webContents = WebContentsFactory.createWebContents(false, false);
+            webContents.initialize(null, null, null, new ActivityWindowAndroid(activity),
+                    WebContents.createDefaultInternalsHolder());
             SelectionPopupController selectionPopupController =
-                    SelectionPopupController.createForTesting(activity, null, webContents);
+                    SelectionPopupController.createForTesting(webContents);
             selectionPopupController.setSelectionClient(this.getContextualSearchSelectionClient());
             MockContextualSearchPolicy policy = new MockContextualSearchPolicy();
             setContextualSearchPolicy(policy);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
index 9df4f3df..69341c7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/input/SelectPopupOtherContentViewTest.java
@@ -29,7 +29,8 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.ActivityWindowAndroid;
 import org.chromium.ui.base.ViewAndroidDelegate;
-import org.chromium.ui.base.WindowAndroid;
+
+import java.util.concurrent.ExecutionException;
 
 /**
  * Test the select popup and how it interacts with another WebContents.
@@ -62,10 +63,16 @@
 
         @Override
         public boolean isSatisfied() {
-            return mActivityTestRule.getActivity()
-                    .getActivityTab()
-                    .getWebContents()
-                    .isSelectPopupVisibleForTesting();
+            return isSelectPopupVisibleOnUiThread();
+        }
+    }
+
+    private boolean isSelectPopupVisibleOnUiThread() {
+        try {
+            return ThreadUtils.runOnUiThreadBlocking(
+                    () -> mActivityTestRule.getWebContents().isSelectPopupVisibleForTesting());
+        } catch (ExecutionException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -84,20 +91,20 @@
         mActivityTestRule.startMainActivityWithURL(SELECT_URL);
 
         // Once clicked, the popup should show up.
-        DOMUtils.clickNode(mActivityTestRule.getActivity().getCurrentWebContents(), "select");
+        DOMUtils.clickNode(mActivityTestRule.getWebContents(), "select");
         CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria());
 
-        // Now create and destroy a different ContentView.
+        // Now create and destroy a different WebContents.
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
                 WebContents webContents = WebContentsFactory.createWebContents(false, false);
                 ChromeActivity activity = mActivityTestRule.getActivity();
-                WindowAndroid windowAndroid = new ActivityWindowAndroid(activity);
 
                 ContentView cv = ContentView.createContentView(activity, webContents);
-                webContents.initialize(activity, "", ViewAndroidDelegate.createBasicDelegate(cv),
-                        cv, windowAndroid);
+                webContents.initialize("", ViewAndroidDelegate.createBasicDelegate(cv), cv,
+                        new ActivityWindowAndroid(activity),
+                        WebContents.createDefaultInternalsHolder());
                 webContents.destroy();
             }
         });
@@ -106,10 +113,7 @@
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
 
         // The popup should still be shown.
-        Assert.assertTrue("The select popup got hidden by destroying of unrelated WebContents.",
-                mActivityTestRule.getActivity()
-                        .getActivityTab()
-                        .getWebContents()
-                        .isSelectPopupVisibleForTesting());
+        Assert.assertTrue("The select popup got hidden by destroying of unrelated ContentViewCore.",
+                isSelectPopupVisibleOnUiThread());
     }
 }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 4a137e8..11e529d3 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-70.0.3502.0_rc-r1.afdo.bz2
\ No newline at end of file
+chromeos-chrome-amd64-70.0.3503.0_rc-r1.afdo.bz2
\ No newline at end of file
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 7d4f3f8c..41630a6d 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -1114,6 +1114,13 @@
         </message>
       </if>
 
+      <!-- OOM intervention message -->
+      <if expr="is_android">
+        <message name="IDS_NEAR_OOM_REDUCTION_MESSAGE" desc="The message stating that the browser removed some content of the page using too much memory.">
+           This page uses too much memory, so Chrome removed some content.
+        </message>
+      </if>
+
       <!-- OOBE -->
       <if expr="chromeos">
         <message name="IDS_INSTALLING_UPDATE" desc="Label shown on the updates installation screen during OOBE">
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index ec8b999c9..5d503ea 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -1132,6 +1132,13 @@
         </message>
       </if>
 
+      <!-- OOM intervention message -->
+      <if expr="is_android">
+        <message name="IDS_NEAR_OOM_REDUCTION_MESSAGE" desc="The message stating that the browser removed some content of the page using too much memory.">
+           This page uses too much memory, so Chrome removed some content.
+        </message>
+      </if>
+
       <!-- OOBE -->
       <if expr="chromeos">
         <message name="IDS_INSTALLING_UPDATE" desc="Label shown on the updates installation screen during OOBE">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7048fc8e..e715eaf7 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4462,6 +4462,7 @@
       "../android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBar.java",
       "../android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBarDelegate.java",
       "../android/java/src/org/chromium/chrome/browser/infobar/NearOomInfoBar.java",
+      "../android/java/src/org/chromium/chrome/browser/infobar/NearOomReductionInfoBar.java",
       "../android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java",
       "../android/java/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfoBarDelegate.java",
       "../android/java/src/org/chromium/chrome/browser/infobar/PreviewsInfoBar.java",
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
index 2ee3567..ff69c31 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -230,7 +230,7 @@
   std::move(callback).Run(should_enable);
 }
 
-void ContextualSearchManager::SetCaption(std::string caption,
+void ContextualSearchManager::SetCaption(const std::string& caption,
                                          bool does_answer) {
   JNIEnv* env = base::android::AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jstring> j_caption =
@@ -239,6 +239,13 @@
                                             does_answer);
 }
 
+void ContextualSearchManager::ChangeOverlayPosition(
+    contextual_search::mojom::OverlayPosition desired_position) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_ContextualSearchManager_onChangeOverlayPosition(
+      env, java_manager_, static_cast<int>(desired_position));
+}
+
 jlong JNI_ContextualSearchManager_Init(JNIEnv* env,
                                        const JavaParamRef<jobject>& obj) {
   ContextualSearchManager* manager = new ContextualSearchManager(env, obj);
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.h b/chrome/browser/android/contextualsearch/contextual_search_manager.h
index 488fc4ed..f83a198f4 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.h
@@ -12,6 +12,7 @@
 #include "chrome/browser/android/contextualsearch/contextual_search_context.h"
 #include "chrome/browser/android/contextualsearch/contextual_search_delegate.h"
 #include "components/contextual_search/browser/contextual_search_js_api_handler.h"
+#include "components/contextual_search/common/contextual_search_js_api_service.mojom.h"
 
 // Manages the native extraction and request logic for Contextual Search,
 // and interacts with the Java ContextualSearchManager for UX.
@@ -82,7 +83,9 @@
       const base::android::JavaParamRef<jobject>& j_web_contents);
 
   // ContextualSearchJsApiHandler overrides:
-  void SetCaption(std::string caption, bool does_answer) override;
+  void SetCaption(const std::string& caption, bool does_answer) override;
+  void ChangeOverlayPosition(
+      contextual_search::mojom::OverlayPosition desired_position) override;
 
   // Determines whether the JS API should be enabled for the given URL.
   // Calls the given |callback| with the answer: whether the API should be
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
index 355ec05..03df1bbd 100644
--- a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
+++ b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.cc
@@ -107,6 +107,11 @@
   }
 }
 
+void OomInterventionTabHelper::DeclineInterventionWithReload() {
+  web_contents()->GetController().Reload(content::ReloadType::NORMAL, true);
+  DeclineIntervention();
+}
+
 void OomInterventionTabHelper::DeclineInterventionSticky() {
   NOTREACHED();
 }
diff --git a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
index da1a28a..dd6b7d1 100644
--- a/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
+++ b/chrome/browser/android/oom_intervention/oom_intervention_tab_helper.h
@@ -43,6 +43,7 @@
   // InterventionDelegate:
   void AcceptIntervention() override;
   void DeclineIntervention() override;
+  void DeclineInterventionWithReload() override;
   void DeclineInterventionSticky() override;
 
  private:
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index c51096e..abfa105 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1443,6 +1443,8 @@
     "policy/pre_signin_policy_fetcher.h",
     "policy/remote_commands/affiliated_remote_commands_invalidator.cc",
     "policy/remote_commands/affiliated_remote_commands_invalidator.h",
+    "policy/remote_commands/crd_host_delegate.cc",
+    "policy/remote_commands/crd_host_delegate.h",
     "policy/remote_commands/device_command_fetch_status_job.cc",
     "policy/remote_commands/device_command_fetch_status_job.h",
     "policy/remote_commands/device_command_reboot_job.cc",
@@ -1451,6 +1453,8 @@
     "policy/remote_commands/device_command_screenshot_job.h",
     "policy/remote_commands/device_command_set_volume_job.cc",
     "policy/remote_commands/device_command_set_volume_job.h",
+    "policy/remote_commands/device_command_start_crd_session_job.cc",
+    "policy/remote_commands/device_command_start_crd_session_job.h",
     "policy/remote_commands/device_command_wipe_users_job.cc",
     "policy/remote_commands/device_command_wipe_users_job.h",
     "policy/remote_commands/device_commands_factory_chromeos.cc",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 8672870..ee9837a 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -214,8 +214,14 @@
                       TestCase("imageOpenGalleryOpenDrive"),
                       TestCase("imageOpenGalleryOpenDrive").EnableDriveFs()));
 
+// NaCl crashes in DEBUG in the zipFileOpen cases crbug.com/867738
+#if !defined(NDEBUG)
+#define MAYBE_ZipFiles DISABLED_ZipFiles
+#else
+#define MAYBE_ZipFiles ZipFiles
+#endif
 WRAPPED_INSTANTIATE_TEST_CASE_P(
-    ZipFiles, /* zip_files.js */
+    MAYBE_ZipFiles, /* zip_files.js */
     FilesAppBrowserTest,
     ::testing::Values(ZipCase("zipFileOpenDownloads").InGuestMode(),
                       ZipCase("zipFileOpenDownloads"),
diff --git a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
index f553a5a..34976ed7 100644
--- a/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller_browsertest.cc
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 #include <string>
-#include <unordered_set>
 #include <vector>
 
 #include "base/barrier_closure.h"
@@ -139,6 +138,16 @@
   // If |files_must_exist| is true and a file already exists the class does not
   // wait when it changes.
   explicit KerberosFilesChangeWaiter(bool files_must_exist) {
+    barrier_closure_ = base::BarrierClosure(2, loop_.QuitClosure());
+
+    watch_callback_ = base::BindRepeating(
+        [](const base::RepeatingClosure& barrier_closure,
+           const base::FilePath& path, bool error) -> void {
+          EXPECT_FALSE(error);
+          barrier_closure.Run();
+        },
+        barrier_closure_);
+
     config_watcher_ = std::make_unique<base::FilePathWatcher>();
     MaybeStartWatch(&config_watcher_,
                     base::FilePath(GetKerberosConfigFileName()),
@@ -148,8 +157,6 @@
     MaybeStartWatch(&creds_watcher_,
                     base::FilePath(GetKerberosCredentialsCacheFileName()),
                     files_must_exist);
-    if (watching_paths_.empty())
-      loop_.Quit();
   }
 
   // Should be called once.
@@ -163,31 +170,19 @@
   void MaybeStartWatch(std::unique_ptr<base::FilePathWatcher>* watcher,
                        const base::FilePath& path,
                        bool files_must_exist) {
-    (*watcher)->Watch(
-        path, false /* recursive */,
-        base::BindRepeating(&KerberosFilesChangeWaiter::WatchCallback,
-                            weak_factory_.GetWeakPtr()));
+    (*watcher)->Watch(path, false /* recursive */, watch_callback_);
     if (!files_must_exist && base::PathExists(path)) {
-      // File was written so stop the watch.
+      watch_callback_.Run(path, false /* error */);
       watcher->reset();
-      return;
     }
-    watching_paths_.insert(path.value());
   }
-
-  void WatchCallback(const base::FilePath& path, bool error) {
-    EXPECT_FALSE(error);
-    watching_paths_.erase(path.value());
-    if (watching_paths_.empty())
-      loop_.Quit();
-  }
-
   base::RunLoop loop_;
-  std::unordered_set<std::string> watching_paths_;
+  base::RepeatingClosure barrier_closure_;
+
+  base::RepeatingCallback<void(const base::FilePath& path, bool error)>
+      watch_callback_;
   std::unique_ptr<base::FilePathWatcher> config_watcher_;
   std::unique_ptr<base::FilePathWatcher> creds_watcher_;
-
-  base::WeakPtrFactory<KerberosFilesChangeWaiter> weak_factory_{this};
 };
 
 }  // namespace
@@ -982,7 +977,7 @@
 // Kerberos files.
 // Disabled due to flakiness, see https://crbug.com/865206.
 IN_PROC_BROWSER_TEST_F(ExistingUserControllerActiveDirectoryTest,
-                       PolicyChangeTriggersFileUpdate) {
+                       DISABLED_PolicyChangeTriggersFileUpdate) {
   LoginAdOnline();
 
   ApplyPolicyAndWaitFilesChanged(false /* enable_dns_cname_lookup */);
@@ -995,8 +990,9 @@
 // Tests if user Kerberos files changed D-Bus signal triggers updating user
 // Kerberos files.
 // Disabled due to flakiness, see https://crbug.com/865206.
-IN_PROC_BROWSER_TEST_F(ExistingUserControllerActiveDirectoryTest,
-                       UserKerberosFilesChangedSignalTriggersFileUpdate) {
+IN_PROC_BROWSER_TEST_F(
+    ExistingUserControllerActiveDirectoryTest,
+    DISABLED_UserKerberosFilesChangedSignalTriggersFileUpdate) {
   LoginAdOnline();
   KerberosFilesChangeWaiter files_change_waiter(true /* files_must_exist */);
   fake_authpolicy_client()->SetUserKerberosFiles("new_kerberos_creds",
diff --git a/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
new file mode 100644
index 0000000..7a8313e
--- /dev/null
+++ b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.cc
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.h"
+
+#include "components/user_manager/user_manager.h"
+#include "ui/base/user_activity/user_activity_detector.h"
+
+namespace policy {
+
+CRDHostDelegate::CRDHostDelegate() {}
+
+CRDHostDelegate::~CRDHostDelegate() {
+  // TODO(antrim): shutdown host somewhat correctly.
+}
+
+bool CRDHostDelegate::HasActiveSession() {
+  return false;
+}
+
+void CRDHostDelegate::TerminateSession(base::OnceClosure callback) {
+  std::move(callback).Run();
+}
+
+bool CRDHostDelegate::AreServicesReady() {
+  return user_manager::UserManager::IsInitialized() &&
+         ui::UserActivityDetector::Get() != nullptr;
+}
+
+bool CRDHostDelegate::IsRunningKiosk() {
+  auto* user_manager = user_manager::UserManager::Get();
+  // TODO(antrim): find out if Arc Kiosk is also eligible.
+  // TODO(antrim): find out if only auto-started Kiosks are elidgible.
+  return user_manager->IsLoggedInAsKioskApp();
+}
+
+base::TimeDelta CRDHostDelegate::GetIdlenessPeriod() {
+  return base::TimeTicks::Now() -
+         ui::UserActivityDetector::Get()->last_activity_time();
+}
+
+void CRDHostDelegate::FetchOAuthToken(
+    DeviceCommandStartCRDSessionJob::OAuthTokenCallback success_callback,
+    DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) {
+  // TODO(antrim): implement
+  std::move(success_callback).Run(std::string("OAuth token"));
+}
+
+void CRDHostDelegate::FetchICEConfig(
+    const std::string& oauth_token,
+    DeviceCommandStartCRDSessionJob::ICEConfigCallback success_callback,
+    DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) {
+  base::Value configuration(base::Value::Type::DICTIONARY);
+  // TODO(antrim): implement
+  std::move(success_callback).Run(std::move(configuration));
+}
+
+void CRDHostDelegate::StartCRDHostAndGetCode(
+    const std::string& directory_bot_jid,
+    const std::string& oauth_token,
+    base::Value ice_config,
+    DeviceCommandStartCRDSessionJob::AuthCodeCallback success_callback,
+    DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) {
+  // TODO(antrim): implement
+  std::move(success_callback).Run(std::string("Auth Code"));
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.h b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.h
new file mode 100644
index 0000000..ad53ab3
--- /dev/null
+++ b/chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_CRD_HOST_DELEGATE_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_CRD_HOST_DELEGATE_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h"
+
+namespace policy {
+
+// An implementation of the |DeviceCommandStartCRDSessionJob::Delegate|.
+class CRDHostDelegate : public DeviceCommandStartCRDSessionJob::Delegate {
+ public:
+  CRDHostDelegate();
+  ~CRDHostDelegate() override;
+
+ private:
+  // DeviceCommandScreenshotJob::Delegate:
+  bool HasActiveSession() override;
+  void TerminateSession(base::OnceClosure callback) override;
+  bool AreServicesReady() override;
+  bool IsRunningKiosk() override;
+  base::TimeDelta GetIdlenessPeriod() override;
+  void FetchOAuthToken(
+      DeviceCommandStartCRDSessionJob::OAuthTokenCallback success_callback,
+      DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) override;
+  void FetchICEConfig(
+      const std::string& oauth_token,
+      DeviceCommandStartCRDSessionJob::ICEConfigCallback success_callback,
+      DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) override;
+  void StartCRDHostAndGetCode(
+      const std::string& directory_bot_jid,
+      const std::string& oauth_token,
+      base::Value ice_config,
+      DeviceCommandStartCRDSessionJob::AuthCodeCallback success_callback,
+      DeviceCommandStartCRDSessionJob::ErrorCallback error_callback) override;
+
+  DISALLOW_COPY_AND_ASSIGN(CRDHostDelegate);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_CRD_HOST_DELEGATE_H_
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc
new file mode 100644
index 0000000..ed99818
--- /dev/null
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.cc
@@ -0,0 +1,257 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/values.h"
+#include "components/policy/proto/device_management_backend.pb.h"
+
+namespace policy {
+
+namespace {
+
+// Job parameters fields:
+
+// Job requires that UI was idle for at least this period of time
+// to proceed. If absent / equal to 0, job will proceed regardless of user
+// activity.
+const char kIdlenessCutoffFieldName[] = "idlenessCutoffSec";
+
+// Parameters that are directly passed to CRD Host.
+const char kDirectoryBotJIDFieldName[] = "directoryBotJID";
+
+// Result payload fields:
+
+// Integer value containing DeviceCommandStartCRDSessionJob::ResultCode
+const char kResultCodeFieldName[] = "resultCode";
+
+// CRD Auth Code if job was completed successfully
+const char kResultAuthCodeFieldName[] = "authCode";
+
+// Optional detailed error message for error result codes.
+const char kResultMessageFieldName[] = "message";
+
+// Period in seconds since last user activity, if job finished with
+// FAILURE_NOT_IDLE result code.
+const char kLastActivityFieldName[] = "lastActivitySec";
+
+}  // namespace
+
+class DeviceCommandStartCRDSessionJob::ResultPayload
+    : public RemoteCommandJob::ResultPayload {
+ public:
+  ResultPayload(ResultCode result_code,
+                const base::Optional<std::string>& auth_code,
+                const base::Optional<base::TimeDelta>& time_delta,
+                const base::Optional<std::string>& error_message);
+  ~ResultPayload() override {}
+
+  static std::unique_ptr<ResultPayload> CreateSuccessPayload(
+      const std::string& auth_code);
+  static std::unique_ptr<ResultPayload> CreateNonIdlePayload(
+      const base::TimeDelta& time_delta);
+  static std::unique_ptr<ResultPayload> CreateErrorPayload(
+      ResultCode result_code,
+      const std::string& error_message);
+
+  // RemoteCommandJob::ResultPayload:
+  std::unique_ptr<std::string> Serialize() override;
+
+ private:
+  std::string payload_;
+};
+
+DeviceCommandStartCRDSessionJob::ResultPayload::ResultPayload(
+    ResultCode result_code,
+    const base::Optional<std::string>& auth_code,
+    const base::Optional<base::TimeDelta>& time_delta,
+    const base::Optional<std::string>& error_message) {
+  base::Value value(base::Value::Type::DICTIONARY);
+  value.SetKey(kResultCodeFieldName, base::Value(result_code));
+  if (error_message && !error_message.value().empty())
+    value.SetKey(kResultMessageFieldName, base::Value(error_message.value()));
+  if (auth_code)
+    value.SetKey(kResultAuthCodeFieldName, base::Value(auth_code.value()));
+  if (time_delta) {
+    value.SetKey(kLastActivityFieldName,
+                 base::Value(static_cast<int>(time_delta.value().InSeconds())));
+  }
+  base::JSONWriter::Write(value, &payload_);
+}
+
+std::unique_ptr<DeviceCommandStartCRDSessionJob::ResultPayload>
+DeviceCommandStartCRDSessionJob::ResultPayload::CreateSuccessPayload(
+    const std::string& auth_code) {
+  return std::make_unique<ResultPayload>(ResultCode::SUCCESS, auth_code,
+                                         base::nullopt /*time_delta*/,
+                                         base::nullopt /* error_message */);
+}
+
+std::unique_ptr<DeviceCommandStartCRDSessionJob::ResultPayload>
+DeviceCommandStartCRDSessionJob::ResultPayload::CreateNonIdlePayload(
+    const base::TimeDelta& time_delta) {
+  return std::make_unique<ResultPayload>(
+      ResultCode::FAILURE_NOT_IDLE, base::nullopt /* auth_code */, time_delta,
+      base::nullopt /* error_message */);
+}
+
+std::unique_ptr<DeviceCommandStartCRDSessionJob::ResultPayload>
+DeviceCommandStartCRDSessionJob::ResultPayload::CreateErrorPayload(
+    ResultCode result_code,
+    const std::string& error_message) {
+  DCHECK(result_code != ResultCode::SUCCESS);
+  DCHECK(result_code != ResultCode::FAILURE_NOT_IDLE);
+  return std::make_unique<ResultPayload>(
+      result_code, base::nullopt /* auth_code */, base::nullopt /*time_delta*/,
+      error_message);
+}
+
+std::unique_ptr<std::string>
+DeviceCommandStartCRDSessionJob::ResultPayload::Serialize() {
+  return std::make_unique<std::string>(payload_);
+}
+
+DeviceCommandStartCRDSessionJob::DeviceCommandStartCRDSessionJob(
+    Delegate* crd_host_delegate)
+    : delegate_(crd_host_delegate),
+      terminate_session_attemtpted_(false),
+      weak_factory_(this) {}
+
+DeviceCommandStartCRDSessionJob::~DeviceCommandStartCRDSessionJob() {}
+
+enterprise_management::RemoteCommand_Type
+DeviceCommandStartCRDSessionJob::GetType() const {
+  return enterprise_management::RemoteCommand_Type_DEVICE_START_CRD_SESSION;
+}
+
+bool DeviceCommandStartCRDSessionJob::ParseCommandPayload(
+    const std::string& command_payload) {
+  std::unique_ptr<base::Value> root(
+      base::JSONReader().ReadToValue(command_payload));
+  if (!root)
+    return false;
+  if (!root->is_dict())
+    return false;
+
+  base::Value* idleness_cutoff_value =
+      root->FindKeyOfType(kIdlenessCutoffFieldName, base::Value::Type::INTEGER);
+  if (idleness_cutoff_value) {
+    idleness_cutoff_ =
+        base::TimeDelta::FromSeconds(idleness_cutoff_value->GetInt());
+  } else {
+    idleness_cutoff_ = base::TimeDelta::FromSeconds(0);
+  }
+
+  base::Value* directory_jid_value =
+      root->FindKeyOfType(kDirectoryBotJIDFieldName, base::Value::Type::STRING);
+  if (!directory_jid_value)
+    return false;
+  directory_bot_jid_ = directory_jid_value->GetString();
+
+  return true;
+}
+
+void DeviceCommandStartCRDSessionJob::FinishWithError(
+    const ResultCode result_code,
+    const std::string& message) {
+  DCHECK(result_code != ResultCode::SUCCESS);
+  if (failed_callback_.is_null())
+    return;  // Task was terminated.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(failed_callback_,
+                     ResultPayload::CreateErrorPayload(result_code, message)));
+}
+
+void DeviceCommandStartCRDSessionJob::RunImpl(
+    const CallbackWithResult& succeeded_callback,
+    const CallbackWithResult& failed_callback) {
+  VLOG(0) << "Running start crd session command";
+
+  if (delegate_->HasActiveSession()) {
+    CHECK(!terminate_session_attemtpted_);
+    terminate_session_attemtpted_ = true;
+    delegate_->TerminateSession(base::BindOnce(
+        &DeviceCommandStartCRDSessionJob::RunImpl, weak_factory_.GetWeakPtr(),
+        std::move(succeeded_callback), std::move(failed_callback)));
+    return;
+  }
+
+  terminate_session_attemtpted_ = false;
+  failed_callback_ = failed_callback;
+  succeeded_callback_ = succeeded_callback;
+
+  if (!delegate_->AreServicesReady()) {
+    FinishWithError(ResultCode::FAILURE_SERVICES_NOT_READY, "");
+    return;
+  }
+
+  if (!delegate_->IsRunningKiosk()) {
+    FinishWithError(ResultCode::FAILURE_NOT_A_KIOSK, "");
+    return;
+  }
+
+  if (delegate_->GetIdlenessPeriod() < idleness_cutoff_) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(failed_callback_, ResultPayload::CreateNonIdlePayload(
+                                             delegate_->GetIdlenessPeriod())));
+    return;
+  }
+
+  delegate_->FetchOAuthToken(
+      base::BindOnce(&DeviceCommandStartCRDSessionJob::OnOAuthTokenReceived,
+                     weak_factory_.GetWeakPtr()),
+      base::BindOnce(&DeviceCommandStartCRDSessionJob::FinishWithError,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void DeviceCommandStartCRDSessionJob::OnOAuthTokenReceived(
+    const std::string& token) {
+  oauth_token_ = token;
+  delegate_->FetchICEConfig(
+      oauth_token_,
+      base::BindOnce(&DeviceCommandStartCRDSessionJob::OnICEConfigReceived,
+                     weak_factory_.GetWeakPtr()),
+      base::BindOnce(&DeviceCommandStartCRDSessionJob::FinishWithError,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void DeviceCommandStartCRDSessionJob::OnICEConfigReceived(
+    base::Value ice_config) {
+  ice_config_ = std::move(ice_config);
+  delegate_->StartCRDHostAndGetCode(
+      directory_bot_jid_, oauth_token_, std::move(ice_config_),
+      base::BindOnce(&DeviceCommandStartCRDSessionJob::OnAuthCodeReceived,
+                     weak_factory_.GetWeakPtr()),
+      base::BindOnce(&DeviceCommandStartCRDSessionJob::FinishWithError,
+                     weak_factory_.GetWeakPtr()));
+}
+
+void DeviceCommandStartCRDSessionJob::OnAuthCodeReceived(
+    const std::string& auth_code) {
+  if (succeeded_callback_.is_null())
+    return;  // Task was terminated.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(succeeded_callback_,
+                     ResultPayload::CreateSuccessPayload(auth_code)));
+}
+
+void DeviceCommandStartCRDSessionJob::TerminateImpl() {
+  succeeded_callback_.Reset();
+  failed_callback_.Reset();
+  weak_factory_.InvalidateWeakPtrs();
+  delegate_->TerminateSession(base::OnceClosure());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h
new file mode 100644
index 0000000..ebe4bb8
--- /dev/null
+++ b/chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h
@@ -0,0 +1,136 @@
+// 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_START_CRD_SESSION_JOB_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_START_CRD_SESSION_JOB_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/policy/core/common/remote_commands/remote_command_job.h"
+
+namespace policy {
+
+// Remote command that would start Chrome Remote Desktop host and return auth
+// code. This command is usable only for devices running Kiosk sessions.
+class DeviceCommandStartCRDSessionJob : public RemoteCommandJob {
+ public:
+  enum ResultCode {
+    // Successfully obtained access code.
+    SUCCESS = 0,
+
+    // Failed as required services are not launched on the device.
+    FAILURE_SERVICES_NOT_READY = 1,
+
+    // Failed as device is not running in Kiosk mode.
+    FAILURE_NOT_A_KIOSK = 2,
+
+    // Failed as device is currently in use and no interruptUser flag is set.
+    FAILURE_NOT_IDLE = 2,
+
+    // TODO(antrim): Work in progress
+    FAILURE_NOT_IMPLEMENTED_YET = 3,
+  };
+
+  using OAuthTokenCallback = base::OnceCallback<void(const std::string&)>;
+  using AuthCodeCallback = base::OnceCallback<void(const std::string&)>;
+  using ICEConfigCallback = base::OnceCallback<void(base::Value)>;
+  using ErrorCallback =
+      base::OnceCallback<void(ResultCode, const std::string&)>;
+
+  // A delegate interface used by DeviceCommandStartCRDSessionJob to retrieve
+  // its dependencies.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Check if there exists an active CRD session.
+    virtual bool HasActiveSession() = 0;
+
+    // Run |callback| once active CRD session is terminated.
+    virtual void TerminateSession(base::OnceClosure callback) = 0;
+
+    // Check if required system services are ready.
+    virtual bool AreServicesReady() = 0;
+
+    // Check if device is running in Kiosk mode.
+    virtual bool IsRunningKiosk() = 0;
+
+    // Return current user idleness period.
+    virtual base::TimeDelta GetIdlenessPeriod() = 0;
+
+    // Attempts to get OAuth token for CRD Host.
+    virtual void FetchOAuthToken(OAuthTokenCallback success_callback,
+                                 ErrorCallback error_callback) = 0;
+
+    // Attempts to get ICE configuration for CRD Host.
+    virtual void FetchICEConfig(const std::string& oauth_token,
+                                ICEConfigCallback success_callback,
+                                ErrorCallback error_callback) = 0;
+
+    // Attempts to start CRD host and get Auth Code.
+    virtual void StartCRDHostAndGetCode(const std::string& directory_bot_jid,
+                                        const std::string& oauth_token,
+                                        base::Value ice_config,
+                                        AuthCodeCallback success_callback,
+                                        ErrorCallback error_callback) = 0;
+  };
+
+  explicit DeviceCommandStartCRDSessionJob(Delegate* crd_host_delegate);
+  ~DeviceCommandStartCRDSessionJob() override;
+
+  // RemoteCommandJob:
+  enterprise_management::RemoteCommand_Type GetType() const override;
+
+ protected:
+  // RemoteCommandJob:
+  bool ParseCommandPayload(const std::string& command_payload) override;
+  void RunImpl(const CallbackWithResult& succeeded_callback,
+               const CallbackWithResult& failed_callback) override;
+  void TerminateImpl() override;
+
+ private:
+  class ResultPayload;
+
+  // Finishes command with error code and optional message.
+  void FinishWithError(ResultCode result_code, const std::string& message);
+
+  void OnOAuthTokenReceived(const std::string& token);
+  void OnICEConfigReceived(base::Value ice_config);
+  void OnAuthCodeReceived(const std::string& token);
+
+  // The callback that will be called when the access code was successfully
+  // obtained.
+  CallbackWithResult succeeded_callback_;
+
+  // The callback that will be called when this command failed.
+  CallbackWithResult failed_callback_;
+
+  // -- Command parameters --
+
+  // Defines whether connection attempt to active user should succeed or fail.
+  base::TimeDelta idleness_cutoff_;
+
+  std::string oauth_token_;
+  std::string directory_bot_jid_;
+  base::Value ice_config_;
+
+  // The Delegate is used to interact with chrome services and CRD host.
+  // Owned by DeviceCommandsFactoryChromeOS.
+  Delegate* delegate_;
+
+  bool terminate_session_attemtpted_;
+
+  base::WeakPtrFactory<DeviceCommandStartCRDSessionJob> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeviceCommandStartCRDSessionJob);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_START_CRD_SESSION_JOB_H_
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc
index 657d9db1..166f41e 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc
+++ b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h"
 
 #include "base/logging.h"
+#include "chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.h"
 #include "chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.h"
 #include "chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.h"
 #include "chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h"
 #include "chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.h"
+#include "chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h"
 #include "chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job.h"
 #include "chrome/browser/chromeos/policy/remote_commands/screenshot_delegate.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
@@ -35,6 +37,9 @@
           std::make_unique<ScreenshotDelegate>());
     case em::RemoteCommand_Type_DEVICE_SET_VOLUME:
       return std::make_unique<DeviceCommandSetVolumeJob>();
+    case em::RemoteCommand_Type_DEVICE_START_CRD_SESSION:
+      return std::make_unique<DeviceCommandStartCRDSessionJob>(
+          GetCRDHostDelegate());
     case em::RemoteCommand_Type_DEVICE_FETCH_STATUS:
       return std::make_unique<DeviceCommandFetchStatusJob>();
     case em::RemoteCommand_Type_DEVICE_WIPE_USERS:
@@ -47,4 +52,11 @@
   }
 }
 
+CRDHostDelegate* DeviceCommandsFactoryChromeOS::GetCRDHostDelegate() {
+  if (!crd_host_delegate_) {
+    crd_host_delegate_ = std::make_unique<CRDHostDelegate>();
+  }
+  return crd_host_delegate_.get();
+}
+
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h
index 1180f76..cb99de75 100644
--- a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h
+++ b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h
@@ -12,6 +12,8 @@
 
 namespace policy {
 
+class CRDHostDelegate;
+
 class DeviceCommandsFactoryChromeOS : public RemoteCommandsFactory {
  public:
   DeviceCommandsFactoryChromeOS();
@@ -23,6 +25,10 @@
       RemoteCommandsService* service) override;
 
  private:
+  std::unique_ptr<CRDHostDelegate> crd_host_delegate_;
+
+  CRDHostDelegate* GetCRDHostDelegate();
+
   DISALLOW_COPY_AND_ASSIGN(DeviceCommandsFactoryChromeOS);
 };
 
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc
index 104c3e65..0a188c00 100644
--- a/chrome/browser/devtools/devtools_file_helper.cc
+++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -296,8 +296,7 @@
   DictionaryPrefUpdate update(profile_->GetPrefs(),
                               prefs::kDevToolsEditedFiles);
   base::DictionaryValue* files_map = update.Get();
-  files_map->SetWithoutPathExpansion(base::MD5String(url),
-                                     base::CreateFilePathValue(path));
+  files_map->SetKey(base::MD5String(url), base::CreateFilePathValue(path));
   std::string file_system_path = path.AsUTF8Unsafe();
   callback.Run(file_system_path);
   file_task_runner_->PostTask(FROM_HERE, BindOnce(&WriteToFile, path, content));
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index 095f65c..b18ea33 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -470,6 +470,14 @@
     return media_mount_point.Append(relative);
   }
 
+  // Allow paths under the Android files mount point.
+  base::FilePath android_files_mount_point(
+      file_manager::util::kAndroidFilesPath);
+  if (android_files_mount_point.AppendRelativePath(path, &relative) &&
+      !relative.ReferencesParent()) {
+    return android_files_mount_point.Append(relative);
+  }
+
   // Fall back to the default download directory for all other paths.
   return profile_download_dir;
 #endif
diff --git a/chrome/browser/download/download_prefs_unittest.cc b/chrome/browser/download/download_prefs_unittest.cc
index b25d4bc..747c755 100644
--- a/chrome/browser/download/download_prefs_unittest.cc
+++ b/chrome/browser/download/download_prefs_unittest.cc
@@ -133,6 +133,13 @@
   EXPECT_TRUE(prefs.DownloadPath().IsAbsolute());
   EXPECT_EQ(prefs.DownloadPath(), testdir);
 
+  // Test a valid path for Android files.
+  testdir = base::FilePath("/run/arc/sdcard/write/emulated/0/Documents");
+  profile.GetPrefs()->SetString(prefs::kDownloadDefaultDirectory,
+                                testdir.value());
+  EXPECT_TRUE(prefs.DownloadPath().IsAbsolute());
+  EXPECT_EQ(prefs.DownloadPath(), testdir);
+
   // Test with an invalid path outside the download directory.
   profile.GetPrefs()->SetString(prefs::kDownloadDefaultDirectory,
                                 "/home/chronos");
diff --git a/chrome/browser/download/download_target_determiner_unittest.cc b/chrome/browser/download/download_target_determiner_unittest.cc
index 79e4a32..4ca3d5e9 100644
--- a/chrome/browser/download/download_target_determiner_unittest.cc
+++ b/chrome/browser/download/download_target_determiner_unittest.cc
@@ -407,7 +407,8 @@
 void DownloadTargetDeterminerTest::SetManagedDownloadPath(
     const base::FilePath& path) {
   profile()->GetTestingPrefService()->SetManagedPref(
-      prefs::kDownloadDefaultDirectory, base::CreateFilePathValue(path));
+      prefs::kDownloadDefaultDirectory,
+      base::Value::ToUniquePtrValue(base::CreateFilePathValue(path)));
 }
 
 void DownloadTargetDeterminerTest::SetPromptForDownload(bool prompt) {
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 7c009cf..1959e72 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -519,6 +519,15 @@
   EXPECT_TRUE(window_controller()->GetWindowForTesting()->IsVisible());
   EXPECT_TRUE(
       window_controller()->GetWindowForTesting()->GetVideoLayer()->visible());
+
+#if !defined(OS_ANDROID)
+  OverlayWindowViews* overlay_window = static_cast<OverlayWindowViews*>(
+      window_controller()->GetWindowForTesting());
+
+  EXPECT_FALSE(overlay_window->play_pause_controls_view_for_testing()
+                   ->layer()
+                   ->visible());
+#endif
 }
 
 // Tests that we can enter Picture-in-Picture when a video is not preloaded,
diff --git a/chrome/browser/prefs/pref_service_incognito_whitelist.cc b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
index b52efa42..c2b6380 100644
--- a/chrome/browser/prefs/pref_service_incognito_whitelist.cc
+++ b/chrome/browser/prefs/pref_service_incognito_whitelist.cc
@@ -197,68 +197,6 @@
     prefs::kOwnerLocale, prefs::kAllowedUILocales,
 #endif
 
-    prefs::kDefaultCharset, prefs::kAcceptLanguages, prefs::kWebKitCommonScript,
-    prefs::kWebKitStandardFontFamily, prefs::kWebKitFixedFontFamily,
-    prefs::kWebKitSerifFontFamily, prefs::kWebKitSansSerifFontFamily,
-    prefs::kWebKitCursiveFontFamily, prefs::kWebKitFantasyFontFamily,
-    prefs::kWebKitPictographFontFamily,
-
-    // prefs::kWebKitScriptsForFontFamilyMaps,
-    // prefs::kWebKitScriptsForFontFamilyMapsLength,
-
-    prefs::kWebKitStandardFontFamilyMap, prefs::kWebKitFixedFontFamilyMap,
-    prefs::kWebKitSerifFontFamilyMap, prefs::kWebKitSansSerifFontFamilyMap,
-    prefs::kWebKitCursiveFontFamilyMap, prefs::kWebKitFantasyFontFamilyMap,
-    prefs::kWebKitPictographFontFamilyMap,
-
-    prefs::kWebKitStandardFontFamilyArabic,
-#if defined(OS_WIN)
-    prefs::kWebKitFixedFontFamilyArabic,
-#endif
-    prefs::kWebKitSerifFontFamilyArabic,
-    prefs::kWebKitSansSerifFontFamilyArabic,
-#if defined(OS_WIN)
-    prefs::kWebKitStandardFontFamilyCyrillic,
-    prefs::kWebKitFixedFontFamilyCyrillic,
-    prefs::kWebKitSerifFontFamilyCyrillic,
-    prefs::kWebKitSansSerifFontFamilyCyrillic,
-    prefs::kWebKitStandardFontFamilyGreek, prefs::kWebKitFixedFontFamilyGreek,
-    prefs::kWebKitSerifFontFamilyGreek, prefs::kWebKitSansSerifFontFamilyGreek,
-#endif
-    prefs::kWebKitStandardFontFamilyJapanese,
-    prefs::kWebKitFixedFontFamilyJapanese,
-    prefs::kWebKitSerifFontFamilyJapanese,
-    prefs::kWebKitSansSerifFontFamilyJapanese,
-    prefs::kWebKitStandardFontFamilyKorean, prefs::kWebKitFixedFontFamilyKorean,
-    prefs::kWebKitSerifFontFamilyKorean,
-    prefs::kWebKitSansSerifFontFamilyKorean,
-#if defined(OS_WIN)
-    prefs::kWebKitCursiveFontFamilyKorean,
-#endif
-    prefs::kWebKitStandardFontFamilySimplifiedHan,
-    prefs::kWebKitFixedFontFamilySimplifiedHan,
-    prefs::kWebKitSerifFontFamilySimplifiedHan,
-    prefs::kWebKitSansSerifFontFamilySimplifiedHan,
-    prefs::kWebKitStandardFontFamilyTraditionalHan,
-    prefs::kWebKitFixedFontFamilyTraditionalHan,
-    prefs::kWebKitSerifFontFamilyTraditionalHan,
-    prefs::kWebKitSansSerifFontFamilyTraditionalHan,
-#if defined(OS_WIN) || defined(OS_MACOSX)
-    prefs::kWebKitCursiveFontFamilySimplifiedHan,
-    prefs::kWebKitCursiveFontFamilyTraditionalHan,
-#endif
-
-    prefs::kWebKitDefaultFontSize, prefs::kWebKitDefaultFixedFontSize,
-    prefs::kWebKitMinimumFontSize, prefs::kWebKitMinimumLogicalFontSize,
-    prefs::kWebKitJavascriptEnabled, prefs::kWebKitWebSecurityEnabled,
-    prefs::kWebKitLoadsImagesAutomatically, prefs::kWebKitPluginsEnabled,
-    prefs::kWebKitDomPasteEnabled, prefs::kWebKitTextAreasAreResizable,
-    prefs::kWebKitJavascriptCanAccessClipboard, prefs::kWebkitTabsToLinks,
-    prefs::kWebKitAllowRunningInsecureContent,
-#if defined(OS_ANDROID)
-    prefs::kWebKitFontScaleFactor, prefs::kWebKitForceEnableZoom,
-    prefs::kWebKitPasswordEchoEnabled,
-#endif
     prefs::kDataSaverEnabled, prefs::kSSLErrorOverrideAllowed,
     prefs::kIncognitoModeAvailability, prefs::kSearchSuggestEnabled,
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 2d962daa..41d43872 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -274,6 +274,10 @@
   return profile_->GetPath();
 }
 
+base::FilePath OffTheRecordProfileImpl::GetCachePath() const {
+  return profile_->GetCachePath();
+}
+
 #if !defined(OS_ANDROID)
 std::unique_ptr<content::ZoomLevelDelegate>
 OffTheRecordProfileImpl::CreateZoomLevelDelegate(
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 5d31663..3ae418b6 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -90,6 +90,7 @@
 
   // content::BrowserContext implementation:
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
 #if !defined(OS_ANDROID)
   std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 08aa42ac..7b6be44 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -807,6 +807,10 @@
   return path_;
 }
 
+base::FilePath ProfileImpl::GetCachePath() const {
+  return base_cache_path_;
+}
+
 scoped_refptr<base::SequencedTaskRunner> ProfileImpl::GetIOTaskRunner() {
   return io_task_runner_;
 }
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 7a57e58b..d685bdc 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -79,6 +79,7 @@
       const base::FilePath& partition_path) override;
 #endif
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
   content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
   content::ResourceContext* GetResourceContext() override;
   content::BrowserPluginGuestManager* GetGuestManager() override;
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index be5d790..3d4ae65 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -240,8 +240,7 @@
   // on shutdown. In case of a crash remaining files are removed on next start.
   ListPrefUpdate deleted_profiles(g_browser_process->local_state(),
                                   prefs::kProfilesDeleted);
-  std::unique_ptr<base::Value> value(CreateFilePathValue(path));
-  deleted_profiles->Append(std::move(value));
+  deleted_profiles->GetList().push_back(CreateFilePathValue(path));
 }
 
 // Cancel a scheduling deletion, so ScheduleProfileDirectoryForDeletion can be
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index f14f0e74..0a8fa09 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -173,7 +173,7 @@
 
       <template is="dom-if" route-path="/content/all" no-search>
         <settings-subpage page-title="$i18n{siteSettingsAllSites}">
-          <all-sites></all-sites>
+          <all-sites focus-config="[[focusConfig_]]"></all-sites>
         </settings-subpage>
       </template>
       <template is="dom-if" route-path="/content/automaticDownloads" no-search>
diff --git a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
index 7492cde1..ef24e1a 100644
--- a/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
+++ b/chrome/browser/resources/settings/settings_page/settings_animated_pages.js
@@ -88,6 +88,9 @@
     if (settings.routes.SITE_SETTINGS_SITE_DATA)
       subpagePaths.push(settings.routes.SITE_SETTINGS_SITE_DATA.path);
 
+    if (settings.routes.SITE_SETTINGS_ALL)
+      subpagePaths.push(settings.routes.SITE_SETTINGS_ALL.path);
+
     // <if expr="chromeos">
     if (settings.routes.INTERNET_NETWORKS)
       subpagePaths.push(settings.routes.INTERNET_NETWORKS.path);
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.html b/chrome/browser/resources/settings/site_settings/all_sites.html
index 64da4599..dab0069 100644
--- a/chrome/browser/resources/settings/site_settings/all_sites.html
+++ b/chrome/browser/resources/settings/site_settings/all_sites.html
@@ -56,7 +56,8 @@
           items="[[filterPopulatedList_(siteGroupList, searchQuery_)]]"
           scroll-target="[[subpageScrollTarget]]">
         <template>
-          <site-entry site-group="[[item]]" list-index="[[index]]"></site-entry>
+          <site-entry site-group="[[item]]" list-index="[[index]]"
+              tabindex$="[[tabIndex]]"></site-entry>
         </template>
       </iron-list>
     </div>
diff --git a/chrome/browser/resources/settings/site_settings/all_sites.js b/chrome/browser/resources/settings/site_settings/all_sites.js
index 537bc46b..8b022b8 100644
--- a/chrome/browser/resources/settings/site_settings/all_sites.js
+++ b/chrome/browser/resources/settings/site_settings/all_sites.js
@@ -65,6 +65,22 @@
       },
       readOnly: true,
     },
+
+    /**
+     * Stores the last selected item in the All Sites list.
+     * @type {?{item: !SiteGroup, index: number}}
+     * @private
+     */
+    selectedItem_: Object,
+
+    /**
+     * Used to determine focus between settings pages.
+     * @type {!Map<string, (string|Function)>}
+     */
+    focusConfig: {
+      type: Object,
+      observer: 'focusConfigChanged_',
+    },
   },
 
   /** @override */
@@ -75,6 +91,12 @@
         'contentSettingSitePermissionChanged', this.populateList_.bind(this));
     this.addEventListener(
         'site-entry-resized', this.resizeListIfScrollTargetActive_.bind(this));
+    this.addEventListener(
+        'site-entry-selected',
+        (/** @type {!{detail: !{item: !SiteGroup, index: number}}} */ e) => {
+          this.selectedItem_ = e.detail;
+        });
+
     this.populateList_();
   },
 
@@ -168,4 +190,36 @@
     if (settings.getCurrentRoute() == this.subpageRoute)
       this.$.allSitesList.fire('iron-resize');
   },
+
+  /**
+   * @param {!Map<string, (string|Function)>} newConfig
+   * @param {?Map<string, (string|Function)>} oldConfig
+   * @private
+   */
+  focusConfigChanged_: function(newConfig, oldConfig) {
+    // focusConfig is set only once on the parent, so this observer should only
+    // fire once.
+    assert(!oldConfig);
+
+    if (!settings.routes.SITE_SETTINGS_ALL)
+      return;
+
+    const onNavigatedTo = () => {
+      this.async(() => {
+        if (this.selectedItem_ == null || this.siteGroupList.length == 0)
+          return;
+
+        // Focus the site-entry to ensure the iron-list renders it, otherwise
+        // the query selector will not be able to find it. Note the index is
+        // used here instead of the item, in case the item was already removed.
+        const index = Math.max(
+            0, Math.min(this.selectedItem_.index, this.siteGroupList.length));
+        this.$.allSitesList.focusItem(index);
+        this.selectedItem_ = null;
+      });
+    };
+
+    this.focusConfig.set(
+        settings.routes.SITE_SETTINGS_SITE_DETAILS.path, onNavigatedTo);
+  },
 });
diff --git a/chrome/browser/resources/settings/site_settings/site_entry.js b/chrome/browser/resources/settings/site_settings/site_entry.js
index e5fc84d1..0cb5e4f0 100644
--- a/chrome/browser/resources/settings/site_settings/site_entry.js
+++ b/chrome/browser/resources/settings/site_settings/site_entry.js
@@ -36,6 +36,18 @@
       type: String,
       value: '',
     },
+
+    /**
+     * The position of this site-entry in its parent list.
+     */
+    listIndex: {
+      type: Number,
+      value: -1,
+    },
+  },
+
+  listeners: {
+    'focus': 'onFocus_',
   },
 
   /** @private {?settings.LocalDataBrowserProxy} */
@@ -159,6 +171,8 @@
    * @private
    */
   navigateToSiteDetails_: function(origin) {
+    this.fire(
+        'site-entry-selected', {item: this.siteGroup, index: this.listIndex});
     settings.navigateTo(
         settings.routes.SITE_SETTINGS_SITE_DETAILS,
         new URLSearchParams('site=' + origin));
@@ -282,4 +296,15 @@
       return 'first';
     return '';
   },
+
+  /**
+   * Focuses the first focusable button in this site-entry.
+   * @private
+   */
+  onFocus_: function() {
+    const button = /** @type Element */
+        (this.root.querySelector('#toggleButton *:not([hidden]) button'));
+    button.focus();
+    this.tabIndex = -1;
+  },
 });
diff --git a/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.js b/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.js
index 46c5895..c6aec9f 100644
--- a/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.js
+++ b/chrome/browser/resources/signin/signin_email_confirmation/signin_email_confirmation.js
@@ -33,15 +33,7 @@
   }
 
   function onConfirm(e) {
-    var action;
-    if ($('createNewUserRadioButton').active) {
-      action = 'createNewUser';
-    } else if ($('startSyncRadioButton').active) {
-      action = 'startSync';
-    } else {
-      // Action is unknown as no radio button is selected.
-      action = 'unknown';
-    }
+    const action = document.querySelector('paper-radio-group').selected;
     chrome.send('dialogClose', [JSON.stringify({'action': action})]);
   }
 
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index e53ea55..1f97100 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -629,19 +629,10 @@
           ->change_processor()
           ->GetControllerDelegateOnUIThread();
 #endif  // defined(OS_CHROMEOS)
-    case syncer::TYPED_URLS: {
-      // We request history service with explicit access here because this
-      // codepath is executed on backend thread while HistoryServiceFactory
-      // checks preference value in implicit mode and PrefService expectes calls
-      // only from UI thread.
-      history::HistoryService* history = HistoryServiceFactory::GetForProfile(
-          profile_, ServiceAccessType::EXPLICIT_ACCESS);
-      if (!history)
-        return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
-      return history->GetTypedURLSyncBridge()
-          ->change_processor()
-          ->GetControllerDelegateOnUIThread();
-    }
+    case syncer::TYPED_URLS:
+      // TypedURLModelTypeController doesn't exercise this function.
+      NOTREACHED();
+      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::USER_CONSENTS:
       return ConsentAuditorFactory::GetForProfile(profile_)
           ->GetControllerDelegateOnUIThread();
diff --git a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
index b6a1a25..e1b364c 100644
--- a/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_bookmarks_sync_test.cc
@@ -532,6 +532,46 @@
   ASSERT_EQ(1, CountFoldersWithTitlesMatching(kSingleProfileIndex, title));
 }
 
+IN_PROC_BROWSER_TEST_P(SingleClientBookmarksSyncTestIncludingUssTests,
+                       DownloadBookmarkFoldersWithPositions) {
+  const std::string title0 = "Folder left";
+  const std::string title1 = "Folder middle";
+  const std::string title2 = "Folder right";
+
+  fake_server::EntityBuilderFactory entity_builder_factory;
+
+  fake_server::BookmarkEntityBuilder bookmark0_builder =
+      entity_builder_factory.NewBookmarkEntityBuilder(title0);
+  bookmark0_builder.SetIndex(0);
+
+  fake_server::BookmarkEntityBuilder bookmark1_builder =
+      entity_builder_factory.NewBookmarkEntityBuilder(title1);
+  bookmark1_builder.SetIndex(1);
+
+  fake_server::BookmarkEntityBuilder bookmark2_builder =
+      entity_builder_factory.NewBookmarkEntityBuilder(title2);
+  bookmark2_builder.SetIndex(2);
+
+  fake_server_->InjectEntity(bookmark0_builder.BuildFolder());
+  fake_server_->InjectEntity(bookmark2_builder.BuildFolder());
+  fake_server_->InjectEntity(bookmark1_builder.BuildFolder());
+
+  DisableVerifier();
+  ASSERT_TRUE(SetupClients());
+
+  ASSERT_TRUE(SetupSync());
+
+  EXPECT_EQ(1, CountFoldersWithTitlesMatching(kSingleProfileIndex, title0));
+  EXPECT_EQ(1, CountFoldersWithTitlesMatching(kSingleProfileIndex, title1));
+  EXPECT_EQ(1, CountFoldersWithTitlesMatching(kSingleProfileIndex, title2));
+
+  const BookmarkNode* bar = GetBookmarkBarNode(kSingleProfileIndex);
+  ASSERT_EQ(3, bar->child_count());
+  EXPECT_EQ(base::ASCIIToUTF16(title0), bar->GetChild(0)->GetTitle());
+  EXPECT_EQ(base::ASCIIToUTF16(title1), bar->GetChild(1)->GetTitle());
+  EXPECT_EQ(base::ASCIIToUTF16(title2), bar->GetChild(2)->GetTitle());
+}
+
 IN_PROC_BROWSER_TEST_F(SingleClientBookmarksSyncTest, E2E_ONLY(SanitySetup)) {
   ASSERT_TRUE(SetupSync()) <<  "SetupSync() failed.";
 }
diff --git a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
index 1abcc44c..154216a 100644
--- a/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
+++ b/chrome/browser/sync/test/integration/two_client_bookmarks_sync_test.cc
@@ -125,7 +125,7 @@
   DISALLOW_COPY_AND_ASSIGN(TwoClientBookmarksSyncTestIncludingUssTests);
 };
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, Sanity) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests, Sanity) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -185,7 +185,18 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_Add3FoldersInShuffledOrder) {
+  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
+  ASSERT_TRUE(AllModelsMatchVerifier());
+
+  ASSERT_NE(nullptr, AddFolder(0, 0, IndexedFolderName(0)));
+  ASSERT_NE(nullptr, AddFolder(0, 1, IndexedFolderName(2)));
+  ASSERT_NE(nullptr, AddFolder(0, 1, IndexedFolderName(1)));
+  ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
+}
+
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_AddFirstBMWithoutFavicon) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -360,7 +371,8 @@
   CheckHasNoFavicon(0, page_url);
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_AddNonHTTPBMs) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_AddNonHTTPBMs) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -370,7 +382,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_AddFirstBMUnderFolder) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -381,7 +393,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_AddSeveralBMsUnderBMBarAndOtherBM) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -395,7 +407,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_AddSeveralBMsAndFolders) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -426,7 +438,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_DuplicateBMWithDifferentURLSameName) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -451,7 +463,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMName) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_RenameBMName) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -465,7 +478,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMURL) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_RenameBMURL) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -480,7 +494,7 @@
 }
 
 // Renaming the same bookmark name twice.
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_TwiceRenamingBookmarkName) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -499,7 +513,7 @@
 }
 
 // Renaming the same bookmark URL twice.
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_TwiceRenamingBookmarkURL) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -517,7 +531,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMFolder) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_RenameBMFolder) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -531,7 +546,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameEmptyBMFolder) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_RenameEmptyBMFolder) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -544,7 +560,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_RenameBMFolderWithLongHierarchy) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -569,7 +585,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_RenameBMFolderThatHasParentAndChildren) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -600,7 +616,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_RenameBMNameAndURL) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_RenameBMNameAndURL) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -646,7 +663,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_DelFirstBMUnderBMFoldNonEmptyFoldAfterwards) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -664,7 +681,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_DelLastBMUnderBMFoldNonEmptyFoldAfterwards) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -682,7 +699,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_DelMiddleBMUnderBMFoldNonEmptyFoldAfterwards) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -700,7 +717,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_DelBMsUnderBMFoldEmptyFolderAfterwards) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -832,7 +849,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_DelBMFoldWithParentAndChildrenBMsAndBMFolds) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -863,7 +880,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_ReverseTheOrderOfTwoBMs) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -882,7 +899,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_ReverseTheOrderOf10BMs) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_ReverseTheOrderOf10BMs) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -897,7 +915,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_MovingBMsFromBMBarToBMFolder) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -922,7 +940,7 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_MovingBMsFromBMFoldToBMBar) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -945,7 +963,7 @@
   }
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_MovingBMsFromParentBMFoldToChildBMFold) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -974,7 +992,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_MovingBMsFromChildBMFoldToParentBMFold) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -1003,7 +1021,8 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_HoistBMs10LevelUp) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_HoistBMs10LevelUp) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -1041,7 +1060,8 @@
 }
 
 // Flaky. http://crbug.com/107744.
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest, SC_SinkBMs10LevelDown) {
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
+                       SC_SinkBMs10LevelDown) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
 
@@ -1077,7 +1097,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_SinkEmptyBMFold5LevelsDown) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -1106,7 +1126,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_SinkNonEmptyBMFold5LevelsDown) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -1139,7 +1159,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_HoistFolder5LevelsUp) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -1172,7 +1192,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_ReverseTheOrderOfTwoBMFolders) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
@@ -1193,7 +1213,7 @@
   ASSERT_TRUE(BookmarksMatchVerifierChecker().Wait());
 }
 
-IN_PROC_BROWSER_TEST_F(TwoClientBookmarksSyncTest,
+IN_PROC_BROWSER_TEST_P(TwoClientBookmarksSyncTestIncludingUssTests,
                        SC_ReverseTheOrderOfTenBMFolders) {
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
   ASSERT_TRUE(AllModelsMatchVerifier());
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index 5b39591..a1af28e2 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -43,11 +43,14 @@
 
 namespace {
 
+// The tallest tab height in any mode.
+constexpr int kTallestTabHeight = 41;
+
 // Version number of the current theme pack. We just throw out and rebuild
 // theme packs that aren't int-equal to this. Increment this number if you
 // change default theme assets or if you need themes to recreate their generated
 // images (which are cached).
-const int kThemePackVersion = 50;
+const int kThemePackVersion = 51;
 
 // IDs that are in the DataPack won't clash with the positive integer
 // uint16_t. kHeaderID should always have the maximum value because we want the
@@ -510,10 +513,13 @@
                            size().height());
     }
 
-    // If they've provided a custom image, overlay it.
+    // If they've provided a custom image, overlay it.  Since tabs have grown
+    // taller over time, not all themes have a sufficiently tall image; tiling
+    // by vertically mirroring in this case is the least-glitchy-looking option.
     if (!overlay_.isNull()) {
-      canvas->TileImageInt(overlay_, 0, 0, size().width(),
-                           overlay_.height());
+      canvas->TileImageInt(overlay_, 0, 0, 0, 0, size().width(),
+                           size().height(), 1.0f, SkShader::kRepeat_TileMode,
+                           SkShader::kMirror_TileMode);
     }
   }
 
@@ -1282,8 +1288,10 @@
           background_color, image_to_tint, overlay,
           GetTintInternal(ThemeProperties::TINT_BACKGROUND_TAB),
           kRestoredTabVerticalOffset);
+      gfx::Size dest_size = image_to_tint.size();
+      dest_size.SetToMax(gfx::Size(0, kTallestTabHeight));
       temp_output[prs_id] =
-          gfx::Image(gfx::ImageSkia(std::move(source), image_to_tint.size()));
+          gfx::Image(gfx::ImageSkia(std::move(source), dest_size));
     }
   }
   MergeImageCaches(temp_output, images);
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 9eaeb2c..e6e8079 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -1165,6 +1165,8 @@
       "android/infobars/instant_apps_infobar.h",
       "android/infobars/near_oom_infobar.cc",
       "android/infobars/near_oom_infobar.h",
+      "android/infobars/near_oom_reduction_infobar.cc",
+      "android/infobars/near_oom_reduction_infobar.h",
       "android/infobars/permission_infobar.cc",
       "android/infobars/permission_infobar.h",
       "android/infobars/previews_infobar.cc",
diff --git a/chrome/browser/ui/android/infobars/near_oom_reduction_infobar.cc b/chrome/browser/ui/android/infobars/near_oom_reduction_infobar.cc
new file mode 100644
index 0000000..a1660a2
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/near_oom_reduction_infobar.cc
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/android/infobars/near_oom_reduction_infobar.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/android/jni_string.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/android/tab_android.h"
+#include "chrome/browser/infobars/infobar_service.h"
+#include "chrome/browser/ui/interventions/intervention_delegate.h"
+#include "chrome/browser/ui/interventions/intervention_infobar_delegate.h"
+#include "components/infobars/core/infobar_delegate.h"
+#include "content/public/browser/web_contents.h"
+#include "jni/NearOomReductionInfoBar_jni.h"
+
+NearOomReductionInfoBar::NearOomReductionInfoBar(InterventionDelegate* delegate)
+    : InfoBarAndroid(std::make_unique<InterventionInfoBarDelegate>(
+          infobars::InfoBarDelegate::InfoBarIdentifier::
+              NEAR_OOM_REDUCTION_INFOBAR_ANDROID,
+          delegate)),
+      delegate_(delegate) {
+  DCHECK(delegate_);
+}
+
+NearOomReductionInfoBar::~NearOomReductionInfoBar() = default;
+
+void NearOomReductionInfoBar::ProcessButton(int action) {
+  NOTREACHED();  // No button on this infobar.
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+NearOomReductionInfoBar::CreateRenderInfoBar(JNIEnv* env) {
+  return Java_NearOomReductionInfoBar_create(env);
+}
+
+void NearOomReductionInfoBar::OnLinkClicked(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj) {
+  if (!owner())
+    return;  // We're closing; don't call anything, it might access the owner.
+
+  delegate_->DeclineInterventionWithReload();
+  RemoveSelf();
+}
+
+// static
+void NearOomReductionInfoBar::Show(content::WebContents* web_contents,
+                                   InterventionDelegate* delegate) {
+  InfoBarService* service = InfoBarService::FromWebContents(web_contents);
+  service->AddInfoBar(base::WrapUnique(new NearOomReductionInfoBar(delegate)));
+}
diff --git a/chrome/browser/ui/android/infobars/near_oom_reduction_infobar.h b/chrome/browser/ui/android/infobars/near_oom_reduction_infobar.h
new file mode 100644
index 0000000..53712859
--- /dev/null
+++ b/chrome/browser/ui/android/infobars/near_oom_reduction_infobar.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_ANDROID_INFOBARS_NEAR_OOM_REDUCTION_INFOBAR_H_
+#define CHROME_BROWSER_UI_ANDROID_INFOBARS_NEAR_OOM_REDUCTION_INFOBAR_H_
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "chrome/browser/ui/android/infobars/infobar_android.h"
+
+namespace content {
+class WebContents;
+}
+
+class InterventionDelegate;
+
+// Communicates to the user about the intervention performed by the browser to
+// limit the page's memory usage. See NearOomReductionInfoBar.java for UI
+// specifics, and NearOomMessageDelegate for behavior specifics.
+class NearOomReductionInfoBar : public InfoBarAndroid {
+ public:
+  ~NearOomReductionInfoBar() override;
+
+  static void Show(content::WebContents* web_contents,
+                   InterventionDelegate* delegate);
+
+ private:
+  explicit NearOomReductionInfoBar(InterventionDelegate* delegate);
+
+  // InfoBarAndroid:
+  base::android::ScopedJavaLocalRef<jobject> CreateRenderInfoBar(
+      JNIEnv* env) override;
+  void OnLinkClicked(JNIEnv* env,
+                     const base::android::JavaParamRef<jobject>& obj) override;
+  void ProcessButton(int action) override;
+
+  InterventionDelegate* delegate_;
+  DISALLOW_COPY_AND_ASSIGN(NearOomReductionInfoBar);
+};
+
+#endif  // CHROME_BROWSER_UI_ANDROID_INFOBARS_NEAR_OOM_REDUCTION_INFOBAR_H_
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 28824ed..da3e63f4 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -150,6 +150,7 @@
 #include "chrome/browser/ui/window_sizer/window_sizer.h"
 #include "chrome/browser/upgrade_detector.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
+#include "chrome/browser/web_applications/extensions/web_app_extension_helpers.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/custom_handlers/protocol_handler.h"
@@ -291,6 +292,21 @@
 #endif
 }
 
+std::unique_ptr<extensions::HostedAppBrowserController>
+MaybeCreateHostedAppController(Browser* browser) {
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  const std::string extension_id =
+      web_app::GetExtensionIdFromApplicationName(browser->app_name());
+  const Extension* extension =
+      extensions::ExtensionRegistry::Get(browser->profile())
+          ->GetExtensionById(extension_id,
+                             extensions::ExtensionRegistry::EVERYTHING);
+  if (extension && extension->is_hosted_app())
+    return std::make_unique<extensions::HostedAppBrowserController>(browser);
+#endif
+  return nullptr;
+}
+
 }  // namespace
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -381,6 +397,7 @@
       toolbar_model_delegate_(new BrowserToolbarModelDelegate(this)),
       live_tab_context_(new BrowserLiveTabContext(this)),
       synced_window_delegate_(new BrowserSyncedWindowDelegate(this)),
+      hosted_app_controller_(MaybeCreateHostedAppController(this)),
       bookmark_bar_state_(BookmarkBar::HIDDEN),
       command_controller_(new chrome::BrowserCommandController(this)),
       window_has_shown_(false),
@@ -435,11 +452,6 @@
   if (search::IsInstantExtendedAPIEnabled() && is_type_tabbed())
     instant_controller_.reset(new BrowserInstantController(this));
 
-  if (extensions::HostedAppBrowserController::IsForHostedApp(this)) {
-    hosted_app_controller_.reset(
-        new extensions::HostedAppBrowserController(this));
-  }
-
   UpdateBookmarkBarState(BOOKMARK_BAR_STATE_CHANGE_INIT);
 
   ProfileMetrics::LogProfileLaunch(profile_);
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index 4945321..48bc28d 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -279,6 +279,9 @@
   BrowserInstantController* instant_controller() {
     return instant_controller_.get();
   }
+  const extensions::HostedAppBrowserController* hosted_app_controller() const {
+    return hosted_app_controller_.get();
+  }
   extensions::HostedAppBrowserController* hosted_app_controller() {
     return hosted_app_controller_.get();
   }
@@ -991,6 +994,8 @@
   std::unique_ptr<BrowserInstantController> instant_controller_;
 
   // Helper which handles bookmark app specific browser configuration.
+  // This must be initialized before |command_controller_| to ensure the correct
+  // set of commands are enabled.
   std::unique_ptr<extensions::HostedAppBrowserController>
       hosted_app_controller_;
 
diff --git a/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util_unittest.cc b/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util_unittest.cc
index 3bdc5db..9b9ea32 100644
--- a/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util_unittest.cc
+++ b/chrome/browser/ui/desktop_ios_promotion/desktop_ios_promotion_util_unittest.cc
@@ -53,12 +53,12 @@
 }
 
 constexpr int kSMSEntrypointSavePasswordBubble =
-    1
-    << static_cast<int>(desktop_ios_promotion::PromotionEntryPoint::SAVE_PASSWORD_BUBBLE);
+    1 << static_cast<int>(
+        desktop_ios_promotion::PromotionEntryPoint::SAVE_PASSWORD_BUBBLE);
 
 constexpr int kSMSEntrypointBookmarksBubble =
-    1
-    << static_cast<int>(desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE);
+    1 << static_cast<int>(
+        desktop_ios_promotion::PromotionEntryPoint::BOOKMARKS_BUBBLE);
 
 }  // namespace
 
@@ -94,7 +94,7 @@
 
   Profile* profile() { return profile_.get(); }
 
-  const std::string& account_id() {
+  std::string account_id() {
     return identity_test_environment_.identity_manager()
         ->GetPrimaryAccountInfo()
         .account_id;
@@ -178,6 +178,8 @@
        false, true},
   };
   std::string locale = base::i18n::GetConfiguredLocale();
+  SigninErrorControllerFactory::GetForProfile(profile())->SetPrimaryAccountID(
+      account_id());
 
   for (const auto& test_case : kTestData) {
     SCOPED_TRACE(testing::Message("#test_case = ") << (&test_case - kTestData));
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
index 071ecde..c34c9ca 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.cc
@@ -107,23 +107,10 @@
     "Webapp.Engagement.EngagementType";
 
 // static
-bool HostedAppBrowserController::IsForHostedApp(const Browser* browser) {
-  if (!browser)
-    return false;
-
-  const std::string extension_id =
-      web_app::GetExtensionIdFromApplicationName(browser->app_name());
-  const Extension* extension =
-      ExtensionRegistry::Get(browser->profile())->GetExtensionById(
-          extension_id, ExtensionRegistry::EVERYTHING);
-  return extension && extension->is_hosted_app();
-}
-
-// static
 bool HostedAppBrowserController::IsForExperimentalHostedAppBrowser(
     const Browser* browser) {
-  return base::FeatureList::IsEnabled(::features::kDesktopPWAWindowing) &&
-         IsForHostedApp(browser);
+  return browser && browser->hosted_app_controller() &&
+         base::FeatureList::IsEnabled(::features::kDesktopPWAWindowing);
 }
 
 // static
diff --git a/chrome/browser/ui/extensions/hosted_app_browser_controller.h b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
index 49681bc..6503a2e 100644
--- a/chrome/browser/ui/extensions/hosted_app_browser_controller.h
+++ b/chrome/browser/ui/extensions/hosted_app_browser_controller.h
@@ -30,9 +30,6 @@
 class HostedAppBrowserController : public SiteEngagementObserver,
                                    public TabStripModelObserver {
  public:
-  // Indicates whether |browser| is a hosted app browser.
-  static bool IsForHostedApp(const Browser* browser);
-
   // Returns whether |browser| uses the experimental hosted app experience.
   static bool IsForExperimentalHostedAppBrowser(const Browser* browser);
 
diff --git a/chrome/browser/ui/interventions/framebust_block_message_delegate.cc b/chrome/browser/ui/interventions/framebust_block_message_delegate.cc
index d818ec1..02f9b3d 100644
--- a/chrome/browser/ui/interventions/framebust_block_message_delegate.cc
+++ b/chrome/browser/ui/interventions/framebust_block_message_delegate.cc
@@ -47,6 +47,10 @@
       ui::PAGE_TRANSITION_LINK, false));
 }
 
+void FramebustBlockMessageDelegate::DeclineInterventionWithReload() {
+  DeclineIntervention();
+}
+
 void FramebustBlockMessageDelegate::DeclineInterventionSticky() {
   HostContentSettingsMap* settings_map =
       HostContentSettingsMapFactory::GetForProfile(
diff --git a/chrome/browser/ui/interventions/framebust_block_message_delegate.h b/chrome/browser/ui/interventions/framebust_block_message_delegate.h
index b15b29a..dce1f4d 100644
--- a/chrome/browser/ui/interventions/framebust_block_message_delegate.h
+++ b/chrome/browser/ui/interventions/framebust_block_message_delegate.h
@@ -39,6 +39,7 @@
   // InterventionDelegate:
   void AcceptIntervention() override;
   void DeclineIntervention() override;
+  void DeclineInterventionWithReload() override;
   void DeclineInterventionSticky() override;
 
  private:
diff --git a/chrome/browser/ui/interventions/intervention_delegate.h b/chrome/browser/ui/interventions/intervention_delegate.h
index 234c596..e242d79 100644
--- a/chrome/browser/ui/interventions/intervention_delegate.h
+++ b/chrome/browser/ui/interventions/intervention_delegate.h
@@ -10,6 +10,7 @@
  public:
   virtual void AcceptIntervention() = 0;
   virtual void DeclineIntervention() = 0;
+  virtual void DeclineInterventionWithReload() = 0;
 
   // Called if the user declines the intervention in a sticky way. e.g. by
   // indicating they always want to decline the intervention on the site.
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index d5845ef..29da264f 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -421,6 +421,9 @@
 }
 
 void OverlayWindowViews::SetPlaybackState(PlaybackState playback_state) {
+  // TODO(apacible): have machine state for controls visibility.
+  bool play_pause_layer_visible = GetPlayPauseControlsLayer()->visible();
+
   switch (playback_state) {
     case kPlaying:
       play_pause_controls_view_->SetToggled(true);
@@ -437,6 +440,8 @@
       video_view_->SetVisible(false);
       break;
   }
+
+  GetPlayPauseControlsLayer()->SetVisible(play_pause_layer_visible);
 }
 
 ui::Layer* OverlayWindowViews::GetWindowBackgroundLayer() {
@@ -512,7 +517,13 @@
 void OverlayWindowViews::OnMouseEvent(ui::MouseEvent* event) {
   switch (event->type()) {
     // Only show the media controls when the mouse is hovering over the window.
+    // This is checking for both ENTERED and MOVED because ENTERED is not fired
+    // after a resize on Windows.
     case ui::ET_MOUSE_ENTERED:
+    case ui::ET_MOUSE_MOVED:
+      UpdateControlsVisibility(true);
+      break;
+
       UpdateControlsVisibility(true);
       break;
 
@@ -619,3 +630,7 @@
 void OverlayWindowViews::ClickCustomControl(const std::string& control_id) {
   controller_->ClickCustomControl(control_id);
 }
+
+views::View* OverlayWindowViews::play_pause_controls_view_for_testing() const {
+  return play_pause_controls_view_.get();
+}
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index da9e1f3..53bc830 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -60,6 +60,8 @@
   // Send the message that a custom control on |this| has been clicked.
   void ClickCustomControl(const std::string& control_id);
 
+  views::View* play_pause_controls_view_for_testing() const;
+
  private:
   // Gets the internal |ui::Layer| of the controls.
   ui::Layer* GetControlsBackgroundLayer();
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index 86f6ffb..54d9829 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -470,7 +470,8 @@
 
       const bool succeeded = canvas->InitPaintFlagsForTiling(
           *tp->GetImageSkiaNamed(bg_id), x, GetContentsBounds().y() + offset_y,
-          x_scale * scale, scale, 0, 0, &flags);
+          x_scale * scale, scale, 0, 0, SkShader::kRepeat_TileMode,
+          SkShader::kRepeat_TileMode, &flags);
       DCHECK(succeeded);
     } else {
       flags.setColor(GetButtonFillColor());
diff --git a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
index f7464ef..217ecad 100644
--- a/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
+++ b/chrome/browser/ui/webui/md_downloads/downloads_list_tracker.cc
@@ -210,7 +210,7 @@
   file_value->SetString("id", base::NumberToString(download_item->GetId()));
 
   base::FilePath download_path(download_item->GetTargetFilePath());
-  file_value->Set("file_path", base::CreateFilePathValue(download_path));
+  file_value->SetKey("file_path", base::CreateFilePathValue(download_path));
   file_value->SetString("file_url",
                         net::FilePathToFileURL(download_path).spec());
 
diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
index e83ded59..4533592 100644
--- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
+++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc
@@ -796,8 +796,8 @@
     profile_value->SetString(kKeyEmailAddress, entry->GetUserName());
     profile_value->SetString(kKeyDisplayName,
                              profiles::GetAvatarNameForProfile(profile_path));
-    profile_value->Set(kKeyProfilePath,
-                       base::CreateFilePathValue(profile_path));
+    profile_value->SetKey(kKeyProfilePath,
+                          base::CreateFilePathValue(profile_path));
     profile_value->SetBoolean(kKeyPublicAccount, false);
     profile_value->SetBoolean(kKeyLegacySupervisedUser,
                               entry->IsLegacySupervised());
diff --git a/chrome/common/custom_handlers/protocol_handler.cc b/chrome/common/custom_handlers/protocol_handler.cc
index e2de8df6..9370aea 100644
--- a/chrome/common/custom_handlers/protocol_handler.cc
+++ b/chrome/common/custom_handlers/protocol_handler.cc
@@ -74,8 +74,8 @@
   auto d = std::make_unique<base::DictionaryValue>();
   d->SetString("protocol", protocol_);
   d->SetString("url", url_.spec());
-  d->Set("last_modified",
-         base::CreateTimeDeltaValue(last_modified_.ToDeltaSinceWindowsEpoch()));
+  d->SetKey("last_modified", base::CreateTimeDeltaValue(
+                                 last_modified_.ToDeltaSinceWindowsEpoch()));
   return d;
 }
 
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 8ee890e..1d76e193 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/web_data_service_factory.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/url_constants.h"
@@ -637,6 +638,12 @@
   return profile_path_;
 }
 
+base::FilePath TestingProfile::GetCachePath() const {
+  base::FilePath cache_path;
+  chrome::GetUserCacheDirectory(profile_path_, &cache_path);
+  return cache_path;
+}
+
 #if !defined(OS_ANDROID)
 std::unique_ptr<content::ZoomLevelDelegate>
 TestingProfile::CreateZoomLevelDelegate(const base::FilePath& partition_path) {
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 9d73150..97ba3f6 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -231,6 +231,7 @@
 
   // content::BrowserContext
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
 #if !defined(OS_ANDROID)
   std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 7b9416a..39db8395 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -80,12 +80,18 @@
     'MobileEmulationCapabilityTest.testClickElement',
     'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabs',
     'MobileEmulationCapabilityTest.testNetworkConnectionTypeIsAppliedToAllTabsImmediately',
+    # Flaky on Win. See http://crbug.com/865842.
+    'ChromeDriverTest.testCanClickInIframes',
+    'ChromeDriverTest.testMoveToElementAndClick'
 ]
 
 _VERSION_SPECIFIC_FILTER = {}
 _VERSION_SPECIFIC_FILTER['HEAD'] = []
 
-_VERSION_SPECIFIC_FILTER['69'] = []
+_VERSION_SPECIFIC_FILTER['69'] = [
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2515
+    'HeadlessInvalidCertificateTest.*',
+]
 
 _VERSION_SPECIFIC_FILTER['68'] = []
 
@@ -108,9 +114,6 @@
     'ChromeDriverTest.testWindowFullScreen',
     # crbug.com/827171
     'ChromeDriverTest.testWindowMinimize',
-    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2515
-    'HeadlessInvalidCertificateTest.testLoadsPage',
-    'HeadlessInvalidCertificateTest.testNavigateNewWindow',
 ]
 
 _DESKTOP_NEGATIVE_FILTER = [
diff --git a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsView.java b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsView.java
index 2be55eb..b178f84e 100644
--- a/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsView.java
+++ b/chromecast/browser/android/apk/src/org/chromium/chromecast/shell/CastWebContentsView.java
@@ -49,8 +49,8 @@
 
             ContentView contentView = ContentView.createContentView(context, webContents);
             // TODO(derekjchow): productVersion
-            webContents.initialize(context, "",
-                    ViewAndroidDelegate.createBasicDelegate(contentView), contentView, window);
+            webContents.initialize("", ViewAndroidDelegate.createBasicDelegate(contentView),
+                    contentView, window, WebContents.createDefaultInternalsHolder());
 
             // Enable display of current webContents.
             webContents.onShow();
@@ -73,8 +73,8 @@
             WindowAndroid window = new WindowAndroid(context);
             ContentView contentView = ContentView.createContentView(context, webContents);
             // TODO(derekjchow): productVersion
-            webContents.initialize(context, "",
-                    ViewAndroidDelegate.createBasicDelegate(contentView), contentView, window);
+            webContents.initialize("", ViewAndroidDelegate.createBasicDelegate(contentView),
+                    contentView, window, WebContents.createDefaultInternalsHolder());
             // Enable display of current webContents.
             webContents.onShow();
             return webContents::onHide;
diff --git a/chromecast/browser/cast_browser_context.cc b/chromecast/browser/cast_browser_context.cc
index bec7475ac..0322f118 100644
--- a/chromecast/browser/cast_browser_context.cc
+++ b/chromecast/browser/cast_browser_context.cc
@@ -94,6 +94,10 @@
   return path_;
 }
 
+base::FilePath CastBrowserContext::GetCachePath() const {
+  return base::FilePath();
+}
+
 bool CastBrowserContext::IsOffTheRecord() const {
   return false;
 }
diff --git a/chromecast/browser/cast_browser_context.h b/chromecast/browser/cast_browser_context.h
index 13c4bbf..16ea170c 100644
--- a/chromecast/browser/cast_browser_context.h
+++ b/chromecast/browser/cast_browser_context.h
@@ -30,6 +30,7 @@
       const base::FilePath& partition_path) override;
 #endif  // !defined(OS_ANDROID)
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
   bool IsOffTheRecord() const override;
   content::ResourceContext* GetResourceContext() override;
   content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
diff --git a/chromeos/dbus/services/chrome_features_service_provider.cc b/chromeos/dbus/services/chrome_features_service_provider.cc
index c891255..c3ad74f 100644
--- a/chromeos/dbus/services/chrome_features_service_provider.cc
+++ b/chromeos/dbus/services/chrome_features_service_provider.cc
@@ -44,9 +44,13 @@
     dbus::ExportedObject::ResponseSender response_sender) {
   dbus::MessageReader reader(method_call);
   std::string user_id_hash;
-  // TODO(nverne): Make it an error to fail to PopString once callers have been
-  // updated.
-  reader.PopString(&user_id_hash);
+
+  if (!reader.PopString(&user_id_hash)) {
+    LOG(ERROR) << "Failed to pop user_id_hash from incoming message.";
+    response_sender.Run(dbus::ErrorResponse::FromMethodCall(
+        method_call, DBUS_ERROR_INVALID_ARGS, "No user_id_hash string arg"));
+    return;
+  }
 
   std::unique_ptr<dbus::Response> response =
       dbus::Response::FromMethodCall(method_call);
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 45e7fa41..99ac8b25 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -130,6 +130,7 @@
     "//components/rappor:unit_tests",
     "//components/reading_list/core:unit_tests",
     "//components/safe_search_api:unit_tests",
+    "//components/scheduling_metrics:unit_tests",
     "//components/search:unit_tests",
     "//components/search_engines:unit_tests",
     "//components/search_provider_logos:unit_tests",
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 1c4a4555..1abe999 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -198,8 +198,6 @@
     "webdata/autofill_webdata_service_observer.h",
     "webdata/system_encryptor.cc",
     "webdata/system_encryptor.h",
-    "webdata/web_data_model_type_controller.cc",
-    "webdata/web_data_model_type_controller.h",
   ]
 
   if (is_ios) {
@@ -464,6 +462,7 @@
     "webdata/autofill_profile_sync_difference_tracker_unittest.cc",
     "webdata/autofill_profile_syncable_service_unittest.cc",
     "webdata/autofill_table_unittest.cc",
+    "webdata/autofill_wallet_metadata_sync_bridge_unittest.cc",
     "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
     "webdata/autofill_wallet_syncable_service_unittest.cc",
     "webdata/web_data_service_unittest.cc",
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
index f836172c..386506af 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.cc
@@ -17,6 +17,20 @@
 // Address to this variable used as the user data key.
 static int kAutofillWalletMetadataSyncBridgeUserDataKey = 0;
 
+std::string GetClientTagForSpecificsId(
+    sync_pb::WalletMetadataSpecifics::Type type,
+    const std::string& specifics_id) {
+  switch (type) {
+    case sync_pb::WalletMetadataSpecifics::ADDRESS:
+      return "address-" + specifics_id;
+    case sync_pb::WalletMetadataSpecifics::CARD:
+      return "card-" + specifics_id;
+    case sync_pb::WalletMetadataSpecifics::UNKNOWN:
+      NOTREACHED();
+      return "";
+  }
+}
+
 }  // namespace
 
 // static
@@ -81,14 +95,15 @@
 
 std::string AutofillWalletMetadataSyncBridge::GetClientTag(
     const syncer::EntityData& entity_data) {
-  NOTIMPLEMENTED();
-  return "";
+  const sync_pb::WalletMetadataSpecifics& remote_metadata =
+      entity_data.specifics.wallet_metadata();
+  return GetClientTagForSpecificsId(remote_metadata.type(),
+                                    remote_metadata.id());
 }
 
 std::string AutofillWalletMetadataSyncBridge::GetStorageKey(
     const syncer::EntityData& entity_data) {
-  NOTIMPLEMENTED();
-  return "";
+  return entity_data.specifics.wallet_metadata().id();
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
new file mode 100644
index 0000000..93ebf4bd
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge_unittest.cc
@@ -0,0 +1,179 @@
+// 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/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/time/time.h"
+#include "components/autofill/core/browser/country_names.h"
+#include "components/autofill/core/browser/test_autofill_clock.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/sync/base/hash_util.h"
+#include "components/sync/model/entity_data.h"
+#include "components/sync/model/mock_model_type_change_processor.h"
+#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/webdata/common/web_database.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace {
+
+using base::ScopedTempDir;
+using sync_pb::WalletMetadataSpecifics;
+using syncer::EntityData;
+using syncer::EntityDataPtr;
+using syncer::MockModelTypeChangeProcessor;
+using syncer::ModelType;
+
+// Base64 encoded SHA1 hash of all address fields.
+const char kAddressHashA[] = "MgM+9iWXwMGwEpFfDDp06K3jizU=";
+
+// Base64 encoded string (opaque to Chrome; any such string works here).
+const char kCardIdA[] = "AQIDBAECAwQBAgMEAQIDBAECAwQBAgMEAQIDBAECAwQBAgME";
+
+const char kLocaleString[] = "en-US";
+const base::Time kJune2017 = base::Time::FromDoubleT(1497552271);
+
+class FakeAutofillBackend : public AutofillWebDataBackend {
+ public:
+  FakeAutofillBackend() {}
+  ~FakeAutofillBackend() override {}
+  WebDatabase* GetDatabase() override { return db_; }
+  void AddObserver(
+      autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+  }
+  void RemoveObserver(
+      autofill::AutofillWebDataServiceObserverOnDBSequence* observer) override {
+  }
+  void RemoveExpiredFormElements() override {}
+  void NotifyOfMultipleAutofillChanges() override {}
+  void NotifyThatSyncHasStarted(ModelType model_type) override {}
+  void SetWebDatabase(WebDatabase* db) { db_ = db; }
+
+ private:
+  WebDatabase* db_;
+};
+
+WalletMetadataSpecifics CreateWalletMetadataSpecificsForAddress(
+    const std::string& id) {
+  WalletMetadataSpecifics specifics;
+  specifics.set_id(id);
+  specifics.set_type(WalletMetadataSpecifics::ADDRESS);
+  return specifics;
+}
+
+WalletMetadataSpecifics CreateWalletMetadataSpecificsForCard(
+    const std::string& id) {
+  WalletMetadataSpecifics specifics;
+  specifics.set_id(id);
+  specifics.set_type(WalletMetadataSpecifics::CARD);
+  return specifics;
+}
+
+}  // namespace
+
+class AutofillWalletMetadataSyncBridgeTest : public testing::Test {
+ public:
+  AutofillWalletMetadataSyncBridgeTest() {}
+  ~AutofillWalletMetadataSyncBridgeTest() override {}
+
+  void SetUp() override {
+    // Fix a time for implicitly constructed use_dates in AutofillProfile.
+    test_clock_.SetNow(kJune2017);
+    CountryNames::SetLocaleString(kLocaleString);
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    db_.AddTable(&table_);
+    db_.Init(temp_dir_.GetPath().AppendASCII("SyncTestWebDatabase"));
+    backend_.SetWebDatabase(&db_);
+    ResetProcessor();
+    ResetBridge();
+  }
+
+  void ResetProcessor() {
+    real_processor_ =
+        std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+            syncer::AUTOFILL_WALLET_METADATA, /*dump_stack=*/base::DoNothing(),
+            /*commit_only=*/false);
+    mock_processor_.DelegateCallsByDefaultTo(real_processor_.get());
+  }
+
+  void ResetBridge() {
+    bridge_.reset(new AutofillWalletMetadataSyncBridge(
+        mock_processor_.CreateForwardingProcessor()));
+  }
+
+  EntityData SpecificsToEntity(const WalletMetadataSpecifics& specifics) {
+    EntityData data;
+    *data.specifics.mutable_wallet_metadata() = specifics;
+    data.client_tag_hash = syncer::GenerateSyncableHash(
+        syncer::AUTOFILL_WALLET_METADATA, bridge()->GetClientTag(data));
+    return data;
+  }
+
+  AutofillWalletMetadataSyncBridge* bridge() { return bridge_.get(); }
+
+  syncer::MockModelTypeChangeProcessor& mock_processor() {
+    return mock_processor_;
+  }
+
+  AutofillTable* table() { return &table_; }
+
+  FakeAutofillBackend* backend() { return &backend_; }
+
+ private:
+  autofill::TestAutofillClock test_clock_;
+  ScopedTempDir temp_dir_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  FakeAutofillBackend backend_;
+  AutofillTable table_;
+  WebDatabase db_;
+  testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_;
+  std::unique_ptr<syncer::ClientTagBasedModelTypeProcessor> real_processor_;
+  std::unique_ptr<AutofillWalletMetadataSyncBridge> bridge_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutofillWalletMetadataSyncBridgeTest);
+};
+
+// The following 2 tests make sure client tags stay stable.
+TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForAddress) {
+  WalletMetadataSpecifics specifics =
+      CreateWalletMetadataSpecificsForAddress(kAddressHashA);
+  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+            "address-" + std::string(kAddressHashA));
+}
+
+TEST_F(AutofillWalletMetadataSyncBridgeTest, GetClientTagForCard) {
+  WalletMetadataSpecifics specifics =
+      CreateWalletMetadataSpecificsForCard(kCardIdA);
+  EXPECT_EQ(bridge()->GetClientTag(SpecificsToEntity(specifics)),
+            "card-" + std::string(kCardIdA));
+}
+
+// The following 2 tests make sure storage keys stay stable.
+TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForAddress) {
+  WalletMetadataSpecifics specifics1 =
+      CreateWalletMetadataSpecificsForAddress(kAddressHashA);
+  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics1)),
+            kAddressHashA);
+}
+
+TEST_F(AutofillWalletMetadataSyncBridgeTest, GetStorageKeyForCard) {
+  WalletMetadataSpecifics specifics2 =
+      CreateWalletMetadataSpecificsForCard(kCardIdA);
+  EXPECT_EQ(bridge()->GetStorageKey(SpecificsToEntity(specifics2)), kCardIdA);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/web_data_model_type_controller.cc b/components/autofill/core/browser/webdata/web_data_model_type_controller.cc
deleted file mode 100644
index d21981e..0000000
--- a/components/autofill/core/browser/webdata/web_data_model_type_controller.cc
+++ /dev/null
@@ -1,36 +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 "components/autofill/core/browser/webdata/web_data_model_type_controller.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-
-using syncer::ModelType;
-using syncer::ModelTypeController;
-using syncer::SyncClient;
-
-namespace autofill {
-
-WebDataModelTypeController::WebDataModelTypeController(
-    ModelType type,
-    SyncClient* sync_client,
-    const scoped_refptr<base::SingleThreadTaskRunner>& model_thread,
-    const scoped_refptr<AutofillWebDataService>& web_data_service,
-    const DelegateFromWebData& delegate_from_web_data)
-    : ModelTypeController(type, sync_client, model_thread),
-      web_data_service_(web_data_service),
-      delegate_from_web_data_(delegate_from_web_data) {}
-
-WebDataModelTypeController::~WebDataModelTypeController() {}
-
-ModelTypeController::DelegateProvider
-WebDataModelTypeController::GetDelegateProvider() {
-  // As opposed to the default implementation, get the delegate on demand, the
-  // web data service requires us to be on the model thread.
-  return base::Bind(delegate_from_web_data_,
-                    base::RetainedRef(web_data_service_));
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/web_data_model_type_controller.h b/components/autofill/core/browser/webdata/web_data_model_type_controller.h
deleted file mode 100644
index 1a80c1e7..0000000
--- a/components/autofill/core/browser/webdata/web_data_model_type_controller.h
+++ /dev/null
@@ -1,49 +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 COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_WEB_DATA_MODEL_TYPE_CONTROLLER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_WEB_DATA_MODEL_TYPE_CONTROLLER_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/sync/driver/model_type_controller.h"
-
-namespace syncer {
-class ModelTypeControllerDelegate;
-}  // namespace syncer
-
-namespace autofill {
-
-class WebDataModelTypeController : public syncer::ModelTypeController {
- public:
-  using DelegateFromWebData =
-      base::Callback<base::WeakPtr<syncer::ModelTypeControllerDelegate>(
-          AutofillWebDataService*)>;
-
-  WebDataModelTypeController(
-      syncer::ModelType type,
-      syncer::SyncClient* sync_client,
-      const scoped_refptr<base::SingleThreadTaskRunner>& model_thread,
-      const scoped_refptr<AutofillWebDataService>& web_data_service,
-      const DelegateFromWebData& delegate_from_web_data);
-
-  ~WebDataModelTypeController() override;
-
- private:
-  // syncer::ModelTypeController implementation.
-  syncer::ModelTypeController::DelegateProvider GetDelegateProvider() override;
-
-  // A reference to the AutofillWebDataService for this controller.
-  scoped_refptr<AutofillWebDataService> web_data_service_;
-
-  // How to grab the correct delegate from a web data.
-  DelegateFromWebData delegate_from_web_data_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebDataModelTypeController);
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_WEB_DATA_MODEL_TYPE_CONTROLLER_H_
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 3f87705..e76e977f 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -17,7 +17,6 @@
 #include "components/autofill/core/browser/webdata/autofill_wallet_metadata_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/browser/webdata/web_data_model_type_controller.h"
 #include "components/browser_sync/browser_sync_switches.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/dom_distiller/core/dom_distiller_features.h"
@@ -37,6 +36,7 @@
 #include "components/sync/driver/sync_client.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/engine/sync_engine.h"
+#include "components/sync/model_impl/proxy_model_type_controller_delegate.h"
 #include "components/sync_bookmarks/bookmark_change_processor.h"
 #include "components/sync_bookmarks/bookmark_data_type_controller.h"
 #include "components/sync_bookmarks/bookmark_model_associator.h"
@@ -136,28 +136,25 @@
   // TODO(stanisc): can DEVICE_INFO be one of disabled datatypes?
   // Use an error callback that always uploads a stacktrace if it can to help
   // get USS as stable as possible.
-  controllers.push_back(std::make_unique<ModelTypeController>(
-      syncer::DEVICE_INFO, sync_client_, ui_thread_));
+  controllers.push_back(
+      CreateModelTypeControllerForModelRunningOnUIThread(syncer::DEVICE_INFO));
   // These features are enabled only if there's a DB thread to post tasks to.
   if (db_thread_) {
     // Autocomplete sync is enabled by default.  Register unless explicitly
     // disabled.
     if (!disabled_types.Has(syncer::AUTOFILL)) {
-      controllers.push_back(
-          std::make_unique<autofill::WebDataModelTypeController>(
-              syncer::AUTOFILL, sync_client_, db_thread_, web_data_service_,
-              base::BindRepeating(&AutocompleteDelegateFromDataService)));
+      controllers.push_back(CreateWebDataModelTypeController(
+          syncer::AUTOFILL,
+          base::BindRepeating(&AutocompleteDelegateFromDataService)));
     }
 
     // Autofill sync is enabled by default.  Register unless explicitly
     // disabled.
     if (!disabled_types.Has(syncer::AUTOFILL_PROFILE)) {
       if (FeatureList::IsEnabled(switches::kSyncUSSAutofillProfile)) {
-        controllers.push_back(
-            std::make_unique<autofill::WebDataModelTypeController>(
-                syncer::AUTOFILL_PROFILE, sync_client_, db_thread_,
-                web_data_service_,
-                base::BindRepeating(&AutofillProfileDelegateFromDataService)));
+        controllers.push_back(CreateWebDataModelTypeController(
+            syncer::AUTOFILL_PROFILE,
+            base::BindRepeating(&AutofillProfileDelegateFromDataService)));
       } else {
         controllers.push_back(
             std::make_unique<AutofillProfileDataTypeController>(
@@ -170,11 +167,9 @@
     bool wallet_disabled = disabled_types.Has(syncer::AUTOFILL_WALLET_DATA);
     if (!wallet_disabled) {
       if (base::FeatureList::IsEnabled(switches::kSyncUSSAutofillWalletData)) {
-        controllers.push_back(
-            std::make_unique<autofill::WebDataModelTypeController>(
-                syncer::AUTOFILL_WALLET_DATA, sync_client_, db_thread_,
-                web_data_service_,
-                base::BindRepeating(&AutofillWalletDelegateFromDataService)));
+        controllers.push_back(CreateWebDataModelTypeController(
+            syncer::AUTOFILL_WALLET_DATA,
+            base::BindRepeating(&AutofillWalletDelegateFromDataService)));
       } else {
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
@@ -189,12 +184,10 @@
         !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
       if (base::FeatureList::IsEnabled(
               switches::kSyncUSSAutofillWalletMetadata)) {
-        controllers.push_back(
-            std::make_unique<autofill::WebDataModelTypeController>(
-                syncer::AUTOFILL_WALLET_METADATA, sync_client_, db_thread_,
-                web_data_service_,
-                base::BindRepeating(
-                    &AutofillWalletMetadataDelegateFromDataService)));
+        controllers.push_back(CreateWebDataModelTypeController(
+            syncer::AUTOFILL_WALLET_METADATA,
+            base::BindRepeating(
+                &AutofillWalletMetadataDelegateFromDataService)));
       } else {
         controllers.push_back(
             std::make_unique<AutofillWalletDataTypeController>(
@@ -208,8 +201,8 @@
   // disabled.
   if (!disabled_types.Has(syncer::BOOKMARKS)) {
     if (FeatureList::IsEnabled(switches::kSyncUSSBookmarks)) {
-      controllers.push_back(std::make_unique<ModelTypeController>(
-          syncer::BOOKMARKS, sync_client_, ui_thread_));
+      controllers.push_back(CreateModelTypeControllerForModelRunningOnUIThread(
+          syncer::BOOKMARKS));
     } else {
       controllers.push_back(std::make_unique<BookmarkDataTypeController>(
           error_callback, sync_client_));
@@ -221,6 +214,8 @@
     // TypedUrl sync is enabled by default.  Register unless explicitly
     // disabled.
     if (!disabled_types.Has(syncer::TYPED_URLS)) {
+      // TypedURLModelTypeController uses a proxy delegate internally, as
+      // provided by HistoryService.
       controllers.push_back(
           std::make_unique<history::TypedURLModelTypeController>(
               sync_client_, history_disabled_pref_));
@@ -242,7 +237,13 @@
       if (FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
         controllers.push_back(
             std::make_unique<sync_sessions::SessionModelTypeController>(
-                sync_client_, ui_thread_, history_disabled_pref_));
+                sync_client_,
+                std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+                    ui_thread_,
+                    base::BindRepeating(
+                        &syncer::SyncClient::GetControllerDelegateForModelType,
+                        base::Unretained(sync_client_), syncer::SESSIONS)),
+                history_disabled_pref_));
       } else {
         controllers.push_back(std::make_unique<SessionDataTypeController>(
             error_callback, sync_client_, local_device_info_provider,
@@ -277,8 +278,8 @@
           syncer::PREFERENCES, error_callback, sync_client_, syncer::GROUP_UI,
           ui_thread_));
     } else {
-      controllers.push_back(std::make_unique<ModelTypeController>(
-          syncer::PREFERENCES, sync_client_, ui_thread_));
+      controllers.push_back(CreateModelTypeControllerForModelRunningOnUIThread(
+          syncer::PREFERENCES));
     }
   }
 
@@ -290,8 +291,8 @@
 
 #if defined(OS_CHROMEOS)
   if (!disabled_types.Has(syncer::PRINTERS)) {
-    controllers.push_back(std::make_unique<ModelTypeController>(
-        syncer::PRINTERS, sync_client_, ui_thread_));
+    controllers.push_back(
+        CreateModelTypeControllerForModelRunningOnUIThread(syncer::PRINTERS));
   }
 #endif
 
@@ -299,19 +300,19 @@
   // Reading List or Reading List Sync is explicitly disabled.
   if (!disabled_types.Has(syncer::READING_LIST) &&
       reading_list::switches::IsReadingListEnabled()) {
-    controllers.push_back(std::make_unique<ModelTypeController>(
-        syncer::READING_LIST, sync_client_, ui_thread_));
+    controllers.push_back(CreateModelTypeControllerForModelRunningOnUIThread(
+        syncer::READING_LIST));
   }
 
   if (!disabled_types.Has(syncer::USER_EVENTS) &&
       FeatureList::IsEnabled(switches::kSyncUserEvents)) {
-    controllers.push_back(std::make_unique<ModelTypeController>(
-        syncer::USER_EVENTS, sync_client_, ui_thread_));
+    controllers.push_back(CreateModelTypeControllerForModelRunningOnUIThread(
+        syncer::USER_EVENTS));
   }
 
   if (base::FeatureList::IsEnabled(switches::kSyncUserConsentSeparateType)) {
-    controllers.push_back(std::make_unique<ModelTypeController>(
-        syncer::USER_CONSENTS, sync_client_, ui_thread_));
+    controllers.push_back(CreateModelTypeControllerForModelRunningOnUIThread(
+        syncer::USER_CONSENTS));
   }
 
   return controllers;
@@ -379,4 +380,33 @@
 bool ProfileSyncComponentsFactoryImpl::
     override_prefs_controller_to_uss_for_test_ = false;
 
+std::unique_ptr<ModelTypeController> ProfileSyncComponentsFactoryImpl::
+    CreateModelTypeControllerForModelRunningOnUIThread(syncer::ModelType type) {
+  // TODO(crbug.com/867801): Replace the proxy delegate below with a simpler
+  // forwarding delegate that involves no posting of tasks.
+  return std::make_unique<ModelTypeController>(
+      type,
+      std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+          ui_thread_,
+          base::BindRepeating(
+              &syncer::SyncClient::GetControllerDelegateForModelType,
+              base::Unretained(sync_client_), type)),
+      sync_client_);
+}
+
+std::unique_ptr<ModelTypeController>
+ProfileSyncComponentsFactoryImpl::CreateWebDataModelTypeController(
+    syncer::ModelType type,
+    const base::RepeatingCallback<
+        base::WeakPtr<syncer::ModelTypeControllerDelegate>(
+            autofill::AutofillWebDataService*)>& delegate_from_web_data) {
+  return std::make_unique<ModelTypeController>(
+      type,
+      std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+          db_thread_,
+          base::BindRepeating(delegate_from_web_data,
+                              base::RetainedRef(web_data_service_))),
+      sync_client_);
+}
+
 }  // namespace browser_sync
diff --git a/components/browser_sync/profile_sync_components_factory_impl.h b/components/browser_sync/profile_sync_components_factory_impl.h
index acac43bb6..bf452bc 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/components/browser_sync/profile_sync_components_factory_impl.h
@@ -16,6 +16,8 @@
 #include "components/version_info/version_info.h"
 
 namespace syncer {
+class ModelTypeController;
+class ModelTypeControllerDelegate;
 class SyncClient;
 }
 
@@ -71,6 +73,20 @@
   static void OverridePrefsForUssTest(bool use_uss);
 
  private:
+  // Factory function for ModelTypeController instances for models living on
+  // |ui_thread_|.
+  std::unique_ptr<syncer::ModelTypeController>
+  CreateModelTypeControllerForModelRunningOnUIThread(syncer::ModelType type);
+
+  // Factory function for ModelTypeController instnaces for autofill-related
+  // datatypes, which live in |db_thread_| and have a delegate accesible via
+  // AutofillWebDataService.
+  std::unique_ptr<syncer::ModelTypeController> CreateWebDataModelTypeController(
+      syncer::ModelType type,
+      const base::RepeatingCallback<
+          base::WeakPtr<syncer::ModelTypeControllerDelegate>(
+              autofill::AutofillWebDataService*)>& delegate_from_web_data);
+
   // Client/platform specific members.
   syncer::SyncClient* const sync_client_;
   const version_info::Channel channel_;
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 5fe883f3..6f34751 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -205,6 +205,10 @@
   DCHECK(signin_scoped_device_id_callback_);
   DCHECK(sync_client_);
 
+  // If Sync is disabled via command line flag, then ProfileSyncService
+  // shouldn't be instantiated.
+  DCHECK(IsSyncAllowedByFlag());
+
   ResetCryptoState();
 
   std::string last_version = sync_prefs_.GetLastRunVersion();
@@ -731,8 +735,12 @@
 int ProfileSyncService::GetDisableReasons() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  // If Sync is disabled via command line flag, then ProfileSyncService
+  // shouldn't even be instantiated.
+  DCHECK(IsSyncAllowedByFlag());
+
   int result = DISABLE_REASON_NONE;
-  if (!IsSyncAllowedByFlag() || !IsSyncAllowedByPlatform()) {
+  if (!IsSyncAllowedByPlatform()) {
     result = result | DISABLE_REASON_PLATFORM_OVERRIDE;
   }
   if (sync_prefs_.IsManaged() || sync_disabled_by_admin_) {
@@ -2156,7 +2164,7 @@
        type_it.Good(); type_it.Inc()) {
     auto dtc_it = data_type_controllers_.find(type_it.Get());
     if (dtc_it != data_type_controllers_.end())
-      dtc_it->second->RecordMemoryUsageHistogram();
+      dtc_it->second->RecordMemoryUsageAndCountsHistograms();
   }
 }
 
diff --git a/components/cdm/browser/media_drm_storage_impl.cc b/components/cdm/browser/media_drm_storage_impl.cc
index b1caa86a..480e3e1 100644
--- a/components/cdm/browser/media_drm_storage_impl.cc
+++ b/components/cdm/browser/media_drm_storage_impl.cc
@@ -98,8 +98,7 @@
   base::Value ToDictValue() const {
     base::Value dict(base::Value::Type::DICTIONARY);
 
-    dict.SetKey(kOriginId, base::Value::FromUniquePtrValue(
-                               base::CreateUnguessableTokenValue(origin_id_)));
+    dict.SetKey(kOriginId, base::CreateUnguessableTokenValue(origin_id_));
     dict.SetKey(kCreationTime, base::Value(provision_time_.ToDoubleT()));
 
     return dict;
diff --git a/components/chrome_apps/webstore_widget/app/main.css b/components/chrome_apps/webstore_widget/app/main.css
index 4b0ac29a..4f3466d7 100644
--- a/components/chrome_apps/webstore_widget/app/main.css
+++ b/components/chrome_apps/webstore_widget/app/main.css
@@ -16,7 +16,7 @@
 }
 
 .window-title {
-  -webkit-margin-start: 20px;
   flex: 1;
   line-height: 48px;
+  margin-inline-start: 20px;
 }
diff --git a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.css b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.css
index 218a4dd3..9de8191 100644
--- a/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.css
+++ b/components/chrome_apps/webstore_widget/cws_widget/cws_widget_container.css
@@ -47,24 +47,24 @@
 }
 
 .cws-widget-webstore-button {
-  -webkit-padding-end: 10px;
-  -webkit-padding-start: 12px;
   color: #00f;
   cursor: pointer;
   display: flex;
   height: 16px;
   padding-bottom: 10px;
+  padding-inline-end: 10px;
+  padding-inline-start: 12px;
   padding-top: 10px;
 }
 
 .cws-widget-webstore-button-icon {
-  -webkit-margin-end: 8px;
   background-image: -webkit-image-set(
     url(chrome://theme/IDR_WEBSTORE_ICON_16) 1x,
     url(chrome://theme/IDR_WEBSTORE_ICON_16@2x) 2x);
   background-repeat: no-repeat;
   display: inline-block;
   height: 16px;
+  margin-inline-end: 8px;
   width: 16px;
 }
 
diff --git a/components/contextual_search/README b/components/contextual_search/README
deleted file mode 100644
index a3dc3f3..0000000
--- a/components/contextual_search/README
+++ /dev/null
@@ -1,8 +0,0 @@
-The Contextual Search component provides renderer support for an overlay panel
-with an API that peeks up from the bottom of the host page.
-
-This component communicates via mojo from the renderer to the browser and vice
-versa.
-
-Eventually we may reuse some of this code for other overlay panels, including
-DOM Distiller (which is currently in a separate component).
diff --git a/components/contextual_search/README.md b/components/contextual_search/README.md
new file mode 100644
index 0000000..5302ac88
--- /dev/null
+++ b/components/contextual_search/README.md
@@ -0,0 +1,42 @@
+# Contextual Search Component
+
+The Contextual Search component implements some platform agnostic services that
+mediate between the main CS implementation in the Browser and some other parts
+of the system.  These include the JS API service to allow communication from
+the Overlay to CS, and user-interaction aggregation.
+
+## JS API Service
+
+The JS API Service allows JavaScript in the Overlay Panel to call into
+Contextual Search.  This is done by providing an entry point at
+chrome.contextualSearch when the Contextual Search Overlay Panel is active.
+
+Enabling this API is somewhat complicated in order to make sure that the API
+only exists for a Renderer created by CS for the Overlay:
+
+1. Whenever a Renderer is created, an OverlayJsRenderFrameObserver is created.
+   This class is at the heart of the connection between the Renderer, CS, JS
+   and the JavaScript API.
+2. An OverlayJsRenderFrameObserver is created for every renderer to check if
+   it's a CS Overlay Panel.  When the renderer starts up it asks Contextual
+   Search if the current URL belongs to its overlay panel, and if it does then
+   the JS API is enabled for that renderer to allow it to accept JS messages
+   from the page.
+3. When the OverlayJsRenderFrameObserver gets the response in #2 it creates a
+   ContextualSearchWrapper object that allows injecting JavaScript into the
+   WebFrame.
+4. When some JS in a page wants to call into Chrome it simply accesses methods
+   in the chrome.contextualSearch API.  If the page is being presented in the
+   Overlay Panel for CS then that object will exist with native method
+   implementations.  The renderer forwards the API request to the browser for
+   processing.
+
+The above interaction is used by the Translate onebox to allow showing a
+translation in the caption of the Contextual Search Bar, and to provide control
+of the position of the Overlay.
+
+## User Interaction Aggregation
+
+The CtrAggregator and WeeklyActivityStorage classes are used aggregate user
+actions on a weekly basis for use in machine learning for improved triggering.
+
diff --git a/components/contextual_search/browser/contextual_search_js_api_handler.h b/components/contextual_search/browser/contextual_search_js_api_handler.h
index a45a78c..6a3642c 100644
--- a/components/contextual_search/browser/contextual_search_js_api_handler.h
+++ b/components/contextual_search/browser/contextual_search_js_api_handler.h
@@ -22,8 +22,8 @@
   // Enabling API, determines if the JS API should be enabled for the given URL.
   virtual void ShouldEnableJsApi(
       const GURL& gurl,
-      contextual_search::mojom::ContextualSearchJsApiService::
-          ShouldEnableJsApiCallback callback) = 0;
+      mojom::ContextualSearchJsApiService::ShouldEnableJsApiCallback
+          callback) = 0;
 
   //=======
   // JS API
@@ -32,7 +32,12 @@
   // Set the caption in the Contextual Search Bar, and indicate whether
   // the caption provides an answer (such as an actual definition), rather than
   // just general notification of what kind of answer may be available.
-  virtual void SetCaption(std::string caption, bool does_answer) = 0;
+  virtual void SetCaption(const std::string& caption, bool does_answer) = 0;
+
+  // Changes the Overlay position to the desired position.
+  // The panel cannot be set to any opened position if it's not already opened.
+  virtual void ChangeOverlayPosition(
+      mojom::OverlayPosition desired_position) = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ContextualSearchJsApiHandler);
diff --git a/components/contextual_search/browser/contextual_search_js_api_service_impl.cc b/components/contextual_search/browser/contextual_search_js_api_service_impl.cc
index 9dc6a06..dfc9531 100644
--- a/components/contextual_search/browser/contextual_search_js_api_service_impl.cc
+++ b/components/contextual_search/browser/contextual_search_js_api_service_impl.cc
@@ -20,8 +20,7 @@
 
 void ContextualSearchJsApiServiceImpl::ShouldEnableJsApi(
     const GURL& gurl,
-    contextual_search::mojom::ContextualSearchJsApiService::
-        ShouldEnableJsApiCallback callback) {
+    mojom::ContextualSearchJsApiService::ShouldEnableJsApiCallback callback) {
   contextual_search_js_api_handler_->ShouldEnableJsApi(gurl,
                                                        std::move(callback));
 }
@@ -32,6 +31,11 @@
   contextual_search_js_api_handler_->SetCaption(caption, does_answer);
 }
 
+void ContextualSearchJsApiServiceImpl::HandleChangeOverlayPosition(
+    mojom::OverlayPosition desired_position) {
+  contextual_search_js_api_handler_->ChangeOverlayPosition(desired_position);
+}
+
 // static
 void CreateContextualSearchJsApiService(
     ContextualSearchJsApiHandler* contextual_search_js_api_handler,
diff --git a/components/contextual_search/browser/contextual_search_js_api_service_impl.h b/components/contextual_search/browser/contextual_search_js_api_service_impl.h
index fbf1fe8..ed3cc5d 100644
--- a/components/contextual_search/browser/contextual_search_js_api_service_impl.h
+++ b/components/contextual_search/browser/contextual_search_js_api_service_impl.h
@@ -12,6 +12,7 @@
 namespace contextual_search {
 
 // This is the receiving end of Contextual Search JavaScript API calls.
+// TODO(donnd): Move this to java.  See https://crbug.com/866972.
 class ContextualSearchJsApiServiceImpl
     : public mojom::ContextualSearchJsApiService {
  public:
@@ -24,13 +25,19 @@
   // The given |callback| will be notified with the answer.
   void ShouldEnableJsApi(
       const GURL& gurl,
-      contextual_search::mojom::ContextualSearchJsApiService::
-          ShouldEnableJsApiCallback callback) override;
+      mojom::ContextualSearchJsApiService::ShouldEnableJsApiCallback callback)
+      override;
 
   // Handles a JavaScript call to set the caption in the Bar to
   // the given |message|.
   void HandleSetCaption(const std::string& message, bool does_answer) override;
 
+  // Handles a JavaScript call to change the Overlay position.
+  // The panel cannot be changed to any opened position if it's not already
+  // opened.
+  void HandleChangeOverlayPosition(
+      mojom::OverlayPosition desired_position) override;
+
  private:
   // The UI handler for calls through the JavaScript API.
   ContextualSearchJsApiHandler* contextual_search_js_api_handler_;
diff --git a/components/contextual_search/common/contextual_search_js_api_service.mojom b/components/contextual_search/common/contextual_search_js_api_service.mojom
index 34841f75..5a252173 100644
--- a/components/contextual_search/common/contextual_search_js_api_service.mojom
+++ b/components/contextual_search/common/contextual_search_js_api_service.mojom
@@ -6,16 +6,39 @@
 
 import "url/mojom/url.mojom";
 
+ // Possible positions for the Overlay Panel.
+enum OverlayPosition {
+  // Not visible.
+  kClose,
+  // Visible only as a Bar peeking up from the bottom.
+  kPeek,
+  // Content is partially visible and partially offscreen.
+  kExpand,
+  // Content is fully visible.
+  kMaximize,
+};
+
 // This service is implemented by the browser process and is used by the
 // renderer when a Contextual Search JavaScript API function is called.
+// When a renderer wants to know if the CS JS API should be enabled it calls the
+// first method.  All the other methods are available to JavaScript at
+// chrome.contextualSearch only when the first method returns true, indicating
+// that the panel belongs to Contextual Search.  More details are in the
+// README.md file in this component.
 interface ContextualSearchJsApiService {
 
   // Determines if this JavaScript API should be enabled for the given URL.
   // The asynchronous callback will be notified with the answer.
+  // TODO(donnd): Consider changing the messaging direction to be from browser
+  // to renderer.  See https://crbug.com/866976.
   ShouldEnableJsApi(url.mojom.Url url) => (bool should_enable);
 
   // Handle a call from the JS API to set the caption, and indicate whether
   // the caption provides an answer (such as an actual definition), rather than
   // just general notification of what kind of answer may be available.
   HandleSetCaption(string message, bool does_answer);
+
+  // Called by JavaScript to change the Overlay position. The panel cannot be
+  // changed to any opened position if it's not already opened.
+  HandleChangeOverlayPosition(OverlayPosition desired_position);
 };
diff --git a/components/contextual_search/renderer/contextual_search_wrapper.cc b/components/contextual_search/renderer/contextual_search_wrapper.cc
index 9d00942f..bdce3855 100644
--- a/components/contextual_search/renderer/contextual_search_wrapper.cc
+++ b/components/contextual_search/renderer/contextual_search_wrapper.cc
@@ -19,6 +19,7 @@
 
 static const char kContextualSearchObjectName[] = "contextualSearch";
 static const char kSetCaptionMethodName[] = "setCaption";
+static const char kChangeOverlayPositionMethodName[] = "changeOverlayPosition";
 
 }  // namespace
 
@@ -66,7 +67,9 @@
     v8::Isolate* isolate) {
   return gin::Wrappable<ContextualSearchWrapper>::GetObjectTemplateBuilder(
              isolate)
-      .SetMethod(kSetCaptionMethodName, &ContextualSearchWrapper::SetCaption);
+      .SetMethod(kSetCaptionMethodName, &ContextualSearchWrapper::SetCaption)
+      .SetMethod(kChangeOverlayPositionMethodName,
+                 &ContextualSearchWrapper::ChangeOverlayPosition);
 }
 
 bool ContextualSearchWrapper::EnsureServiceConnected() {
@@ -88,4 +91,12 @@
   }
 }
 
+void ContextualSearchWrapper::ChangeOverlayPosition(
+    unsigned int desired_position) {
+  if (EnsureServiceConnected()) {
+    contextual_search_js_api_service_->HandleChangeOverlayPosition(
+        static_cast<mojom::OverlayPosition>(desired_position));
+  }
+}
+
 }  // namespace contextual_search
diff --git a/components/contextual_search/renderer/contextual_search_wrapper.h b/components/contextual_search/renderer/contextual_search_wrapper.h
index 23162f2..06c2377 100644
--- a/components/contextual_search/renderer/contextual_search_wrapper.h
+++ b/components/contextual_search/renderer/contextual_search_wrapper.h
@@ -46,6 +46,11 @@
   // just general notification of what kind of answer may be available.
   void SetCaption(const std::string& caption, bool does_answer);
 
+  // Called by JavaScript to change the Overlay position.
+  // The panel cannot be changed to any opened position if it's not already
+  // opened.
+  void ChangeOverlayPosition(unsigned int desired_position);
+
   // Helper function to ensure that this class has connected to the API service.
   // Returns false if cannot connect.
   bool EnsureServiceConnected();
diff --git a/components/contextual_search/renderer/overlay_js_render_frame_observer.h b/components/contextual_search/renderer/overlay_js_render_frame_observer.h
index 53cc1ca..4755ee7 100644
--- a/components/contextual_search/renderer/overlay_js_render_frame_observer.h
+++ b/components/contextual_search/renderer/overlay_js_render_frame_observer.h
@@ -45,7 +45,7 @@
   mojom::ContextualSearchJsApiServicePtr contextual_search_js_api_service_;
 
   // Remembers whether we did start enabling the JS API by making a request
-  // to the Contextaual Search service to ask if we should enable for this
+  // to the Contextual Search service to ask if we should enable for this
   // URL or not.
   bool did_start_enabling_js_api_ = false;
 
diff --git a/components/crash/core/browser/resources/crashes.css b/components/crash/core/browser/resources/crashes.css
index ff158e14..05687c1 100644
--- a/components/crash/core/browser/resources/crashes.css
+++ b/components/crash/core/browser/resources/crashes.css
@@ -7,7 +7,6 @@
 }
 
 h1 {
-  -webkit-padding-start: 75px;
   background-image: url(../../../../resources/sadtab.svg);
   background-position: left;
   background-repeat: no-repeat;
@@ -15,6 +14,7 @@
   font-weight: bold;
   margin: 0;
   padding-bottom: 20px;
+  padding-inline-start: 75px;
   padding-top: 20px;
 }
 
diff --git a/components/flags_ui/resources/flags.css b/components/flags_ui/resources/flags.css
index b068942..8ab2de8 100644
--- a/components/flags_ui/resources/flags.css
+++ b/components/flags_ui/resources/flags.css
@@ -101,7 +101,7 @@
 }
 
 .search-container {
-  -webkit-margin-end: 8px;
+  margin-inline-end: 8px;
   position: relative;
 }
 
@@ -199,9 +199,9 @@
 }
 
 .experiment .flex-container .flex:first-child {
-  -webkit-padding-end: 8px;
   box-sizing: border-box;
   max-width: 540px;
+  padding-inline-end: 8px;
 }
 
 [dir='rtl'] .experiment .flex-container .flex:first-child  {
@@ -224,13 +224,13 @@
 }
 
 .experiment-switched .experiment-name::before {
-  -webkit-margin-end: 4px;
-  -webkit-margin-start: -20px;
   color: var(--google-blue-500);
   content: '•';
   display: inline-block;
   font-size: 40px;
   line-height: 0;
+  margin-inline-end: 4px;
+  margin-inline-start: -20px;
   vertical-align: middle;
   width: 16px;
 }
@@ -242,8 +242,8 @@
 }
 
 .experiment-actions {
-  -webkit-padding-start: 5px;
   flex: 0 0 auto;
+  padding-inline-start: 5px;
   text-align: right;
   width: 150px;
 }
@@ -345,7 +345,7 @@
 }
 
 .tabs li:nth-child(2) .tab-content {
-  -webkit-margin-start: -100%;
+  margin-inline-start: -100%;
 }
 
 .selected .tab-content {
@@ -518,7 +518,7 @@
 
 @media (max-width: 732px) {
   .experiment-switched .experiment-name::before {
-    -webkit-margin-start: 0;
+    margin-inline-start: 0;
   }
 
   #flagsTemplate {
diff --git a/components/history/core/browser/browsing_history_service.cc b/components/history/core/browser/browsing_history_service.cc
index 3221b84..7371ab1 100644
--- a/components/history/core/browser/browsing_history_service.cc
+++ b/components/history/core/browser/browsing_history_service.cc
@@ -24,6 +24,7 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/sync/driver/sync_service.h"
 #include "components/sync/driver/sync_service_observer.h"
+#include "components/sync/protocol/history_delete_directive_specifics.pb.h"
 
 namespace history {
 
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 0bfa6b96..6e54197 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -1131,8 +1131,11 @@
     db_->GetVisitsForURL(result->row.id(), &result->visits);
 }
 
-TypedURLSyncBridge* HistoryBackend::GetTypedURLSyncBridge() const {
-  return typed_url_sync_bridge_.get();
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+HistoryBackend::GetTypedURLSyncControllerDelegate() {
+  DCHECK(typed_url_sync_bridge_);
+  return typed_url_sync_bridge_->change_processor()
+      ->GetControllerDelegateOnUIThread();
 }
 
 // Statistics ------------------------------------------------------------------
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index 80fcd56..8439788 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -45,6 +45,10 @@
 class SingleThreadTaskRunner;
 }
 
+namespace syncer {
+class ModelTypeControllerDelegate;
+}
+
 namespace history {
 struct DownloadRow;
 class HistoryBackendClient;
@@ -415,9 +419,10 @@
 
   bool GetURLByID(URLID url_id, URLRow* url_row);
 
-  // Returns the sync bridge for syncing typed urls. The returned service
-  // is owned by |this| object.
-  TypedURLSyncBridge* GetTypedURLSyncBridge() const;
+  // Returns the sync controller delegate for syncing typed urls. The returned
+  // delegate is owned by |this| object.
+  base::WeakPtr<syncer::ModelTypeControllerDelegate>
+  GetTypedURLSyncControllerDelegate();
 
   // Deleting ------------------------------------------------------------------
 
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index 4d58f7c..f51e820 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -3843,7 +3843,6 @@
 // test for https://crbug.com/796138)
 TEST_F(HistoryBackendTest, DatabaseError) {
   backend_->SetTypedURLSyncBridgeForTest(nullptr);
-  EXPECT_EQ(nullptr, backend_->GetTypedURLSyncBridge());
   backend_->DatabaseErrorCallback(SQLITE_CORRUPT, nullptr);
   // Run loop to let any posted callbacks run before TearDown().
   base::RunLoop().RunUntilIdle();
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index 2f4975b2..6f48ce8 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -51,6 +51,7 @@
 #include "components/history/core/browser/web_history_service.h"
 #include "components/history/core/common/thumbnail_score.h"
 #include "components/sync/model/sync_error_factory.h"
+#include "components/sync/model_impl/proxy_model_type_controller_delegate.h"
 #include "components/variations/variations_associated_data.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/page_transition_types.h"
@@ -231,10 +232,6 @@
   return in_memory_backend_ ? in_memory_backend_->db() : nullptr;
 }
 
-TypedURLSyncBridge* HistoryService::GetTypedURLSyncBridge() const {
-  return history_backend_->GetTypedURLSyncBridge();
-}
-
 void HistoryService::Shutdown() {
   DCHECK(thread_checker_.CalledOnValidThread());
   Cleanup();
@@ -996,6 +993,11 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   CHECK(backend_task_runner_);
   // TODO(brettw): Do prioritization.
+  // NOTE(mastiz): If this implementation changes, be cautious with implications
+  // for sync, because a) the sync engine (sync thread) post tasks directly to
+  // the task runner via ModelTypeProcessorProxy (which is subtle); and b)
+  // ProfileSyncService (UI thread) does the same via
+  // ProxyModelTypeControllerDelegate.
   backend_task_runner_->PostTask(FROM_HERE, std::move(task));
 }
 
@@ -1037,6 +1039,18 @@
   return syncer::SyncError();
 }
 
+std::unique_ptr<syncer::ModelTypeControllerDelegate>
+HistoryService::GetTypedURLSyncControllerDelegate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // Note that a callback is bound for GetTypedURLSyncControllerDelegate()
+  // because this getter itself must also run in the backend sequence, and the
+  // proxy object below will take care of that.
+  return std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
+      backend_task_runner_,
+      base::BindRepeating(&HistoryBackend::GetTypedURLSyncControllerDelegate,
+                          base::Unretained(history_backend_.get())));
+}
+
 syncer::SyncError HistoryService::ProcessLocalDeleteDirective(
     const sync_pb::HistoryDeleteDirectiveSpecifics& delete_directive) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 41d8aed1..41749a9 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -35,7 +35,6 @@
 #include "components/history/core/browser/delete_directive_handler.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/keyword_id.h"
-#include "components/history/core/browser/typed_url_sync_bridge.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/sync/model/syncable_service.h"
 #include "sql/init_status.h"
@@ -58,6 +57,10 @@
 class FaviconServiceImpl;
 }
 
+namespace syncer {
+class ModelTypeControllerDelegate;
+}
+
 namespace history {
 
 struct DownloadRow;
@@ -131,11 +134,6 @@
   // They return false if database is not available (e.g. not loaded yet) or the
   // URL does not exist.
 
-  // Returns a pointer to the TypedURLSyncBridge owned by HistoryBackend.
-  // This method should only be called from the history thread, because the
-  // returned bridge is intended to be accessed only via the history thread.
-  TypedURLSyncBridge* GetTypedURLSyncBridge() const;
-
   // KeyedService:
   void Shutdown() override;
 
@@ -545,6 +543,11 @@
       const base::Location& from_here,
       const syncer::SyncChangeList& change_list) override;
 
+  // For sync codebase only: instantiates a controller delegate to interact with
+  // TypedURLSyncBridge. Must be called from the UI thread.
+  std::unique_ptr<syncer::ModelTypeControllerDelegate>
+  GetTypedURLSyncControllerDelegate();
+
  protected:
   // These are not currently used, hopefully we can do something in the future
   // to ensure that the most important things happen first.
diff --git a/components/history/core/browser/typed_url_model_type_controller.cc b/components/history/core/browser/typed_url_model_type_controller.cc
index f7d482a8..500881f7 100644
--- a/components/history/core/browser/typed_url_model_type_controller.cc
+++ b/components/history/core/browser/typed_url_model_type_controller.cc
@@ -4,60 +4,39 @@
 
 #include "components/history/core/browser/typed_url_model_type_controller.h"
 
+#include <memory>
+
 #include "base/bind.h"
-#include "components/history/core/browser/history_backend.h"
-#include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/prefs/pref_service.h"
 #include "components/sync/driver/model_type_controller.h"
 #include "components/sync/driver/sync_client.h"
-#include "components/sync/model/model_type_controller_delegate.h"
 
-using syncer::ModelType;
-using syncer::ModelTypeController;
-using syncer::ModelTypeControllerDelegate;
 using syncer::SyncClient;
 
 namespace history {
 
 namespace {
 
-// The history service exposes a special non-standard task API which calls back
-// once a task has been dispatched, so we have to build a special wrapper around
-// the tasks we want to run.
-class RunTaskOnHistoryThread : public HistoryDBTask {
- public:
-  explicit RunTaskOnHistoryThread(ModelTypeController::ModelTask task)
-      : task_(std::move(task)) {}
-
-  bool RunOnDBThread(HistoryBackend* backend, HistoryDatabase* db) override {
-    // Invoke the task, then free it immediately so we don't keep a reference
-    // around all the way until DoneRunOnMainThread() is invoked back on the
-    // main thread - we want to release references as soon as possible to avoid
-    // keeping them around too long during shutdown.
-    base::WeakPtr<ModelTypeControllerDelegate> delegate =
-        backend->GetTypedURLSyncBridge()
-            ->change_processor()
-            ->GetControllerDelegateOnUIThread();
-    DCHECK(delegate);
-
-    std::move(task_).Run(delegate);
-    return true;
+std::unique_ptr<syncer::ModelTypeControllerDelegate>
+GetDelegateFromHistoryService(HistoryService* history_service) {
+  if (history_service) {
+    return history_service->GetTypedURLSyncControllerDelegate();
   }
-
-  void DoneRunOnMainThread() override {}
-
- protected:
-  ModelTypeController::ModelTask task_;
-};
+  return nullptr;
+}
 
 }  // namespace
 
 TypedURLModelTypeController::TypedURLModelTypeController(
     SyncClient* sync_client,
     const char* history_disabled_pref_name)
-    : ModelTypeController(syncer::TYPED_URLS, sync_client, nullptr),
-      history_disabled_pref_name_(history_disabled_pref_name) {
+    : ModelTypeController(
+          syncer::TYPED_URLS,
+          GetDelegateFromHistoryService(sync_client->GetHistoryService()),
+          sync_client),
+      history_disabled_pref_name_(history_disabled_pref_name),
+      history_service_(sync_client->GetHistoryService()) {
   pref_registrar_.Init(sync_client->GetPrefService());
   pref_registrar_.Add(
       history_disabled_pref_name_,
@@ -69,22 +48,8 @@
 TypedURLModelTypeController::~TypedURLModelTypeController() {}
 
 bool TypedURLModelTypeController::ReadyForStart() const {
-  return !sync_client()->GetPrefService()->GetBoolean(
-      history_disabled_pref_name_);
-}
-
-void TypedURLModelTypeController::PostModelTask(const base::Location& location,
-                                                ModelTask task) {
-  history::HistoryService* history = sync_client()->GetHistoryService();
-  if (!history) {
-    // History must be disabled - don't start.
-    LOG(WARNING) << "Cannot access history service.";
-    return;
-  }
-
-  history->ScheduleDBTask(
-      FROM_HERE, std::make_unique<RunTaskOnHistoryThread>(std::move(task)),
-      &task_tracker_);
+  return history_service_ && !sync_client()->GetPrefService()->GetBoolean(
+                                 history_disabled_pref_name_);
 }
 
 void TypedURLModelTypeController::OnSavingBrowserHistoryDisabledChanged() {
diff --git a/components/history/core/browser/typed_url_model_type_controller.h b/components/history/core/browser/typed_url_model_type_controller.h
index df2a43d..70dbf2c2 100644
--- a/components/history/core/browser/typed_url_model_type_controller.h
+++ b/components/history/core/browser/typed_url_model_type_controller.h
@@ -5,12 +5,13 @@
 #ifndef COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_MODEL_TYPE_CONTROLLER_H__
 #define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_MODEL_TYPE_CONTROLLER_H__
 
-#include "base/task/cancelable_task_tracker.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/sync/driver/model_type_controller.h"
 
 namespace history {
 
+class HistoryService;
+
 class TypedURLModelTypeController : public syncer::ModelTypeController {
  public:
   TypedURLModelTypeController(syncer::SyncClient* sync_client,
@@ -22,20 +23,14 @@
   bool ReadyForStart() const override;
 
  private:
-  // syncer::ModelTypeController implementation.
-  void PostModelTask(const base::Location& location, ModelTask task) override;
-
   void OnSavingBrowserHistoryDisabledChanged();
 
   // Name of the pref that indicates whether saving history is disabled.
-  const char* history_disabled_pref_name_;
+  const char* const history_disabled_pref_name_;
+  HistoryService* const history_service_;
 
   PrefChangeRegistrar pref_registrar_;
 
-  // Helper object to make sure we don't leave tasks running on the history
-  // thread.
-  base::CancelableTaskTracker task_tracker_;
-
   DISALLOW_COPY_AND_ASSIGN(TypedURLModelTypeController);
 };
 
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index 98f4963..f408099 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -154,6 +154,7 @@
     AR_CORE_UPGRADE_ANDROID = 83,
     BLOATED_RENDERER_INFOBAR_DELEGATE = 84,
     SUPERVISED_USERS_DEPRECATED_INFOBAR_DELEGATE = 85,
+    NEAR_OOM_REDUCTION_INFOBAR_ANDROID = 86,
   };
 
   // Describes navigation events, used to decide whether infobars should be
diff --git a/components/invalidation/impl/per_user_topic_registration_manager.cc b/components/invalidation/impl/per_user_topic_registration_manager.cc
index 37e0f1f1..cbc94d6 100644
--- a/components/invalidation/impl/per_user_topic_registration_manager.cc
+++ b/components/invalidation/impl/per_user_topic_registration_manager.cc
@@ -149,6 +149,7 @@
                             .SetAuthenticationHeader(base::StringPrintf(
                                 "Bearer %s", access_token_.c_str()))
                             .SetProjectId(kProjectId)
+                            .SetType(PerUserTopicRegistrationRequest::SUBSCRIBE)
                             .Build();
 
   it->second->request->Start(
diff --git a/components/invalidation/impl/per_user_topic_registration_request.cc b/components/invalidation/impl/per_user_topic_registration_request.cc
index 353818a..d781c7c 100644
--- a/components/invalidation/impl/per_user_topic_registration_request.cc
+++ b/components/invalidation/impl/per_user_topic_registration_request.cc
@@ -79,6 +79,13 @@
     return;
   }
 
+  if (type_ == UNSUBSCRIBE) {
+    // No response body expected for DELETE requests.
+    std::move(request_completed_callback_)
+        .Run(Status(StatusCode::SUCCESS, std::string()), std::string());
+    return;
+  }
+
   if (!response_body || response_body->empty()) {
     std::move(request_completed_callback_)
         .Run(Status(StatusCode::FAILED, base::StringPrintf("Body parse error")),
@@ -128,15 +135,29 @@
   DCHECK(!scope_.empty());
   auto request = base::WrapUnique(new PerUserTopicRegistrationRequest);
 
-  GURL full_url(base::StringPrintf(
-      "%s/v1/perusertopics/%s/rel/topics/?subscriber_token=%s", scope_.c_str(),
-      project_id_.c_str(), token_.c_str()));
+  std::string url;
+  switch (type_) {
+    case SUBSCRIBE:
+      url = base::StringPrintf(
+          "%s/v1/perusertopics/%s/rel/topics/?subscriber_token=%s",
+          scope_.c_str(), project_id_.c_str(), token_.c_str());
+      break;
+    case UNSUBSCRIBE:
+      url = base::StringPrintf(
+          "%s/v1/perusertopics/%s/rel/topics/%s?subscriber_token=%s",
+          scope_.c_str(), project_id_.c_str(), topic_.c_str(), token_.c_str());
+      break;
+  }
+  GURL full_url(url);
 
   DCHECK(full_url.is_valid());
 
   request->url_ = full_url;
+  request->type_ = type_;
 
-  std::string body = BuildBody();
+  std::string body;
+  if (type_ == SUBSCRIBE)
+    body = BuildBody();
   net::HttpRequestHeaders headers = BuildHeaders();
   request->simple_loader_ = BuildURLFetcher(headers, body, full_url);
 
@@ -180,6 +201,12 @@
   return *this;
 }
 
+PerUserTopicRegistrationRequest::Builder&
+PerUserTopicRegistrationRequest::Builder::SetType(RequestType type) {
+  type_ = type;
+  return *this;
+}
+
 HttpRequestHeaders PerUserTopicRegistrationRequest::Builder::BuildHeaders()
     const {
   HttpRequestHeaders headers;
@@ -234,7 +261,14 @@
         })");
 
   auto request = std::make_unique<network::ResourceRequest>();
-  request->method = "POST";
+  switch (type_) {
+    case SUBSCRIBE:
+      request->method = "POST";
+      break;
+    case UNSUBSCRIBE:
+      request->method = "DELETE";
+      break;
+  }
   request->url = url;
   request->headers = headers;
 
diff --git a/components/invalidation/impl/per_user_topic_registration_request.h b/components/invalidation/impl/per_user_topic_registration_request.h
index a4b37e56..7a251c5 100644
--- a/components/invalidation/impl/per_user_topic_registration_request.h
+++ b/components/invalidation/impl/per_user_topic_registration_request.h
@@ -30,6 +30,7 @@
   using CompletedCallback =
       base::OnceCallback<void(const Status& status,
                               const std::string& private_topic_name)>;
+  enum RequestType { SUBSCRIBE, UNSUBSCRIBE };
 
   // Builds authenticated PerUserTopicRegistrationRequests.
   class Builder {
@@ -48,6 +49,10 @@
     Builder& SetPublicTopicName(const std::string& topic);
     Builder& SetProjectId(const std::string& project_id);
 
+    Builder& SetType(RequestType type);
+
+    enum RegistrationState { REGISTERED, UNREGISTERED };
+
    private:
     net::HttpRequestHeaders BuildHeaders() const;
     std::string BuildBody() const;
@@ -63,6 +68,7 @@
 
     std::string scope_;
     std::string auth_header_;
+    RequestType type_;
 
     DISALLOW_COPY_AND_ASSIGN(Builder);
   };
@@ -102,6 +108,7 @@
 
   // Full URL. Used in tests only.
   GURL url_;
+  RequestType type_;
 
   base::WeakPtrFactory<PerUserTopicRegistrationRequest> weak_ptr_factory_;
 
diff --git a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
index 6c452fb..4cb1320 100644
--- a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
@@ -81,6 +81,8 @@
   std::string url = "http://valid-url.test";
   std::string topic = "test";
   std::string project_id = "smarty-pants-12345";
+  PerUserTopicRegistrationRequest::RequestType type =
+      PerUserTopicRegistrationRequest::SUBSCRIBE;
 
   base::MockCallback<PerUserTopicRegistrationRequest::CompletedCallback>
       callback;
@@ -92,6 +94,7 @@
           .SetScope(url)
           .SetPublicTopicName(topic)
           .SetProjectId(project_id)
+          .SetType(type)
           .Build();
   request->Start(callback.Get(),
                  base::BindRepeating(&syncer::JsonUnsafeParser::Parse),
@@ -107,6 +110,8 @@
   std::string base_url = "http://valid-url.test";
   std::string topic = "test";
   std::string project_id = "smarty-pants-12345";
+  PerUserTopicRegistrationRequest::RequestType type =
+      PerUserTopicRegistrationRequest::SUBSCRIBE;
 
   base::MockCallback<PerUserTopicRegistrationRequest::CompletedCallback>
       callback;
@@ -121,6 +126,7 @@
           .SetScope(base_url)
           .SetPublicTopicName(topic)
           .SetProjectId(project_id)
+          .SetType(type)
           .Build();
   std::string response_body = R"(
     {
@@ -149,6 +155,8 @@
   std::string base_url = "http://valid-url.test";
   std::string topic = "test";
   std::string project_id = "smarty-pants-12345";
+  PerUserTopicRegistrationRequest::RequestType type =
+      PerUserTopicRegistrationRequest::SUBSCRIBE;
 
   base::MockCallback<PerUserTopicRegistrationRequest::CompletedCallback>
       callback;
@@ -163,6 +171,7 @@
           .SetScope(base_url)
           .SetPublicTopicName(topic)
           .SetProjectId(project_id)
+          .SetType(type)
           .Build();
   std::string response_body = R"(
     {
@@ -190,10 +199,12 @@
   std::string base_url = "http://valid-url.test";
   std::string topic = "test";
   std::string project_id = "smarty-pants-12345";
+  PerUserTopicRegistrationRequest::RequestType type =
+      PerUserTopicRegistrationRequest::SUBSCRIBE;
 
   base::MockCallback<PerUserTopicRegistrationRequest::CompletedCallback>
       callback;
-  Status status(StatusCode::FAILED, "initial");
+  Status status(StatusCode::SUCCESS, "initial");
   std::string private_topic;
 
   EXPECT_CALL(callback, Run(_, _))
@@ -205,6 +216,7 @@
           .SetScope(base_url)
           .SetPublicTopicName(topic)
           .SetProjectId(project_id)
+          .SetType(type)
           .Build();
   std::string response_body = R"(
     {}
@@ -222,6 +234,50 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_EQ(status.code, StatusCode::FAILED);
+  EXPECT_EQ(status.message, "Body parse error");
+}
+
+TEST_F(PerUserTopicRegistrationRequestTest, ShouldUnsubscribe) {
+  std::string token = "1234567890";
+  std::string base_url = "http://valid-url.test";
+  std::string topic = "test";
+  std::string project_id = "smarty-pants-12345";
+  PerUserTopicRegistrationRequest::RequestType type =
+      PerUserTopicRegistrationRequest::UNSUBSCRIBE;
+
+  base::MockCallback<PerUserTopicRegistrationRequest::CompletedCallback>
+      callback;
+  Status status(StatusCode::FAILED, "initial");
+  std::string private_topic;
+
+  EXPECT_CALL(callback, Run(_, _))
+      .WillOnce(DoAll(SaveArg<0>(&status), SaveArg<1>(&private_topic)));
+
+  PerUserTopicRegistrationRequest::Builder builder;
+  std::unique_ptr<PerUserTopicRegistrationRequest> request =
+      builder.SetToken(token)
+          .SetScope(base_url)
+          .SetPublicTopicName(topic)
+          .SetProjectId(project_id)
+          .SetType(type)
+          .Build();
+  std::string response_body = R"(
+    {}
+  )";
+
+  network::URLLoaderCompletionStatus response_status(net::OK);
+  response_status.decoded_body_length = response_body.size();
+
+  url_loader_factory()->AddResponse(url(request.get()),
+                                    CreateHeadersForTest(net::HTTP_OK),
+                                    response_body, response_status);
+  request->Start(callback.Get(),
+                 base::BindRepeating(&syncer::JsonUnsafeParser::Parse),
+                 url_loader_factory());
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(status.code, StatusCode::SUCCESS);
+  EXPECT_EQ(status.message, std::string());
 }
 
 }  // namespace syncer
diff --git a/components/neterror/resources/neterror.css b/components/neterror/resources/neterror.css
index 90d2831..3fd07fd 100644
--- a/components/neterror/resources/neterror.css
+++ b/components/neterror/resources/neterror.css
@@ -13,9 +13,9 @@
 }
 
 #diagnose-button {
-  -webkit-margin-start: 0;
   float: none;
   margin-bottom: 10px;
+  margin-inline-start: 0;
   margin-top: 20px;
 }
 
@@ -95,7 +95,7 @@
 }
 
 #suggestions-list p {
-  -webkit-margin-after: 0;
+  margin-block-end: 0;
 }
 
 #suggestions-list ul {
@@ -168,9 +168,9 @@
 }
 
 .secondary-button {
-  -webkit-margin-end: 16px;
   background: #d9d9d9;
   color: #696969;
+  margin-inline-end: 16px;
 }
 
 .snackbar {
@@ -331,8 +331,8 @@
 }
 
 .suggested-left .secondary-button {
-  -webkit-margin-end: 0px;
-  -webkit-margin-start: 16px;
+  margin-inline-end: 0px;
+  margin-inline-start: 16px;
 }
 
 #details-button.singular {
@@ -350,7 +350,6 @@
 }
 
 .download-button:before {
-  -webkit-margin-end: 4px;
   background: -webkit-image-set(
       url(../../resources/default_100_percent/neterror/download.png) 1x,
       url(../../resources/default_200_percent/neterror/download.png) 2x)
@@ -359,6 +358,7 @@
   display: inline-block;
   width: 24px;
   height: 24px;
+  margin-inline-end: 4px;
   vertical-align: middle;
 }
 
@@ -391,7 +391,7 @@
 }
 
 .download-button-alternate:before {
-  -webkit-margin-end: 4px;
+  margin-inline-end: 4px;
   background: -webkit-image-set(
       url(../../resources/default_100_percent/neterror/download_blue.png) 1x,
       url(../../resources/default_200_percent/neterror/download_blue.png) 2x)
diff --git a/components/nux_google_apps/resources/apps_chooser.html b/components/nux_google_apps/resources/apps_chooser.html
index 437954a..b5a96d44 100644
--- a/components/nux_google_apps/resources/apps_chooser.html
+++ b/components/nux_google_apps/resources/apps_chooser.html
@@ -14,12 +14,12 @@
       }
 
       .app-icon {
-        -webkit-margin-end: 16px;
-        -webkit-margin-start: 4px;
+        margin-inline-end: 16px;
+        margin-inline-start: 4px;
       }
 
       iron-icon {
-        -webkit-margin-end: 48px;
+        margin-inline-end: 48px;
       }
 
       [active] iron-icon[icon="cr:check"] {
diff --git a/components/omnibox/browser/in_memory_url_index.cc b/components/omnibox/browser/in_memory_url_index.cc
index 3a2fe066..f2439e7b 100644
--- a/components/omnibox/browser/in_memory_url_index.cc
+++ b/components/omnibox/browser/in_memory_url_index.cc
@@ -14,6 +14,7 @@
 #include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_usage_estimator.h"
 #include "base/trace_event/trace_event.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/browser/url_database.h"
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 8d10885..277cb31 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -18,6 +18,7 @@
 #include "base/strings/string_util.h"
 #include "base/sys_info.h"
 #include "base/time/time.h"
+#include "base/trace_event/memory_usage_estimator.h"
 #include "build/build_config.h"
 #include "components/omnibox/browser/omnibox_switches.h"
 #include "components/omnibox/browser/url_index_private_data.h"
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index ab14f65..8168c19 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -15,8 +15,8 @@
 #include <utility>
 
 #include "base/containers/stack.h"
-#include "base/files/file_util.h"
 #include "base/feature_list.h"
+#include "base/files/file_util.h"
 #include "base/i18n/break_iterator.h"
 #include "base/i18n/case_conversion.h"
 #include "base/macros.h"
@@ -25,6 +25,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "base/trace_event/memory_usage_estimator.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_utils.h"
 #include "components/history/core/browser/history_database.h"
diff --git a/components/prefs/pref_service.cc b/components/prefs/pref_service.cc
index 6e7ae1e..afd66ba 100644
--- a/components/prefs/pref_service.cc
+++ b/components/prefs/pref_service.cc
@@ -424,7 +424,8 @@
 
 void PrefService::SetFilePath(const std::string& path,
                               const base::FilePath& value) {
-  SetUserPrefValue(path, base::CreateFilePathValue(value));
+  SetUserPrefValue(
+      path, base::Value::ToUniquePtrValue(base::CreateFilePathValue(value)));
 }
 
 void PrefService::SetInt64(const std::string& path, int64_t value) {
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index c7ea5cf..028de5b 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -739,15 +739,15 @@
 
   FrameReference frame_;
   blink::WebNode node_to_print_;
-  bool owns_web_view_;
+  bool owns_web_view_ = false;
   blink::WebPrintParams web_print_params_;
   gfx::Size prev_view_size_;
   gfx::Size prev_scroll_offset_;
-  int expected_pages_count_;
+  int expected_pages_count_ = 0;
   base::Closure on_ready_;
-  bool should_print_backgrounds_;
-  bool should_print_selection_only_;
-  bool is_printing_started_;
+  const bool should_print_backgrounds_;
+  const bool should_print_selection_only_;
+  bool is_printing_started_ = false;
 
   base::WeakPtrFactory<PrepareFrameAndViewForPrint> weak_ptr_factory_;
 
@@ -761,11 +761,8 @@
     bool ignore_css_margins)
     : frame_(frame),
       node_to_print_(node),
-      owns_web_view_(false),
-      expected_pages_count_(0),
       should_print_backgrounds_(params.should_print_backgrounds),
       should_print_selection_only_(params.selection_only),
-      is_printing_started_(false),
       weak_ptr_factory_(this) {
   PrintMsg_Print_Params print_params = params;
   bool source_is_pdf = PrintingNodeOrPdfFrame(frame, node_to_print_);
@@ -968,17 +965,7 @@
     std::unique_ptr<Delegate> delegate)
     : content::RenderFrameObserver(render_frame),
       content::RenderFrameObserverTracker<PrintRenderFrameHelper>(render_frame),
-      reset_prep_frame_view_(false),
-      is_print_ready_metafile_sent_(false),
-      ignore_css_margins_(false),
-      is_printing_enabled_(true),
-      notify_browser_of_print_failure_(true),
       delegate_(std::move(delegate)),
-      print_node_in_progress_(false),
-      is_loading_(false),
-      is_scripted_preview_delayed_(false),
-      ipc_nesting_level_(0),
-      render_frame_gone_(false),
       weak_ptr_factory_(this) {
   if (!delegate_->IsPrintPreviewEnabled())
     DisablePreview();
@@ -2199,15 +2186,9 @@
 }
 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
 
-PrintRenderFrameHelper::PrintPreviewContext::PrintPreviewContext()
-    : total_page_count_(0),
-      current_page_index_(0),
-      is_modifiable_(true),
-      print_ready_metafile_page_count_(0),
-      error_(PREVIEW_ERROR_NONE),
-      state_(UNINITIALIZED) {}
+PrintRenderFrameHelper::PrintPreviewContext::PrintPreviewContext() = default;
 
-PrintRenderFrameHelper::PrintPreviewContext::~PrintPreviewContext() {}
+PrintRenderFrameHelper::PrintPreviewContext::~PrintPreviewContext() = default;
 
 void PrintRenderFrameHelper::PrintPreviewContext::InitWithFrame(
     blink::WebLocalFrame* web_frame) {
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
index 6e2d7e1..947ab972 100644
--- a/components/printing/renderer/print_render_frame_helper.h
+++ b/components/printing/renderer/print_render_frame_helper.h
@@ -375,18 +375,18 @@
 
   // WebView used only to print the selection.
   std::unique_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
-  bool reset_prep_frame_view_;
+  bool reset_prep_frame_view_ = false;
 
   std::unique_ptr<PrintMsg_PrintPages_Params> print_pages_params_;
   gfx::Rect printer_printable_area_;
-  bool is_print_ready_metafile_sent_;
-  bool ignore_css_margins_;
+  bool is_print_ready_metafile_sent_ = false;
+  bool ignore_css_margins_ = false;
 
-  bool is_printing_enabled_;
+  bool is_printing_enabled_ = true;
 
   // Let the browser process know of a printing failure. Only set to false when
   // the failure came from the browser in the first place.
-  bool notify_browser_of_print_failure_;
+  bool notify_browser_of_print_failure_ = true;
 
   // Used to check the prerendering status.
   const std::unique_ptr<Delegate> delegate_;
@@ -479,26 +479,26 @@
     std::unique_ptr<PdfMetafileSkia> metafile_;
 
     // Total page count in the renderer.
-    int total_page_count_;
+    int total_page_count_ = 0;
 
     // The current page to render.
-    int current_page_index_;
+    int current_page_index_ = 0;
 
     // List of page indices that need to be rendered.
     std::vector<int> pages_to_render_;
 
     // True, if the document source is modifiable. e.g. HTML and not PDF.
-    bool is_modifiable_;
+    bool is_modifiable_ = true;
 
     // Specifies the total number of pages in the print ready metafile.
-    int print_ready_metafile_page_count_;
+    int print_ready_metafile_page_count_ = 0;
 
     base::TimeDelta document_render_time_;
     base::TimeTicks begin_time_;
 
-    enum PrintPreviewErrorBuckets error_;
+    enum PrintPreviewErrorBuckets error_ = PREVIEW_ERROR_NONE;
 
-    State state_;
+    State state_ = UNINITIALIZED;
 
     DISALLOW_COPY_AND_ASSIGN(PrintPreviewContext);
   };
@@ -522,12 +522,12 @@
 
   ScriptingThrottler scripting_throttler_;
 
-  bool print_node_in_progress_;
+  bool print_node_in_progress_ = false;
   PrintPreviewContext print_preview_context_;
-  bool is_loading_;
-  bool is_scripted_preview_delayed_;
-  int ipc_nesting_level_;
-  bool render_frame_gone_;
+  bool is_loading_ = false;
+  bool is_scripted_preview_delayed_ = false;
+  int ipc_nesting_level_ = 0;
+  bool render_frame_gone_ = false;
 
   // Used to fix a race condition where the source is a PDF and print preview
   // hangs because RequestPrintPreview is called before DidStopLoading() is
diff --git a/components/scheduling_metrics/BUILD.gn b/components/scheduling_metrics/BUILD.gn
new file mode 100644
index 0000000..cc99e7fd
--- /dev/null
+++ b/components/scheduling_metrics/BUILD.gn
@@ -0,0 +1,35 @@
+# 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.
+
+component("scheduling_metrics") {
+  sources = [
+    "task_duration_metric_reporter.h",
+    "thread_metrics.cc",
+    "thread_metrics.h",
+    "thread_type.h",
+    "total_duration_metric_reporter.cc",
+    "total_duration_metric_reporter.h",
+  ]
+
+  defines = [ "IS_SCHEDULING_METRICS_IMPL" ]
+
+  public_deps = [
+    "//base",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+  sources = [
+    "thread_metrics_unittest.cc",
+    "total_duration_metric_reporter_unittest.cc",
+  ]
+
+  deps = [
+    ":scheduling_metrics",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/components/scheduling_metrics/DEPS b/components/scheduling_metrics/DEPS
new file mode 100644
index 0000000..91d8d419
--- /dev/null
+++ b/components/scheduling_metrics/DEPS
@@ -0,0 +1,5 @@
+deps = [
+  # This component should not have any dependencies other than //base as it 
+  # should be able to be used from any other place.
+  "+components/scheduling_metrics",
+]
diff --git a/components/scheduling_metrics/OWNERS b/components/scheduling_metrics/OWNERS
new file mode 100644
index 0000000..88a3022c
--- /dev/null
+++ b/components/scheduling_metrics/OWNERS
@@ -0,0 +1,15 @@
+# LON scheduling team
+altimin@chromium.org
+alexclarke@chromium.org
+esecker@chromium.org
+skyostil@chromium.org
+
+# WAT speed metrics team
+tdresser@chromium.org
+npm@chromium.org
+
+# MON scheduling team
+fdoray@chromium.org
+gab@chromium.org
+
+# COMPONENT: Blink>Scheduler
diff --git a/components/scheduling_metrics/README b/components/scheduling_metrics/README
new file mode 100644
index 0000000..efca241
--- /dev/null
+++ b/components/scheduling_metrics/README
@@ -0,0 +1,9 @@
+This directory contains code for scheduling metrics which are shared between
+renderer process and browser process.
+
+These metrics include:
+- Expected queueing time (EQT) calculation.
+- Per-thread task duration metrics.
+
+This component should not have any dependencies other than //base as it 
+should be able to be used from any other place.
diff --git a/third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h b/components/scheduling_metrics/task_duration_metric_reporter.h
similarity index 77%
rename from third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h
rename to components/scheduling_metrics/task_duration_metric_reporter.h
index de4dc8a..b2a9b818 100644
--- a/third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h
+++ b/components/scheduling_metrics/task_duration_metric_reporter.h
@@ -1,10 +1,13 @@
-// Copyright 2018 The Chromium Authors.All rights reserved.
+// 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.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_TASK_DURATION_METRIC_REPORTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_TASK_DURATION_METRIC_REPORTER_H_
+#ifndef COMPONENTS_SCHEDULING_METRICS_TASK_DURATION_METRIC_REPORTER_H_
+#define COMPONENTS_SCHEDULING_METRICS_TASK_DURATION_METRIC_REPORTER_H_
 
+#include <memory>
+
+#include "base/component_export.h"
 #include "base/macros.h"
 #include "base/metrics/histogram.h"
 #include "base/time/time.h"
@@ -13,15 +16,14 @@
 class HistogramBase;
 }
 
-namespace blink {
-namespace scheduler {
+namespace scheduling_metrics {
 
 // A helper class to report total task runtime split by the different types of
 // |TypeClass|. Only full seconds are reported. Note that partial seconds are
 // rounded up/down, so that on average the correct value is reported when many
 // reports are added.
 //
-//|TaskClass| is an enum which should have COUNT field.
+// |TaskClass| is an enum which should have kClass field.
 template <class TaskClass>
 class TaskDurationMetricReporter {
  public:
@@ -55,7 +57,6 @@
   DISALLOW_COPY_AND_ASSIGN(TaskDurationMetricReporter);
 };
 
-}  // namespace scheduler
-}  // namespace blink
+}  // namespace scheduling_metrics
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_UTIL_TASK_DURATION_METRIC_REPORTER_H_
+#endif  // COMPONENTS_SCHEDULING_METRICS_TASK_DURATION_METRIC_REPORTER_H_
diff --git a/components/scheduling_metrics/thread_metrics.cc b/components/scheduling_metrics/thread_metrics.cc
new file mode 100644
index 0000000..ac568b2
--- /dev/null
+++ b/components/scheduling_metrics/thread_metrics.cc
@@ -0,0 +1,67 @@
+// 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/scheduling_metrics/thread_metrics.h"
+
+namespace scheduling_metrics {
+
+namespace {
+
+// Threshold for discarding ultra-long tasks. It is assumed that ultra-long
+// tasks are reporting glitches (e.g. system falling asleep on the middle of the
+// task).
+constexpr base::TimeDelta kLongTaskDiscardingThreshold =
+    base::TimeDelta::FromSeconds(30);
+
+}  // namespace
+
+ThreadMetrics::ThreadMetrics(ThreadType thread_type,
+                             bool has_cpu_timing_for_each_task)
+    : thread_type_(thread_type),
+      has_cpu_timing_for_each_task_(has_cpu_timing_for_each_task),
+      last_known_time_(has_cpu_timing_for_each_task_ ? base::ThreadTicks::Now()
+                                                     : base::ThreadTicks()),
+      thread_task_duration_reporter_(
+          "Scheduler.Experimental.WallTimePerThread"),
+      thread_task_cpu_duration_reporter_(
+          "Scheduler.Experimental.CPUTimePerThread"),
+      tracked_cpu_duration_reporter_(
+          "Scheduler.Experimental.CPUTimePerThread.Tracked"),
+      non_tracked_cpu_duration_reporter_(
+          "Scheduler.Experimental.CPUTimePerThread.Untracked") {}
+
+ThreadMetrics::~ThreadMetrics() {}
+
+bool ThreadMetrics::ShouldDiscardTask(
+    base::sequence_manager::TaskQueue* queue,
+    const base::sequence_manager::TaskQueue::Task& task,
+    const base::sequence_manager::TaskQueue::TaskTiming& task_timing) {
+  // TODO(altimin): Investigate the relationship between thread time and
+  // wall time for discarded tasks.
+  return task_timing.wall_duration() > kLongTaskDiscardingThreshold;
+}
+
+void ThreadMetrics::RecordTaskMetrics(
+    base::sequence_manager::TaskQueue* queue,
+    const base::sequence_manager::TaskQueue::Task& task,
+    const base::sequence_manager::TaskQueue::TaskTiming& task_timing) {
+  DCHECK(!has_cpu_timing_for_each_task_ || task_timing.has_thread_time());
+  thread_task_duration_reporter_.RecordTask(thread_type_,
+                                            task_timing.wall_duration());
+
+  if (!task_timing.has_thread_time())
+    return;
+  thread_task_cpu_duration_reporter_.RecordTask(thread_type_,
+                                                task_timing.thread_duration());
+  if (has_cpu_timing_for_each_task_) {
+    non_tracked_cpu_duration_reporter_.RecordTask(
+        thread_type_, task_timing.start_thread_time() - last_known_time_);
+    tracked_cpu_duration_reporter_.RecordTask(thread_type_,
+                                              task_timing.thread_duration());
+
+    last_known_time_ = task_timing.end_thread_time();
+  }
+}
+
+}  // namespace scheduling_metrics
diff --git a/components/scheduling_metrics/thread_metrics.h b/components/scheduling_metrics/thread_metrics.h
new file mode 100644
index 0000000..e2f4f23
--- /dev/null
+++ b/components/scheduling_metrics/thread_metrics.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef COMPONENTS_SCHEDULING_METRICS_THREAD_METRICS_H_
+#define COMPONENTS_SCHEDULING_METRICS_THREAD_METRICS_H_
+
+#include "base/component_export.h"
+#include "base/optional.h"
+#include "base/task/sequence_manager/task_queue.h"
+#include "base/time/time.h"
+#include "components/scheduling_metrics/task_duration_metric_reporter.h"
+#include "components/scheduling_metrics/thread_type.h"
+#include "components/scheduling_metrics/total_duration_metric_reporter.h"
+
+namespace scheduling_metrics {
+
+// Helper class to take care of task metrics shared between different threads
+// in Chrome, including but not limited to browser UI and IO threads, renderer
+// main thread and blink worker threads.
+//
+class COMPONENT_EXPORT(SCHEDULING_METRICS) ThreadMetrics {
+ public:
+  ThreadMetrics(ThreadType thread_type, bool has_cpu_timing_for_each_task);
+  ~ThreadMetrics();
+
+  bool ShouldDiscardTask(
+      base::sequence_manager::TaskQueue* queue,
+      const base::sequence_manager::TaskQueue::Task& task,
+      const base::sequence_manager::TaskQueue::TaskTiming& task_timing);
+
+  // Record task metrics which are shared between threads.
+  void RecordTaskMetrics(
+      base::sequence_manager::TaskQueue* queue,
+      const base::sequence_manager::TaskQueue::Task& task,
+      const base::sequence_manager::TaskQueue::TaskTiming& task_timing);
+
+ protected:
+  const ThreadType thread_type_;
+  const bool has_cpu_timing_for_each_task_;
+
+ private:
+  base::ThreadTicks last_known_time_;
+
+  TaskDurationMetricReporter<ThreadType> thread_task_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType> thread_task_cpu_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType> tracked_cpu_duration_reporter_;
+  TaskDurationMetricReporter<ThreadType> non_tracked_cpu_duration_reporter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadMetrics);
+};
+
+}  // namespace scheduling_metrics
+
+#endif  // COMPONENTS_SCHEDULING_METRICS_THREAD_METRICS_H_
diff --git a/components/scheduling_metrics/thread_metrics_unittest.cc b/components/scheduling_metrics/thread_metrics_unittest.cc
new file mode 100644
index 0000000..7160af3
--- /dev/null
+++ b/components/scheduling_metrics/thread_metrics_unittest.cc
@@ -0,0 +1,106 @@
+// 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/scheduling_metrics/thread_metrics.h"
+
+#include "base/task/sequence_manager/test/fake_task.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "base/time/time_override.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::sequence_manager::TaskQueue;
+
+namespace scheduling_metrics {
+
+namespace {
+
+using base::sequence_manager::FakeTask;
+using base::sequence_manager::FakeTaskTiming;
+
+base::TimeTicks Seconds(int seconds) {
+  return base::TimeTicks() + base::TimeDelta::FromSeconds(seconds);
+}
+
+base::ThreadTicks ThreadSeconds(int seconds) {
+  return base::ThreadTicks() + base::TimeDelta::FromSeconds(seconds);
+}
+
+}  // namespace
+
+TEST(MetricsHelperTest, TaskDurationPerThreadType) {
+  base::HistogramTester histogram_tester;
+
+  ThreadMetrics main_thread_metrics(ThreadType::kRendererMainThread,
+                                    false /* has_cpu_timing_for_each_task */);
+  ThreadMetrics compositor_metrics(ThreadType::kRendererCompositorThread,
+                                   false /* has_cpu_timing_for_each_task */);
+  ThreadMetrics worker_metrics(ThreadType::kRendererOtherBlinkThread,
+                               false /* has_cpu_timing_for_each_task */);
+
+  main_thread_metrics.RecordTaskMetrics(
+      nullptr, FakeTask(),
+      FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(0),
+                     ThreadSeconds(15)));
+  compositor_metrics.RecordTaskMetrics(
+      nullptr, FakeTask(),
+      FakeTaskTiming(Seconds(10), Seconds(80), ThreadSeconds(0),
+                     ThreadSeconds(5)));
+  compositor_metrics.RecordTaskMetrics(
+      nullptr, FakeTask(), FakeTaskTiming(Seconds(100), Seconds(200)));
+  worker_metrics.RecordTaskMetrics(
+      nullptr, FakeTask(),
+      FakeTaskTiming(Seconds(10), Seconds(125), ThreadSeconds(0),
+                     ThreadSeconds(25)));
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples(
+          "Scheduler.Experimental.WallTimePerThread"),
+      testing::UnorderedElementsAre(
+          base::Bucket(static_cast<int>(ThreadType::kRendererMainThread), 40),
+          base::Bucket(static_cast<int>(ThreadType::kRendererCompositorThread),
+                       170),
+          base::Bucket(static_cast<int>(ThreadType::kRendererOtherBlinkThread),
+                       115)));
+
+  EXPECT_THAT(
+      histogram_tester.GetAllSamples("Scheduler.Experimental.CPUTimePerThread"),
+      testing::UnorderedElementsAre(
+          base::Bucket(static_cast<int>(ThreadType::kRendererMainThread), 15),
+          base::Bucket(static_cast<int>(ThreadType::kRendererCompositorThread),
+                       5),
+          base::Bucket(static_cast<int>(ThreadType::kRendererOtherBlinkThread),
+                       25)));
+}
+
+TEST(MetricsHelperTest, TrackedCPUTimeMetrics) {
+  base::HistogramTester histogram_tester;
+  base::subtle::ScopedTimeClockOverrides time_override(
+      []() { return base::Time(); }, []() { return Seconds(1); },
+      []() { return ThreadSeconds(1); });
+
+  ThreadMetrics main_thread_metrics(ThreadType::kRendererMainThread,
+                                    true /* has_cpu_timing_for_each_task */);
+
+  main_thread_metrics.RecordTaskMetrics(
+      nullptr, FakeTask(),
+      FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(5),
+                     ThreadSeconds(15)));
+  main_thread_metrics.RecordTaskMetrics(
+      nullptr, FakeTask(),
+      FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(20),
+                     ThreadSeconds(25)));
+
+  EXPECT_THAT(histogram_tester.GetAllSamples(
+                  "Scheduler.Experimental.CPUTimePerThread.Tracked"),
+              testing::UnorderedElementsAre(base::Bucket(
+                  static_cast<int>(ThreadType::kRendererMainThread), 15)));
+  // 9 = 4 seconds before task 1 and 5 seconds between tasks 1 and 2.
+  EXPECT_THAT(histogram_tester.GetAllSamples(
+                  "Scheduler.Experimental.CPUTimePerThread.Untracked"),
+              testing::UnorderedElementsAre(base::Bucket(
+                  static_cast<int>(ThreadType::kRendererMainThread), 9)));
+}
+
+}  // namespace scheduling_metrics
diff --git a/components/scheduling_metrics/thread_type.h b/components/scheduling_metrics/thread_type.h
new file mode 100644
index 0000000..d844cab5
--- /dev/null
+++ b/components/scheduling_metrics/thread_type.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef COMPONENTS_SCHEDULING_METRICS_THREAD_TYPE_H_
+#define COMPONENTS_SCHEDULING_METRICS_THREAD_TYPE_H_
+
+namespace scheduling_metrics {
+
+// The list of all threads in the Chrome we support scheduling metrics for.
+// This enum is used as a key in histograms and should not be renumbered.
+// Please update SchedulerThreadType enum in tools/metrics/histograms/enums.xml
+// when adding new values.
+enum class ThreadType {
+  kBrowserUIThread = 0,
+  kBrowserIOThread = 1,
+  kRendererMainThread = 2,
+  kRendererCompositorThread = 3,
+  kRendererDedicatedWorkerThread = 4,
+  kRendererServiceWorkerThread = 5,
+  // Blink has ~10 other named threads, however they run just a few tasks.
+  // Aggregate them into a single item for clarity and split out if necessary.
+  kRendererOtherBlinkThread = 6,
+
+  kCount = 7,
+};
+
+}  // namespace scheduling_metrics
+
+#endif  // COMPONENTS_SCHEDULING_METRICS_THREAD_TYPE_H_
diff --git a/third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.cc b/components/scheduling_metrics/total_duration_metric_reporter.cc
similarity index 87%
rename from third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.cc
rename to components/scheduling_metrics/total_duration_metric_reporter.cc
index 54ed2af..061c4d7 100644
--- a/third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.cc
+++ b/components/scheduling_metrics/total_duration_metric_reporter.cc
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h"
+#include "components/scheduling_metrics/total_duration_metric_reporter.h"
 
-namespace blink {
-namespace scheduler {
+namespace scheduling_metrics {
 
 namespace {
 
@@ -43,5 +42,4 @@
   reported_value_ = base::nullopt;
 }
 
-}  // namespace scheduler
-}  // namespace blink
+}  // namespace scheduling_metrics
diff --git a/third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h b/components/scheduling_metrics/total_duration_metric_reporter.h
similarity index 68%
rename from third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h
rename to components/scheduling_metrics/total_duration_metric_reporter.h
index f15e5011..5ea43ed 100644
--- a/third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h
+++ b/components/scheduling_metrics/total_duration_metric_reporter.h
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TOTAL_DURATION_METRIC_REPORTER_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TOTAL_DURATION_METRIC_REPORTER_H_
+#ifndef COMPONENTS_SCHEDULING_METRICS_TOTAL_DURATION_METRIC_REPORTER_H_
+#define COMPONENTS_SCHEDULING_METRICS_TOTAL_DURATION_METRIC_REPORTER_H_
 
+#include "base/component_export.h"
 #include "base/metrics/histogram.h"
 #include "base/optional.h"
 #include "base/time/time.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
 
-namespace blink {
-namespace scheduler {
+namespace scheduling_metrics {
 
 // Helper class to measure the total duration of the event accounting for
 // possibility of the renderer process going away at any point.
@@ -21,7 +20,7 @@
 // "Undoing" is implemented by having a second "negative" histogram, so to
 // obtain the result, |positive_histogram - negative_histogram| difference
 // should be analysed.
-class PLATFORM_EXPORT TotalDurationMetricReporter {
+class COMPONENT_EXPORT(SCHEDULING_METRICS) TotalDurationMetricReporter {
  public:
   TotalDurationMetricReporter(const char* positive_histogram_name,
                               const char* negative_histogram_name);
@@ -37,7 +36,6 @@
   base::HistogramBase* negative_histogram_;
 };
 
-}  // namespace scheduler
-}  // namespace blink
+}  // namespace scheduling_metrics
 
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_COMMON_TOTAL_DURATION_METRIC_REPORTER_H_
+#endif  // COMPONENTS_SCHEDULING_METRICS_TOTAL_DURATION_METRIC_REPORTER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter_unittest.cc b/components/scheduling_metrics/total_duration_metric_reporter_unittest.cc
similarity index 88%
rename from third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter_unittest.cc
rename to components/scheduling_metrics/total_duration_metric_reporter_unittest.cc
index c30cfaae..0b99a6d 100644
--- a/third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter_unittest.cc
+++ b/components/scheduling_metrics/total_duration_metric_reporter_unittest.cc
@@ -2,13 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h"
+#include "components/scheduling_metrics/total_duration_metric_reporter.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace blink {
-namespace scheduler {
+namespace scheduling_metrics {
 
 TEST(TotalDurationMetricReporterTest, Test) {
   base::HistogramTester histogram_tester;
@@ -41,5 +40,4 @@
                           std::make_pair(8, 1), std::make_pair(10, 1)));
 }
 
-}  // namespace scheduler
-}  // namespace blink
+}  // namespace scheduling_metrics
diff --git a/components/security_interstitials/core/common/resources/interstitial_common.css b/components/security_interstitials/core/common/resources/interstitial_common.css
index 51a5b710..7fd721d 100644
--- a/components/security_interstitials/core/common/resources/interstitial_common.css
+++ b/components/security_interstitials/core/common/resources/interstitial_common.css
@@ -269,7 +269,7 @@
   }
 
   .secondary-button {
-    -webkit-margin-end: 0;
+    margin-inline-end: 0;
     margin-top: 16px;
   }
 }
diff --git a/components/signin/core/browser/account_info.cc b/components/signin/core/browser/account_info.cc
index e7e061e..ca29895 100644
--- a/components/signin/core/browser/account_info.cc
+++ b/components/signin/core/browser/account_info.cc
@@ -19,11 +19,20 @@
     *field = new_value;
   return should_update;
 }
-}
 
-AccountInfo::AccountInfo() : is_child_account(false) {}
+}  // namespace
+
+AccountInfo::AccountInfo() = default;
+
+AccountInfo::~AccountInfo() = default;
+
 AccountInfo::AccountInfo(const AccountInfo& other) = default;
-AccountInfo::~AccountInfo() {}
+
+AccountInfo::AccountInfo(AccountInfo&& other) noexcept = default;
+
+AccountInfo& AccountInfo::operator=(const AccountInfo& other) = default;
+
+AccountInfo& AccountInfo::operator=(AccountInfo&& other) noexcept = default;
 
 bool AccountInfo::IsEmpty() const {
   return account_id.empty() && email.empty() && gaia.empty() &&
diff --git a/components/signin/core/browser/account_info.h b/components/signin/core/browser/account_info.h
index b97189e..30165bcf 100644
--- a/components/signin/core/browser/account_info.h
+++ b/components/signin/core/browser/account_info.h
@@ -12,9 +12,16 @@
 // Information about a specific account.
 struct AccountInfo {
   AccountInfo();
-  AccountInfo(const AccountInfo& other);
   ~AccountInfo();
 
+  // Copy/move constructors and assignment operators are defined out-of-line
+  // as they are identified as complex by clang plugin.
+  AccountInfo(const AccountInfo& other);
+  AccountInfo(AccountInfo&& other) noexcept;
+
+  AccountInfo& operator=(const AccountInfo& other);
+  AccountInfo& operator=(AccountInfo&& other) noexcept;
+
   std::string account_id;  // The account ID used by OAuth2TokenService.
   std::string gaia;
   std::string email;
@@ -23,7 +30,7 @@
   std::string hosted_domain;
   std::string locale;
   std::string picture_url;
-  bool is_child_account;
+  bool is_child_account = false;
 
   // Returns true if all fields in the account info are empty.
   bool IsEmpty() const;
diff --git a/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css b/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css
index e84b3bc..d7253f0 100644
--- a/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css
+++ b/components/supervised_user_error_page/resources/supervised_user_block_interstitial.css
@@ -225,7 +225,7 @@
   }
 
   .secondary-button {
-    -webkit-margin-end: 0;
+    margin-inline-end: 0;
     margin-top: 16px;
   }
 }
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 1766d58..9382bf6 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -445,6 +445,8 @@
     "model_impl/model_type_store_service_impl.h",
     "model_impl/processor_entity_tracker.cc",
     "model_impl/processor_entity_tracker.h",
+    "model_impl/proxy_model_type_controller_delegate.cc",
+    "model_impl/proxy_model_type_controller_delegate.h",
     "model_impl/sync_metadata_store_change_list.cc",
     "model_impl/sync_metadata_store_change_list.h",
     "protocol/proto_enum_conversions.cc",
diff --git a/components/sync/base/data_type_histogram.cc b/components/sync/base/data_type_histogram.cc
index 42b8b34a..d67da6b 100644
--- a/components/sync/base/data_type_histogram.cc
+++ b/components/sync/base/data_type_histogram.cc
@@ -6,12 +6,23 @@
 
 #include "base/metrics/histogram_functions.h"
 
+namespace {
 const char kModelTypeMemoryHistogramPrefix[] = "Sync.ModelTypeMemoryKB.";
+const char kModelTypeCountHistogramPrefix[] = "Sync.ModelTypeCount2.";
+}  // namespace
 
-void SyncRecordMemoryKbHistogram(const std::string& histogram_name_prefix,
-                                 syncer::ModelType model_type,
-                                 size_t value) {
+void SyncRecordModelTypeMemoryHistogram(syncer::ModelType model_type,
+                                        size_t bytes) {
   std::string type_string = ModelTypeToHistogramSuffix(model_type);
-  std::string full_histogram_name = histogram_name_prefix + type_string;
-  base::UmaHistogramCounts1M(full_histogram_name, value / 1024);
+  std::string full_histogram_name =
+      kModelTypeMemoryHistogramPrefix + type_string;
+  base::UmaHistogramCounts1M(full_histogram_name, bytes / 1024);
+}
+
+void SyncRecordModelTypeCountHistogram(syncer::ModelType model_type,
+                                       size_t count) {
+  std::string type_string = ModelTypeToHistogramSuffix(model_type);
+  std::string full_histogram_name =
+      kModelTypeCountHistogramPrefix + type_string;
+  base::UmaHistogramCounts1M(full_histogram_name, count);
 }
diff --git a/components/sync/base/data_type_histogram.h b/components/sync/base/data_type_histogram.h
index e59031c..bd17cfb 100644
--- a/components/sync/base/data_type_histogram.h
+++ b/components/sync/base/data_type_histogram.h
@@ -11,14 +11,15 @@
 #include "base/time/time.h"
 #include "components/sync/base/model_type.h"
 
-// Prefix for histogram recording datatype's memory usage.
-extern const char kModelTypeMemoryHistogramPrefix[];
+// Converts memory size |bytes| into kilobytes and records it into |model_type|
+// related histogram for memory footprint of sync data.
+void SyncRecordModelTypeMemoryHistogram(syncer::ModelType model_type,
+                                        size_t bytes);
 
-// Converts memory size |value| into kilobytes and records it into |model_type|
-// related histogram with prefix |histogram_name_prefix|.
-void SyncRecordMemoryKbHistogram(const std::string& histogram_name_prefix,
-                                 syncer::ModelType model_type,
-                                 size_t value);
+// Records |count| into a |model_type| related histogram for count of sync
+// entities.
+void SyncRecordModelTypeCountHistogram(syncer::ModelType model_type,
+                                       size_t count);
 
 // Helper macro for datatype specific histograms. For each datatype, invokes
 // a pre-defined PER_DATA_TYPE_MACRO(type_str), where |type_str| is the string
diff --git a/components/sync/driver/DEPS b/components/sync/driver/DEPS
index 442fcaa9..64c7a38 100644
--- a/components/sync/driver/DEPS
+++ b/components/sync/driver/DEPS
@@ -12,6 +12,8 @@
   "+components/sync/engine",
   "+components/sync/js",
   "+components/sync/model",
+  # TODO(crbug.com/855010): Remove this dependency when tests get simplified.
+  "+components/sync/model_impl",
   "+components/sync/protocol",
   "+components/sync/syncable",
   "+components/sync/test",
diff --git a/components/sync/driver/data_type_controller.h b/components/sync/driver/data_type_controller.h
index 61e6bf5f..b557fe1 100644
--- a/components/sync/driver/data_type_controller.h
+++ b/components/sync/driver/data_type_controller.h
@@ -171,8 +171,9 @@
   // Used to display entity counts in chrome://sync-internals.
   virtual void GetStatusCounters(const StatusCountersCallback& callback) = 0;
 
-  // Estimates memory usage of type and records it into histogram.
-  virtual void RecordMemoryUsageHistogram() = 0;
+  // Records entities count and estimated memory usage of the type into
+  // histograms.
+  virtual void RecordMemoryUsageAndCountsHistograms() = 0;
 
  protected:
   explicit DataTypeController(ModelType type);
diff --git a/components/sync/driver/directory_data_type_controller.cc b/components/sync/driver/directory_data_type_controller.cc
index 03d0c7e..3420a8c 100644
--- a/components/sync/driver/directory_data_type_controller.cc
+++ b/components/sync/driver/directory_data_type_controller.cc
@@ -90,12 +90,13 @@
   callback.Run(type(), counters);
 }
 
-void DirectoryDataTypeController::RecordMemoryUsageHistogram() {
+void DirectoryDataTypeController::RecordMemoryUsageAndCountsHistograms() {
   syncer::syncable::Directory* directory =
       sync_client_->GetSyncService()->GetUserShare()->directory.get();
-  size_t memory_usage = directory->EstimateMemoryUsageByType(type());
-  SyncRecordMemoryKbHistogram(kModelTypeMemoryHistogramPrefix, type(),
-                              memory_usage);
+  SyncRecordModelTypeMemoryHistogram(
+      type(), directory->EstimateMemoryUsageByType(type()));
+  SyncRecordModelTypeCountHistogram(type(),
+                                    directory->CountEntriesByType(type()));
 }
 
 // static
diff --git a/components/sync/driver/directory_data_type_controller.h b/components/sync/driver/directory_data_type_controller.h
index a2873ea..7ee6747 100644
--- a/components/sync/driver/directory_data_type_controller.h
+++ b/components/sync/driver/directory_data_type_controller.h
@@ -49,7 +49,7 @@
   void Stop(SyncStopMetadataFate metadata_fate, StopCallback callback) final;
   void GetAllNodes(const AllNodesCallback& callback) override;
   void GetStatusCounters(const StatusCountersCallback& callback) override;
-  void RecordMemoryUsageHistogram() override;
+  void RecordMemoryUsageAndCountsHistograms() override;
 
   // Convenience overload with synchronous API, since directory types are always
   // capable of stopping immediately.
diff --git a/components/sync/driver/model_type_controller.cc b/components/sync/driver/model_type_controller.cc
index d47c32e..272e59b 100644
--- a/components/sync/driver/model_type_controller.cc
+++ b/components/sync/driver/model_type_controller.cc
@@ -10,7 +10,6 @@
 #include "base/location.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "components/signin/core/browser/account_info.h"
-#include "components/sync/base/bind_to_task_runner.h"
 #include "components/sync/base/data_type_histogram.h"
 #include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/driver/sync_client.h"
@@ -23,43 +22,8 @@
 #include "components/sync/model/sync_merge_result.h"
 
 namespace syncer {
-
-using DelegateProvider = ModelTypeController::DelegateProvider;
-using ModelTask = ModelTypeController::ModelTask;
-
 namespace {
 
-void OnSyncStartingHelperOnModelThread(
-    const DataTypeActivationRequest& request,
-    ModelTypeControllerDelegate::StartCallback callback_bound_to_ui_thread,
-    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
-  delegate->OnSyncStarting(request, std::move(callback_bound_to_ui_thread));
-}
-
-void GetAllNodesForDebuggingHelperOnModelThread(
-    const DataTypeController::AllNodesCallback& callback_bound_to_ui_thread,
-    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
-  delegate->GetAllNodesForDebugging(callback_bound_to_ui_thread);
-}
-
-void GetStatusCountersForDebuggingHelperOnModelThread(
-    const DataTypeController::StatusCountersCallback&
-        callback_bound_to_ui_thread,
-    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
-  delegate->GetStatusCountersForDebugging(callback_bound_to_ui_thread);
-}
-
-void RecordMemoryUsageHistogramHelperOnModelThread(
-    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
-  delegate->RecordMemoryUsageHistogram();
-}
-
-void StopSyncHelperOnModelThread(
-    SyncStopMetadataFate metadata_fate,
-    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
-  delegate->OnSyncStopping(metadata_fate);
-}
-
 void ReportError(ModelType model_type,
                  scoped_refptr<base::SequencedTaskRunner> ui_thread,
                  const ModelErrorHandler& error_handler,
@@ -71,20 +35,6 @@
   ui_thread->PostTask(error.location(), base::Bind(error_handler, error));
 }
 
-// This function allows us to return a Callback using Bind that returns the
-// given |arg|. This function itself does nothing.
-base::WeakPtr<ModelTypeControllerDelegate> ReturnCapturedDelegate(
-    base::WeakPtr<ModelTypeControllerDelegate> arg) {
-  return arg;
-}
-
-void RunModelTask(DelegateProvider delegate_provider, ModelTask task) {
-  base::WeakPtr<ModelTypeControllerDelegate> delegate =
-      std::move(delegate_provider).Run();
-  if (delegate.get())
-    std::move(task).Run(delegate);
-}
-
 // Takes the strictest policy for clearing sync metadata.
 SyncStopMetadataFate TakeStrictestMetadataFate(SyncStopMetadataFate fate1,
                                                SyncStopMetadataFate fate2) {
@@ -102,12 +52,14 @@
 
 ModelTypeController::ModelTypeController(
     ModelType type,
-    SyncClient* sync_client,
-    const scoped_refptr<base::SingleThreadTaskRunner>& model_thread)
+    std::unique_ptr<ModelTypeControllerDelegate> delegate,
+    SyncClient* sync_client)
     : DataTypeController(type),
+      delegate_(std::move(delegate)),
       sync_client_(sync_client),
-      model_thread_(model_thread),
-      state_(NOT_RUNNING) {}
+      state_(NOT_RUNNING) {
+  DCHECK(sync_client_);
+}
 
 ModelTypeController::~ModelTypeController() {}
 
@@ -128,11 +80,6 @@
   DVLOG(1) << "Sync starting for " << ModelTypeToString(type());
   state_ = MODEL_STARTING;
 
-  // Callback that posts back to the UI thread.
-  ModelTypeControllerDelegate::StartCallback callback_bound_to_ui_thread =
-      BindToCurrentSequence(base::BindOnce(
-          &ModelTypeController::OnProcessorStarted, base::AsWeakPtr(this)));
-
   DataTypeActivationRequest request;
   request.error_handler = base::BindRepeating(
       &ReportError, type(), base::SequencedTaskRunnerHandle::Get(),
@@ -147,11 +94,10 @@
   DCHECK(!request.authenticated_account_id.empty());
   DCHECK(!request.cache_guid.empty());
 
-  // Start the type processor on the model thread.
-  PostModelTask(
-      FROM_HERE,
-      base::BindOnce(&OnSyncStartingHelperOnModelThread, std::move(request),
-                     std::move(callback_bound_to_ui_thread)));
+  // Ask the delegate to actually start the datatype.
+  delegate_->OnSyncStarting(
+      request, base::BindOnce(&ModelTypeController::OnProcessorStarted,
+                              base::AsWeakPtr(this)));
 }
 
 void ModelTypeController::BeforeLoadModels(ModelTypeConfigurer* configurer) {}
@@ -168,8 +114,6 @@
     DVLOG(1) << "Sync start completion received late for "
              << ModelTypeToString(type()) << ", it has been stopped meanwhile";
     RecordStartFailure(ABORTED);
-    PostModelTask(FROM_HERE, base::BindOnce(&StopSyncHelperOnModelThread,
-                                            model_stop_metadata_fate_));
     state_ = NOT_RUNNING;
 
     // We make a copy in case running the callbacks has side effects and
@@ -177,6 +121,9 @@
     std::vector<StopCallback> model_stop_callbacks =
         std::move(model_stop_callbacks_);
     DCHECK(model_stop_callbacks_.empty());
+
+    delegate_->OnSyncStopping(model_stop_metadata_fate_);
+
     for (StopCallback& stop_callback : model_stop_callbacks) {
       std::move(stop_callback).Run();
     }
@@ -298,9 +245,8 @@
     case MODEL_LOADED:
     case RUNNING:
       DVLOG(1) << "Stopping sync for " << ModelTypeToString(type());
-      PostModelTask(FROM_HERE, base::BindOnce(&StopSyncHelperOnModelThread,
-                                              metadata_fate));
       state_ = NOT_RUNNING;
+      delegate_->OnSyncStopping(metadata_fate);
       std::move(callback).Run();
       break;
   }
@@ -311,22 +257,16 @@
 }
 
 void ModelTypeController::GetAllNodes(const AllNodesCallback& callback) {
-  PostModelTask(FROM_HERE,
-                base::BindOnce(&GetAllNodesForDebuggingHelperOnModelThread,
-                               BindToCurrentSequence(callback)));
+  delegate_->GetAllNodesForDebugging(callback);
 }
 
 void ModelTypeController::GetStatusCounters(
     const StatusCountersCallback& callback) {
-  PostModelTask(
-      FROM_HERE,
-      base::BindOnce(&GetStatusCountersForDebuggingHelperOnModelThread,
-                     BindToCurrentSequence(callback)));
+  delegate_->GetStatusCountersForDebugging(callback);
 }
 
-void ModelTypeController::RecordMemoryUsageHistogram() {
-  PostModelTask(FROM_HERE,
-                base::BindOnce(&RecordMemoryUsageHistogramHelperOnModelThread));
+void ModelTypeController::RecordMemoryUsageAndCountsHistograms() {
+  delegate_->RecordMemoryUsageAndCountsHistograms();
 }
 
 void ModelTypeController::ReportModelError(SyncError::ErrorType error_type,
@@ -349,19 +289,4 @@
 #undef PER_DATA_TYPE_MACRO
 }
 
-DelegateProvider ModelTypeController::GetDelegateProvider() {
-  // Get the delegate eagerly, and capture the weak pointer.
-  base::WeakPtr<ModelTypeControllerDelegate> delegate =
-      sync_client_->GetControllerDelegateForModelType(type());
-  return base::Bind(&ReturnCapturedDelegate, delegate);
-}
-
-void ModelTypeController::PostModelTask(const base::Location& location,
-                                        ModelTask task) {
-  DCHECK(model_thread_);
-  model_thread_->PostTask(
-      location,
-      base::BindOnce(&RunModelTask, GetDelegateProvider(), std::move(task)));
-}
-
 }  // namespace syncer
diff --git a/components/sync/driver/model_type_controller.h b/components/sync/driver/model_type_controller.h
index f96bf88..587dd03 100644
--- a/components/sync/driver/model_type_controller.h
+++ b/components/sync/driver/model_type_controller.h
@@ -12,7 +12,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
 #include "components/sync/base/model_type.h"
 #include "components/sync/driver/data_type_controller.h"
 #include "components/sync/model/model_error.h"
@@ -27,15 +26,9 @@
 // DataTypeController implementation for Unified Sync and Storage model types.
 class ModelTypeController : public DataTypeController {
  public:
-  using DelegateProvider =
-      base::OnceCallback<base::WeakPtr<ModelTypeControllerDelegate>()>;
-  using ModelTask =
-      base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)>;
-
-  ModelTypeController(
-      ModelType type,
-      SyncClient* sync_client,
-      const scoped_refptr<base::SingleThreadTaskRunner>& model_thread);
+  ModelTypeController(ModelType type,
+                      std::unique_ptr<ModelTypeControllerDelegate> delegate,
+                      SyncClient* sync_client);
   ~ModelTypeController() override;
 
   // DataTypeController implementation.
@@ -51,7 +44,7 @@
   State state() const override;
   void GetAllNodes(const AllNodesCallback& callback) override;
   void GetStatusCounters(const StatusCountersCallback& callback) override;
-  void RecordMemoryUsageHistogram() override;
+  void RecordMemoryUsageAndCountsHistograms() override;
 
  protected:
   void ReportModelError(SyncError::ErrorType error_type,
@@ -73,20 +66,11 @@
   void OnProcessorStarted(
       std::unique_ptr<DataTypeActivationResponse> activation_response);
 
-  // Delegate accessor that can be overridden. This will be called on the UI
-  // thread, but the callback will only be run on the model thread.
-  virtual DelegateProvider GetDelegateProvider();
-
-  // Post the given task (that requires the delegate object to run) to the model
-  // thread.
-  virtual void PostModelTask(const base::Location& location, ModelTask task);
+  const std::unique_ptr<ModelTypeControllerDelegate> delegate_;
 
   // The sync client, which provides access to this type's Delegate.
   SyncClient* const sync_client_;
 
-  // The thread the model type lives on.
-  scoped_refptr<base::SingleThreadTaskRunner> model_thread_;
-
   // State of this datatype controller.
   State state_;
 
diff --git a/components/sync/driver/model_type_controller_unittest.cc b/components/sync/driver/model_type_controller_unittest.cc
index 8b562443..cae0180f 100644
--- a/components/sync/driver/model_type_controller_unittest.cc
+++ b/components/sync/driver/model_type_controller_unittest.cc
@@ -24,6 +24,7 @@
 #include "components/sync/engine/fake_model_type_processor.h"
 #include "components/sync/engine/model_type_configurer.h"
 #include "components/sync/engine/model_type_processor_proxy.h"
+#include "components/sync/model_impl/proxy_model_type_controller_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -104,7 +105,7 @@
   void GetStatusCountersForDebugging(StatusCountersCallback callback) override {
   }
 
-  void RecordMemoryUsageHistogram() override {}
+  void RecordMemoryUsageAndCountsHistograms() override {}
 
  private:
   int cleared_metadata_count_ = 0;
@@ -193,11 +194,18 @@
 
     ON_CALL(sync_client_mock_, GetSyncService())
         .WillByDefault(testing::Return(&sync_service_));
-    ON_CALL(sync_client_mock_, GetControllerDelegateForModelType(_))
-        .WillByDefault(testing::Return(base::AsWeakPtr(&delegate_)));
 
+    // TODO(crbug.com/855010): Remove the proxy and simplify these tests.
     controller_ = std::make_unique<ModelTypeController>(
-        kTestModelType, &sync_client_mock_, model_thread_.task_runner());
+        kTestModelType,
+        std::make_unique<ProxyModelTypeControllerDelegate>(
+            model_thread_.task_runner(),
+            base::BindRepeating(
+                [](base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+                  return delegate;
+                },
+                base::AsWeakPtr(&delegate_))),
+        &sync_client_mock_);
   }
 
   ~ModelTypeControllerTest() {
diff --git a/components/sync/driver/proxy_data_type_controller.cc b/components/sync/driver/proxy_data_type_controller.cc
index 138e603a..048545d 100644
--- a/components/sync/driver/proxy_data_type_controller.cc
+++ b/components/sync/driver/proxy_data_type_controller.cc
@@ -83,6 +83,6 @@
   callback.Run(type(), counters);
 }
 
-void ProxyDataTypeController::RecordMemoryUsageHistogram() {}
+void ProxyDataTypeController::RecordMemoryUsageAndCountsHistograms() {}
 
 }  // namespace syncer
diff --git a/components/sync/driver/proxy_data_type_controller.h b/components/sync/driver/proxy_data_type_controller.h
index 3f70df6..c5d1d8e9 100644
--- a/components/sync/driver/proxy_data_type_controller.h
+++ b/components/sync/driver/proxy_data_type_controller.h
@@ -34,7 +34,7 @@
   void DeactivateDataType(ModelTypeConfigurer* configurer) override;
   void GetAllNodes(const AllNodesCallback& callback) override;
   void GetStatusCounters(const StatusCountersCallback& callback) override;
-  void RecordMemoryUsageHistogram() override;
+  void RecordMemoryUsageAndCountsHistograms() override;
 
  private:
   State state_;
diff --git a/components/sync/driver/resources/sync_node_browser.css b/components/sync/driver/resources/sync_node_browser.css
index b1f72dc..d3ed5de 100644
--- a/components/sync/driver/resources/sync_node_browser.css
+++ b/components/sync/driver/resources/sync_node_browser.css
@@ -16,13 +16,13 @@
 }
 
 #sync-node-tree-container {
-  -webkit-padding-start: 10px;
   box-sizing: border-box;
   height: 100%;
   /* min-width and max-width are used by the split pane. */
   max-width: 50%;
   min-width: 200px;
   overflow: auto;
+  padding-inline-start: 10px;
   width: 200px;
 }
 
diff --git a/components/sync/driver/resources/sync_search.css b/components/sync/driver/resources/sync_search.css
index 5500b46..bc8af104 100644
--- a/components/sync/driver/resources/sync_search.css
+++ b/components/sync/driver/resources/sync_search.css
@@ -29,7 +29,6 @@
 }
 
 #sync-results-list {
-  -webkit-padding-start: 10px;
   box-sizing: border-box;
   height: 100%;
   /* min-width and max-width are used by the split pane. */
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index 3d270305..8e33e05f 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -61,8 +61,8 @@
   // bitmask.
   enum DisableReason {
     DISABLE_REASON_NONE = 0,
-    // Sync is disabled via command-line flag or platform-level override (e.g.
-    // Android's "MasterSync" toggle).
+    // Sync is disabled via platform-level override (e.g. Android's "MasterSync"
+    // toggle).
     DISABLE_REASON_PLATFORM_OVERRIDE = 1 << 0,
     // Sync is disabled by enterprise policy, either browser policy (through
     // prefs) or account policy received from the Sync server.
diff --git a/components/sync/model/fake_model_type_controller_delegate.cc b/components/sync/model/fake_model_type_controller_delegate.cc
index 57eeb29d..405e272 100644
--- a/components/sync/model/fake_model_type_controller_delegate.cc
+++ b/components/sync/model/fake_model_type_controller_delegate.cc
@@ -37,7 +37,7 @@
   std::move(callback).Run(type_, StatusCounters());
 }
 
-void FakeModelTypeControllerDelegate::RecordMemoryUsageHistogram() {}
+void FakeModelTypeControllerDelegate::RecordMemoryUsageAndCountsHistograms() {}
 
 base::WeakPtr<ModelTypeControllerDelegate>
 FakeModelTypeControllerDelegate::GetWeakPtr() {
diff --git a/components/sync/model/fake_model_type_controller_delegate.h b/components/sync/model/fake_model_type_controller_delegate.h
index c4589cf..c565e5e 100644
--- a/components/sync/model/fake_model_type_controller_delegate.h
+++ b/components/sync/model/fake_model_type_controller_delegate.h
@@ -27,7 +27,7 @@
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
   void GetStatusCountersForDebugging(StatusCountersCallback callback) override;
-  void RecordMemoryUsageHistogram() override;
+  void RecordMemoryUsageAndCountsHistograms() override;
 
   base::WeakPtr<ModelTypeControllerDelegate> GetWeakPtr();
 
diff --git a/components/sync/model/model_type_change_processor.h b/components/sync/model/model_type_change_processor.h
index 73023ba..2cb60b7 100644
--- a/components/sync/model/model_type_change_processor.h
+++ b/components/sync/model/model_type_change_processor.h
@@ -92,6 +92,8 @@
 
   // Returns the delegate for the controller. This function must be thread-safe!
   // It is run on the UI thread by the ModelTypeController.
+  // TODO(mastiz): Remove the inaccurate suffix OnUIThread and the thread-safety
+  // requirement documented above, since it actually runs on the model thread.
   virtual base::WeakPtr<ModelTypeControllerDelegate>
   GetControllerDelegateOnUIThread() = 0;
 };
diff --git a/components/sync/model/model_type_controller_delegate.h b/components/sync/model/model_type_controller_delegate.h
index bd4799d..712365d7 100644
--- a/components/sync/model/model_type_controller_delegate.h
+++ b/components/sync/model/model_type_controller_delegate.h
@@ -54,8 +54,9 @@
   virtual void GetStatusCountersForDebugging(
       StatusCountersCallback callback) = 0;
 
-  // Estimates memory usage and records it in a histogram.
-  virtual void RecordMemoryUsageHistogram() = 0;
+  // Records entities count and estimated memory usage of the type into
+  // histograms.
+  virtual void RecordMemoryUsageAndCountsHistograms() = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index d4e3a25..8cc9fbd 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -1173,9 +1173,9 @@
   std::move(callback).Run(type_, counters);
 }
 
-void ClientTagBasedModelTypeProcessor::RecordMemoryUsageHistogram() {
-  SyncRecordMemoryKbHistogram(kModelTypeMemoryHistogramPrefix, type_,
-                              EstimateMemoryUsage());
+void ClientTagBasedModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
+  SyncRecordModelTypeMemoryHistogram(type_, EstimateMemoryUsage());
+  SyncRecordModelTypeCountHistogram(type_, entities_.size());
 }
 
 }  // namespace syncer
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.h b/components/sync/model_impl/client_tag_based_model_type_processor.h
index e05f1a9..a00a5859 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.h
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.h
@@ -89,7 +89,7 @@
   void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
   void GetStatusCountersForDebugging(StatusCountersCallback callback) override;
-  void RecordMemoryUsageHistogram() override;
+  void RecordMemoryUsageAndCountsHistograms() override;
 
   // Returns the estimate of dynamically allocated memory in bytes.
   size_t EstimateMemoryUsage() const;
diff --git a/components/sync/model_impl/proxy_model_type_controller_delegate.cc b/components/sync/model_impl/proxy_model_type_controller_delegate.cc
new file mode 100644
index 0000000..128657d
--- /dev/null
+++ b/components/sync/model_impl/proxy_model_type_controller_delegate.cc
@@ -0,0 +1,113 @@
+// 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/sync/model_impl/proxy_model_type_controller_delegate.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "components/sync/base/bind_to_task_runner.h"
+#include "components/sync/model/data_type_activation_request.h"
+
+namespace syncer {
+namespace {
+
+void OnSyncStartingHelperOnModelThread(
+    const DataTypeActivationRequest& request,
+    ModelTypeControllerDelegate::StartCallback callback_bound_to_ui_thread,
+    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+  delegate->OnSyncStarting(request, std::move(callback_bound_to_ui_thread));
+}
+
+void GetAllNodesForDebuggingHelperOnModelThread(
+    ProxyModelTypeControllerDelegate::AllNodesCallback
+        callback_bound_to_ui_thread,
+    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+  delegate->GetAllNodesForDebugging(std::move(callback_bound_to_ui_thread));
+}
+
+void GetStatusCountersForDebuggingHelperOnModelThread(
+    ProxyModelTypeControllerDelegate::StatusCountersCallback
+        callback_bound_to_ui_thread,
+    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+  delegate->GetStatusCountersForDebugging(
+      std::move(callback_bound_to_ui_thread));
+}
+
+void StopSyncHelperOnModelThread(
+    SyncStopMetadataFate metadata_fate,
+    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+  delegate->OnSyncStopping(metadata_fate);
+}
+
+void RecordMemoryUsageAndCountsHistogramsHelperOnModelThread(
+    base::WeakPtr<ModelTypeControllerDelegate> delegate) {
+  delegate->RecordMemoryUsageAndCountsHistograms();
+}
+
+// Rurns some task on the destination task runner (backend sequence), first
+// exercising |delegate_provider| *also* in the backend sequence.
+void RunModelTask(
+    const ProxyModelTypeControllerDelegate::DelegateProvider& delegate_provider,
+    base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)> task) {
+  base::WeakPtr<ModelTypeControllerDelegate> delegate = delegate_provider.Run();
+  if (delegate) {
+    std::move(task).Run(delegate);
+  }
+}
+
+}  // namespace
+
+ProxyModelTypeControllerDelegate::ProxyModelTypeControllerDelegate(
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    const DelegateProvider& delegate_provider)
+    : task_runner_(task_runner), delegate_provider_(delegate_provider) {
+  DCHECK(task_runner_);
+}
+
+ProxyModelTypeControllerDelegate::~ProxyModelTypeControllerDelegate() {}
+
+void ProxyModelTypeControllerDelegate::OnSyncStarting(
+    const DataTypeActivationRequest& request,
+    StartCallback callback) {
+  PostTask(FROM_HERE,
+           base::BindOnce(&OnSyncStartingHelperOnModelThread, request,
+                          BindToCurrentSequence(std::move(callback))));
+}
+
+void ProxyModelTypeControllerDelegate::OnSyncStopping(
+    SyncStopMetadataFate metadata_fate) {
+  PostTask(FROM_HERE,
+           base::BindOnce(&StopSyncHelperOnModelThread, metadata_fate));
+}
+
+void ProxyModelTypeControllerDelegate::GetAllNodesForDebugging(
+    AllNodesCallback callback) {
+  PostTask(FROM_HERE,
+           base::BindOnce(&GetAllNodesForDebuggingHelperOnModelThread,
+                          BindToCurrentSequence(std::move(callback))));
+}
+
+void ProxyModelTypeControllerDelegate::GetStatusCountersForDebugging(
+    StatusCountersCallback callback) {
+  PostTask(FROM_HERE,
+           base::BindOnce(&GetStatusCountersForDebuggingHelperOnModelThread,
+                          BindToCurrentSequence(std::move(callback))));
+}
+
+void ProxyModelTypeControllerDelegate::RecordMemoryUsageAndCountsHistograms() {
+  PostTask(
+      FROM_HERE,
+      base::BindOnce(&RecordMemoryUsageAndCountsHistogramsHelperOnModelThread));
+}
+
+void ProxyModelTypeControllerDelegate::PostTask(
+    const base::Location& location,
+    base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)> task) {
+  task_runner_->PostTask(
+      location,
+      base::BindOnce(&RunModelTask, delegate_provider_, std::move(task)));
+}
+
+}  // namespace syncer
diff --git a/components/sync/model_impl/proxy_model_type_controller_delegate.h b/components/sync/model_impl/proxy_model_type_controller_delegate.h
new file mode 100644
index 0000000..53670ce1
--- /dev/null
+++ b/components/sync/model_impl/proxy_model_type_controller_delegate.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef COMPONENTS_SYNC_MODEL_IMPL_PROXY_MODEL_TYPE_CONTROLLER_DELEGATE_H_
+#define COMPONENTS_SYNC_MODEL_IMPL_PROXY_MODEL_TYPE_CONTROLLER_DELEGATE_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "components/sync/model/model_type_controller_delegate.h"
+
+namespace syncer {
+
+// Implementation of ModelTypeControllerDelegate that simply delegates the work
+// further to |other|, which lives in a difference thread/sequence. This means
+// all methods are implemented via posting tasks to the destination sequence, as
+// provided in the constructor via |task_runner|.
+class ProxyModelTypeControllerDelegate : public ModelTypeControllerDelegate {
+ public:
+  using DelegateProvider =
+      base::RepeatingCallback<base::WeakPtr<ModelTypeControllerDelegate>()>;
+  // |delegate_provider| will be run lazily *AND* in |task_runner|.
+  ProxyModelTypeControllerDelegate(
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      const DelegateProvider& delegate_provider);
+  ~ProxyModelTypeControllerDelegate() override;
+
+  // ModelTypeControllerDelegate implementation.
+  void OnSyncStarting(const DataTypeActivationRequest& request,
+                      StartCallback callback) override;
+  void OnSyncStopping(SyncStopMetadataFate metadata_fate) override;
+  void GetAllNodesForDebugging(AllNodesCallback callback) override;
+  void GetStatusCountersForDebugging(StatusCountersCallback callback) override;
+  void RecordMemoryUsageAndCountsHistograms() override;
+
+ private:
+  // Post the given task (that requires the destination delegate to run) to
+  // |task_runner_|.
+  void PostTask(
+      const base::Location& location,
+      base::OnceCallback<void(base::WeakPtr<ModelTypeControllerDelegate>)>
+          task);
+
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  const DelegateProvider delegate_provider_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProxyModelTypeControllerDelegate);
+};
+
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_MODEL_IMPL_PROXY_MODEL_TYPE_CONTROLLER_DELEGATE_H_
diff --git a/components/sync/syncable/directory.cc b/components/sync/syncable/directory.cc
index a504f2c1..cf0b75c 100644
--- a/components/sync/syncable/directory.cc
+++ b/components/sync/syncable/directory.cc
@@ -456,11 +456,15 @@
   kernel_->dirty_metahandles.clear();
 }
 
-bool Directory::SafeToPurgeFromMemory(WriteTransaction* trans,
-                                      const EntryKernel* const entry) const {
-  bool safe = entry->ref(IS_DEL) && !entry->is_dirty() &&
-              !entry->ref(SYNCING) && !entry->ref(IS_UNAPPLIED_UPDATE) &&
-              !entry->ref(IS_UNSYNCED);
+bool Directory::SafeToPurgeFromMemory(const EntryKernel& entry) const {
+  return entry.ref(IS_DEL) && !entry.is_dirty() && !entry.ref(SYNCING) &&
+         !entry.ref(IS_UNAPPLIED_UPDATE) && !entry.ref(IS_UNSYNCED);
+}
+
+bool Directory::SafeToPurgeFromMemoryForTransaction(
+    WriteTransaction* trans,
+    const EntryKernel* const entry) const {
+  bool safe = SafeToPurgeFromMemory(*entry);
 
   if (safe) {
     int64_t handle = entry->ref(META_HANDLE);
@@ -552,7 +556,7 @@
     MetahandlesMap::iterator found =
         kernel_->metahandles_map.find((*i)->ref(META_HANDLE));
     if (found != kernel_->metahandles_map.end() &&
-        SafeToPurgeFromMemory(&trans, found->second.get())) {
+        SafeToPurgeFromMemoryForTransaction(&trans, found->second.get())) {
       // We now drop deleted metahandles that are up to date on both the client
       // and the server.
       std::unique_ptr<EntryKernel> entry = std::move(found->second);
@@ -935,6 +939,22 @@
   return memory_usage;
 }
 
+size_t Directory::CountEntriesByType(ModelType model_type) const {
+  ScopedKernelLock lock(this);
+  int count = 0;
+  for (const auto& handle_and_kernel : kernel_->metahandles_map) {
+    EntryKernel* entry = handle_and_kernel.second.get();
+    if (GetModelTypeFromSpecifics(entry->ref(SPECIFICS)) != model_type) {
+      continue;
+    }
+    if (SafeToPurgeFromMemory(*entry)) {
+      continue;
+    }
+    ++count;
+  }
+  return count;
+}
+
 void Directory::SetDownloadProgress(
     ModelType model_type,
     const sync_pb::DataTypeProgressMarker& new_progress) {
diff --git a/components/sync/syncable/directory.h b/components/sync/syncable/directory.h
index 29907fe..81a0bb3 100644
--- a/components/sync/syncable/directory.h
+++ b/components/sync/syncable/directory.h
@@ -279,6 +279,9 @@
   // |model_type|.
   size_t EstimateMemoryUsageByType(ModelType model_type);
 
+  // Get the count of entries of type |model_type|.
+  size_t CountEntriesByType(ModelType model_type) const;
+
   // Gets/Increments transaction version of a model type. Must be called when
   // holding kernel mutex.
   int64_t GetTransactionVersion(ModelType type) const;
@@ -554,9 +557,14 @@
   // Used by CheckTreeInvariants.
   void GetAllMetaHandles(BaseTransaction* trans, MetahandleSet* result);
 
+  // Checks whether |entry| is safe to purge.
+  bool SafeToPurgeFromMemory(const EntryKernel& entry) const;
+
   // Used by VacuumAfterSaveChanges.
-  bool SafeToPurgeFromMemory(WriteTransaction* trans,
-                             const EntryKernel* const entry) const;
+  bool SafeToPurgeFromMemoryForTransaction(
+      WriteTransaction* trans,
+      const EntryKernel* const entry) const;
+
   // A helper used by GetTotalNodeCount.
   void GetChildSetForKernel(
       BaseTransaction*,
diff --git a/components/sync/syncable/directory_backing_store.cc b/components/sync/syncable/directory_backing_store.cc
index 8c97f4b..e6a1cda9 100644
--- a/components/sync/syncable/directory_backing_store.cc
+++ b/components/sync/syncable/directory_backing_store.cc
@@ -133,8 +133,7 @@
 void UnpackProtoFields(sql::Statement* statement,
                        EntryKernel* kernel,
                        int* index,
-                       int end_index,
-                       int* total_entry_copies) {
+                       int end_index) {
   const void* prev_blob = nullptr;
   int prev_length = -1;
   int prev_index = -1;
@@ -160,7 +159,6 @@
       prev_blob = blob;
       prev_length = length;
       prev_index = *index;
-      ++(*total_entry_copies);
     }
   }
 }
@@ -168,8 +166,7 @@
 // The caller owns the returned EntryKernel*.  Assumes the statement currently
 // points to a valid row in the metas table. Returns null to indicate that
 // it detected a corruption in the data on unpacking.
-std::unique_ptr<EntryKernel> UnpackEntry(sql::Statement* statement,
-                                         int* total_specifics_copies) {
+std::unique_ptr<EntryKernel> UnpackEntry(sql::Statement* statement) {
   std::unique_ptr<EntryKernel> kernel(new EntryKernel());
   DCHECK_EQ(statement->ColumnCount(), static_cast<int>(FIELD_COUNT));
   int i = 0;
@@ -192,7 +189,7 @@
                 statement->ColumnString(i));
   }
   UnpackProtoFields<sync_pb::EntitySpecifics, ProtoField>(
-      statement, kernel.get(), &i, PROTO_FIELDS_END, total_specifics_copies);
+      statement, kernel.get(), &i, PROTO_FIELDS_END);
   for ( ; i < UNIQUE_POSITION_FIELDS_END; ++i) {
     std::string temp;
     statement->ColumnBlobAsString(i, &temp);
@@ -273,27 +270,6 @@
   return save_statement->Run();
 }
 
-// total_specifics_copies : Total copies of entries in memory, include extra
-// copy for some entries which create by copy-on-write mechanism.
-// entries_counts : entry counts for each model type.
-void UploadModelTypeEntryCount(const int total_specifics_copies,
-                               const int (&entries_counts)[MODEL_TYPE_COUNT]) {
-  int total_entry_counts = 0;
-  for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
-    std::string model_type = ModelTypeToHistogramSuffix((ModelType)i);
-    std::string full_histogram_name = "Sync.ModelTypeCount." + model_type;
-    base::HistogramBase* histogram = base::Histogram::FactoryGet(
-        full_histogram_name, 1, 1000000, 50,
-        base::HistogramBase::kUmaTargetedHistogramFlag);
-    if (histogram)
-      histogram->Add(entries_counts[i]);
-    total_entry_counts += entries_counts[i];
-  }
-  UMA_HISTOGRAM_COUNTS("Sync.ModelTypeCount", total_entry_counts);
-  UMA_HISTOGRAM_COUNTS("Sync.ExtraSyncDataCount",
-                       total_specifics_copies - total_entry_counts);
-}
-
 }  // namespace
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -705,17 +681,10 @@
   select.append("SELECT ");
   AppendColumnList(&select);
   select.append(" FROM metas");
-  int total_specifics_copies = 0;
-  int model_type_entry_count[MODEL_TYPE_COUNT];
-  for (int i = 0; i < MODEL_TYPE_COUNT; ++i) {
-    model_type_entry_count[i] = 0;
-  }
-
   sql::Statement s(db_->GetUniqueStatement(select.c_str()));
 
   while (s.Step()) {
-    std::unique_ptr<EntryKernel> kernel =
-        UnpackEntry(&s, &total_specifics_copies);
+    std::unique_ptr<EntryKernel> kernel = UnpackEntry(&s);
     // A null kernel is evidence of external data corruption.
     if (!kernel)
       return false;
@@ -724,17 +693,10 @@
     if (SafeToPurgeOnLoading(*kernel)) {
       metahandles_to_purge->insert(handle);
     } else {
-      ModelType model_type = kernel->GetModelType();
-      if (!IsRealDataType(model_type)) {
-        model_type = kernel->GetServerModelType();
-      }
-      ++model_type_entry_count[model_type];
       (*handles_map)[handle] = std::move(kernel);
     }
   }
 
-  UploadModelTypeEntryCount(total_specifics_copies, model_type_entry_count);
-
   return s.Succeeded();
 }
 
@@ -759,8 +721,7 @@
   sql::Statement s(db_->GetUniqueStatement(select.c_str()));
 
   while (s.Step()) {
-    int total_entry_copies;
-    std::unique_ptr<EntryKernel> kernel = UnpackEntry(&s, &total_entry_copies);
+    std::unique_ptr<EntryKernel> kernel = UnpackEntry(&s);
     // A null kernel is evidence of external data corruption.
     if (!kernel)
       return false;
diff --git a/components/sync/syncable/syncable_id.h b/components/sync/syncable/syncable_id.h
index 67cf909..56e5c090 100644
--- a/components/sync/syncable/syncable_id.h
+++ b/components/sync/syncable/syncable_id.h
@@ -88,8 +88,7 @@
   static Id GetRoot();
 
  private:
-  friend std::unique_ptr<EntryKernel> UnpackEntry(sql::Statement* statement,
-                                                  int* total_created_entries);
+  friend std::unique_ptr<EntryKernel> UnpackEntry(sql::Statement* statement);
   friend void BindFields(const EntryKernel& entry, sql::Statement* statement);
   friend std::ostream& operator<<(std::ostream& out, const Id& id);
   friend class SyncableIdTest;
diff --git a/components/sync/test/fake_server/bookmark_entity_builder.cc b/components/sync/test/fake_server/bookmark_entity_builder.cc
index 2844fec..5b01f9a 100644
--- a/components/sync/test/fake_server/bookmark_entity_builder.cc
+++ b/components/sync/test/fake_server/bookmark_entity_builder.cc
@@ -45,6 +45,10 @@
   parent_id_ = parent_id;
 }
 
+void BookmarkEntityBuilder::SetIndex(int index) {
+  index_ = index;
+}
+
 std::unique_ptr<LoopbackServerEntity> BookmarkEntityBuilder::BuildBookmark(
     const GURL& url) {
   if (!url.is_valid()) {
@@ -75,11 +79,10 @@
 std::unique_ptr<LoopbackServerEntity> BookmarkEntityBuilder::Build(
     const sync_pb::EntitySpecifics& entity_specifics,
     bool is_folder) {
-  // TODO(pvalenzuela): Allow caller customization of the position integer.
   const string suffix = GenerateSyncableBookmarkHash(
       originator_cache_guid_, originator_client_item_id_);
   sync_pb::UniquePosition unique_position =
-      syncer::UniquePosition::FromInt64(0, suffix).ToProto();
+      syncer::UniquePosition::FromInt64(index_, suffix).ToProto();
 
   if (parent_id_.empty()) {
     parent_id_ =
diff --git a/components/sync/test/fake_server/bookmark_entity_builder.h b/components/sync/test/fake_server/bookmark_entity_builder.h
index 10cb784..ffb1b0bc1 100644
--- a/components/sync/test/fake_server/bookmark_entity_builder.h
+++ b/components/sync/test/fake_server/bookmark_entity_builder.h
@@ -29,6 +29,10 @@
   // the bookmark will be included in the bookmarks bar.
   void SetParentId(const std::string& parent_id);
 
+  // Sets the index of the bookmark to be built. If this is not called,
+  // the bookmark will be placed at index 0.
+  void SetIndex(int index);
+
   // Builds and returns a LoopbackServerEntity representing a bookmark. Returns
   // null if the entity could not be built.
   std::unique_ptr<syncer::LoopbackServerEntity> BuildBookmark(const GURL& url);
@@ -57,6 +61,9 @@
 
   // The ID of the parent bookmark folder.
   std::string parent_id_;
+
+  // The index of the bookmark folder within its siblings.
+  int index_ = 0;
 };
 
 }  // namespace fake_server
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.cc b/components/sync_bookmarks/bookmark_model_type_processor.cc
index 419b4ed..2068a1e 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -331,7 +331,7 @@
   NOTIMPLEMENTED();
 }
 
-void BookmarkModelTypeProcessor::RecordMemoryUsageHistogram() {
+void BookmarkModelTypeProcessor::RecordMemoryUsageAndCountsHistograms() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   NOTIMPLEMENTED();
 }
diff --git a/components/sync_bookmarks/bookmark_model_type_processor.h b/components/sync_bookmarks/bookmark_model_type_processor.h
index 96c9412..445d2d4 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -53,7 +53,7 @@
   void OnSyncStopping(syncer::SyncStopMetadataFate metadata_fate) override;
   void GetAllNodesForDebugging(AllNodesCallback callback) override;
   void GetStatusCountersForDebugging(StatusCountersCallback callback) override;
-  void RecordMemoryUsageHistogram() override;
+  void RecordMemoryUsageAndCountsHistograms() override;
 
   // Encodes all sync metadata into a string, representing a state that can be
   // restored via ModelReadyToSync() below.
diff --git a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index bbde8c3..917bbbe 100644
--- a/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/test/scoped_task_environment.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/sync/base/unique_position.h"
 #include "components/sync/driver/fake_sync_client.h"
 #include "components/sync/model/data_type_activation_request.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -38,11 +39,14 @@
   std::string server_tag;
 };
 
-syncer::UpdateResponseData CreateUpdateData(const BookmarkInfo& bookmark_info) {
+syncer::UpdateResponseData CreateUpdateResponseData(
+    const BookmarkInfo& bookmark_info,
+    const syncer::UniquePosition& unique_position) {
   syncer::EntityData data;
   data.id = bookmark_info.server_id;
   data.parent_id = bookmark_info.parent_id;
   data.server_defined_unique_tag = bookmark_info.server_tag;
+  data.unique_position = unique_position.ToProto();
 
   sync_pb::BookmarkSpecifics* bookmark_specifics =
       data.specifics.mutable_bookmark();
@@ -94,12 +98,17 @@
 void InitWithSyncedBookmarks(const std::vector<BookmarkInfo>& bookmarks,
                              BookmarkModelTypeProcessor* processor) {
   syncer::UpdateResponseDataList updates;
+  syncer::UniquePosition pos = syncer::UniquePosition::InitialPosition(
+      syncer::UniquePosition::RandomSuffix());
   // Add update for the permanent folder "Bookmarks bar".
   updates.push_back(
-      CreateUpdateData({kBookmarkBarId, std::string(), std::string(),
-                        kBookmarksRootId, kBookmarkBarTag}));
+      CreateUpdateResponseData({kBookmarkBarId, std::string(), std::string(),
+                                kBookmarksRootId, kBookmarkBarTag},
+                               pos));
   for (BookmarkInfo bookmark : bookmarks) {
-    updates.push_back(CreateUpdateData(bookmark));
+    pos = syncer::UniquePosition::After(pos,
+                                        syncer::UniquePosition::RandomSuffix());
+    updates.push_back(CreateUpdateResponseData(bookmark, pos));
   }
   // TODO(crbug.com/516866): Remove after a proper positioning for remote
   // updates is implemented. Reversing the updates because the sorting algorithm
@@ -110,17 +119,6 @@
   AssertState(processor, bookmarks);
 }
 
-syncer::UpdateResponseData CreateTombstone(const std::string& server_id) {
-  // EntityData is considered to represent a deletion if its
-  // specifics hasn't been set.
-  syncer::EntityData data;
-  data.id = server_id;
-
-  syncer::UpdateResponseData response_data;
-  response_data.entity = data.PassToPtr();
-  return response_data;
-}
-
 class TestSyncClient : public syncer::FakeSyncClient {
  public:
   explicit TestSyncClient(bookmarks::BookmarkModel* bookmark_model)
@@ -167,18 +165,25 @@
 };
 
 TEST_F(BookmarkModelTypeProcessorTest, ShouldUpdateModelAfterRemoteCreation) {
+  syncer::UniquePosition kRandomPosition =
+      syncer::UniquePosition::InitialPosition(
+          syncer::UniquePosition::RandomSuffix());
+
   syncer::UpdateResponseDataList updates;
   // Add update for the permanent folder "Bookmarks bar".
   updates.push_back(
-      CreateUpdateData({kBookmarkBarId, std::string(), std::string(),
-                        kBookmarksRootId, kBookmarkBarTag}));
+      CreateUpdateResponseData({kBookmarkBarId, std::string(), std::string(),
+                                kBookmarksRootId, kBookmarkBarTag},
+                               kRandomPosition));
 
   // Add update for another node under the bookmarks bar.
   const std::string kNodeId = "node_id";
   const std::string kTitle = "title";
   const std::string kUrl = "http://www.url.com";
-  updates.push_back(CreateUpdateData({kNodeId, kTitle, kUrl, kBookmarkBarId,
-                                      /*server_tag=*/std::string()}));
+  updates.push_back(
+      CreateUpdateResponseData({kNodeId, kTitle, kUrl, kBookmarkBarId,
+                                /*server_tag=*/std::string()},
+                               kRandomPosition));
 
   const bookmarks::BookmarkNode* bookmarkbar =
       bookmark_model()->bookmark_bar_node();
@@ -195,6 +200,9 @@
   const std::string kNodeId = "node_id";
   const std::string kTitle = "title";
   const std::string kUrl = "http://www.url.com";
+  syncer::UniquePosition kRandomPosition =
+      syncer::UniquePosition::InitialPosition(
+          syncer::UniquePosition::RandomSuffix());
 
   std::vector<BookmarkInfo> bookmarks = {
       {kNodeId, kTitle, kUrl, kBookmarkBarId, /*server_tag=*/std::string()}};
@@ -214,8 +222,9 @@
   const std::string kNewUrl = "http://www.new-url.com";
   syncer::UpdateResponseDataList updates;
   updates.push_back(
-      CreateUpdateData({kNodeId, kNewTitle, kNewUrl, kBookmarkBarId,
-                        /*server_tag=*/std::string()}));
+      CreateUpdateResponseData({kNodeId, kNewTitle, kNewUrl, kBookmarkBarId,
+                                /*server_tag=*/std::string()},
+                               kRandomPosition));
 
   processor()->OnUpdateReceived(CreateDummyModelTypeState(), updates);
 
@@ -230,6 +239,9 @@
   const std::string kNodeId = "node_id";
   const std::string kTitle = "title";
   const std::string kUrl = "http://www.url.com";
+  syncer::UniquePosition kRandomPosition =
+      syncer::UniquePosition::InitialPosition(
+          syncer::UniquePosition::RandomSuffix());
 
   std::vector<BookmarkInfo> bookmarks = {
       {kNodeId, kTitle, kUrl, kBookmarkBarId, /*server_tag=*/std::string()}};
@@ -244,81 +256,16 @@
 
   // Process an update for the same bookmark with the same data.
   syncer::UpdateResponseDataList updates;
-  updates.push_back(CreateUpdateData({kNodeId, kTitle, kUrl, kBookmarkBarId,
-                                      /*server_tag=*/std::string()}));
+  updates.push_back(
+      CreateUpdateResponseData({kNodeId, kTitle, kUrl, kBookmarkBarId,
+                                /*server_tag=*/std::string()},
+                               kRandomPosition));
   updates[0].response_version++;
 
   EXPECT_CALL(*schedule_save_closure(), Run());
   processor()->OnUpdateReceived(CreateDummyModelTypeState(), updates);
 }
 
-TEST_F(BookmarkModelTypeProcessorTest, ShouldUpdateModelAfterRemoteDelete) {
-  // Build this structure
-  // bookmark_bar
-  //  |- folder1
-  //      |- title1
-  //      |- title2
-  //  |- folder2
-  //      |- title3
-
-  // Then send delete updates in this order
-  // folder1 -> title2 -> title1
-  // to exercise the code of creating a |foster_parent|.
-
-  const std::string kTitle1 = "title1";
-  const std::string kTitle1Id = "title1Id";
-  const std::string kTitle2 = "title2";
-  const std::string kTitle2Id = "title2Id";
-  const std::string kTitle3 = "title3";
-  const std::string kTitle3Id = "title3Id";
-  const std::string kFolder1 = "folder1";
-  const std::string kFolder1Id = "folder1Id";
-  const std::string kFolder2 = "folder2";
-  const std::string kFolder2Id = "folder2Id";
-  const std::string kUrl = "http://www.url.com";
-
-  std::vector<BookmarkInfo> bookmarks = {
-      {kFolder1Id, kFolder1, /*url=*/std::string(), kBookmarkBarId,
-       /*server_tag=*/std::string()},
-      {kTitle1Id, kTitle1, kUrl, kFolder1Id, /*server_tag=*/std::string()},
-      {kTitle2Id, kTitle2, kUrl, kFolder1Id, /*server_tag=*/std::string()},
-      {kFolder2Id, kFolder2, /*url=*/std::string(), kBookmarkBarId,
-       /*server_tag=*/std::string()},
-      {kTitle3Id, kTitle3, kUrl, kFolder2Id, /*server_tag=*/std::string()},
-  };
-
-  InitWithSyncedBookmarks(bookmarks, processor());
-
-  const bookmarks::BookmarkNode* bookmarkbar =
-      bookmark_model()->bookmark_bar_node();
-
-  ASSERT_THAT(bookmarkbar->child_count(), Eq(2));
-  ASSERT_THAT(bookmarkbar->GetChild(0)->GetTitle(), Eq(ASCIIToUTF16(kFolder1)));
-  ASSERT_THAT(bookmarkbar->GetChild(0)->child_count(), Eq(2));
-  ASSERT_THAT(bookmarkbar->GetChild(1)->GetTitle(), Eq(ASCIIToUTF16(kFolder2)));
-  ASSERT_THAT(bookmarkbar->GetChild(1)->child_count(), Eq(1));
-  ASSERT_THAT(bookmarkbar->GetChild(1)->GetChild(0)->GetTitle(),
-              Eq(ASCIIToUTF16(kTitle3)));
-
-  // Process delete updates
-  syncer::UpdateResponseDataList updates;
-  updates.push_back(CreateTombstone(kTitle2Id));
-  updates.push_back(CreateTombstone(kTitle1Id));
-  updates.push_back(CreateTombstone(kFolder1Id));
-
-  processor()->OnUpdateReceived(CreateDummyModelTypeState(), updates);
-
-  // The structure should be
-  // bookmark_bar
-  //  |- folder2
-  //      |- title3
-  EXPECT_THAT(bookmarkbar->child_count(), Eq(1));
-  EXPECT_THAT(bookmarkbar->GetChild(0)->GetTitle(), Eq(ASCIIToUTF16(kFolder2)));
-  EXPECT_THAT(bookmarkbar->GetChild(0)->child_count(), Eq(1));
-  EXPECT_THAT(bookmarkbar->GetChild(0)->GetChild(0)->GetTitle(),
-              Eq(ASCIIToUTF16(kTitle3)));
-}
-
 TEST_F(BookmarkModelTypeProcessorTest, ShouldDecodeSyncMetadata) {
   const std::string kNodeId = "node_id1";
   const std::string kTitle = "title1";
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler.cc b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
index 14431c78..67ba6ef 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler.cc
@@ -13,6 +13,8 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/browser/bookmark_node.h"
+#include "components/sync/base/unique_position.h"
+#include "components/sync/protocol/unique_position.pb.h"
 
 namespace sync_bookmarks {
 
@@ -135,6 +137,26 @@
   }
 }
 
+int ComputeChildNodeIndex(const bookmarks::BookmarkNode* parent,
+                          const sync_pb::UniquePosition& unique_position,
+                          const SyncedBookmarkTracker* bookmark_tracker) {
+  const syncer::UniquePosition position =
+      syncer::UniquePosition::FromProto(unique_position);
+  for (int i = 0; i < parent->child_count(); ++i) {
+    const bookmarks::BookmarkNode* child = parent->GetChild(i);
+    const SyncedBookmarkTracker::Entity* child_entity =
+        bookmark_tracker->GetEntityForBookmarkNode(child);
+    DCHECK(child_entity);
+    const syncer::UniquePosition child_position =
+        syncer::UniquePosition::FromProto(
+            child_entity->metadata()->unique_position());
+    if (position.LessThan(child_position)) {
+      return i;
+    }
+  }
+  return parent->child_count();
+}
+
 }  // namespace
 
 BookmarkRemoteUpdatesHandler::BookmarkRemoteUpdatesHandler(
@@ -152,6 +174,7 @@
     // TODO(crbug.com/516866): Check |update_entity| for sanity.
     // 1. Has bookmark specifics or no specifics in case of delete.
     // 2. All meta info entries in the specifics have unique keys.
+    // 3. Unique position is valid.
     const SyncedBookmarkTracker::Entity* tracked_entity =
         bookmark_tracker_->GetEntityForSyncId(update_entity.id);
     if (update_entity.is_deleted()) {
@@ -288,12 +311,10 @@
                 << ", parent id = " << update_entity.parent_id;
     return;
   }
-  // TODO(crbug.com/516866): This code appends the code to the very end of the
-  // list of the children by assigning the index to the
-  // parent_node->child_count(). It should instead compute the exact using the
-  // unique position information of the new node as well as the siblings.
   const bookmarks::BookmarkNode* bookmark_node = CreateBookmarkNode(
-      update_entity, parent_node, bookmark_model_, parent_node->child_count());
+      update_entity, parent_node, bookmark_model_,
+      ComputeChildNodeIndex(parent_node, update_entity.unique_position,
+                            bookmark_tracker_));
   if (!bookmark_node) {
     // We ignore bookmarks we can't add.
     DLOG(ERROR) << "Failed to create bookmark node with title "
@@ -327,14 +348,36 @@
     // TODO(crbug.com/516866): Handle conflict resolution.
     return;
   }
-  if (tracked_entity->MatchesData(update_entity)) {
+
+  const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
+  const bookmarks::BookmarkNode* old_parent = node->parent();
+
+  const SyncedBookmarkTracker::Entity* new_parent_entity =
+      bookmark_tracker_->GetEntityForSyncId(update_entity.parent_id);
+  if (!new_parent_entity) {
+    DLOG(ERROR) << "Could not update node. Parent node doesn't exist: "
+                << update_entity.parent_id;
+    return;
+  }
+  const bookmarks::BookmarkNode* new_parent =
+      new_parent_entity->bookmark_node();
+  if (!new_parent) {
+    DLOG(ERROR)
+        << "Could not update node. Parent node has been deleted already.";
+    return;
+  }
+  // Node update could be either in the node data (e.g. title or
+  // unique_position), or it could be that the node has moved under another
+  // parent without any data change. Should check both the data and the parent
+  // to confirm that no updates to the model are needed.
+  if (tracked_entity->MatchesDataIgnoringParent(update_entity) &&
+      new_parent == old_parent) {
     bookmark_tracker_->Update(update_entity.id, update.response_version,
                               update_entity.modification_time,
                               update_entity.unique_position,
                               update_entity.specifics);
     return;
   }
-  const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
   if (update_entity.is_folder != node->is_folder()) {
     DLOG(ERROR) << "Could not update node. Remote node is a "
                 << (update_entity.is_folder ? "folder" : "bookmark")
@@ -351,13 +394,24 @@
   bookmark_model_->SetTitle(node, base::UTF8ToUTF16(specifics.title()));
   // TODO(crbug.com/516866): Add the favicon related code.
   bookmark_model_->SetNodeMetaInfoMap(node, GetBookmarkMetaInfo(update_entity));
+  // Compute index information before updating the |bookmark_tracker_|.
+  const int old_index = old_parent->GetIndexOf(node);
+  const int new_index = ComputeChildNodeIndex(
+      new_parent, update_entity.unique_position, bookmark_tracker_);
   bookmark_tracker_->Update(update_entity.id, update.response_version,
                             update_entity.modification_time,
                             update_entity.unique_position,
                             update_entity.specifics);
-  // TODO(crbug.com/516866): Handle reparenting.
-  // TODO(crbug.com/516866): Handle the case of moving the bookmark to a new
-  // position under the same parent (i.e. change in the unique position)
+
+  if (new_parent == old_parent &&
+      (new_index == old_index || new_index == old_index + 1)) {
+    // Node hasn't moved. No more work to do.
+    return;
+  }
+  // Node has moved to another position under the same parent. Update the model.
+  // BookmarkModel takes care of placing the node in the correct position if the
+  // node is move to the left. (i.e. no need to subtract one from |new_index|).
+  bookmark_model_->Move(node, new_parent, new_index);
 }
 
 void BookmarkRemoteUpdatesHandler::ProcessRemoteDelete(
diff --git a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
index 05085bc..5fa31bc 100644
--- a/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
+++ b/components/sync_bookmarks/bookmark_remote_updates_handler_unittest.cc
@@ -12,7 +12,10 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/sync/base/hash_util.h"
 #include "components/sync/base/model_type.h"
+#include "components/sync/base/unique_position.h"
+#include "components/sync/protocol/unique_position.pb.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,10 +36,12 @@
 syncer::UpdateResponseData CreateUpdateResponseData(
     const std::string& server_id,
     const std::string& parent_id,
-    bool is_deletion) {
+    bool is_deletion,
+    const syncer::UniquePosition& unique_position) {
   syncer::EntityData data;
   data.id = server_id;
   data.parent_id = parent_id;
+  data.unique_position = unique_position.ToProto();
 
   // EntityData would be considered a deletion if its specifics hasn't been set.
   if (!is_deletion) {
@@ -53,6 +58,17 @@
   return response_data;
 }
 
+// Overload that assign a random position. Should only be used when position
+// doesn't matter.
+syncer::UpdateResponseData CreateUpdateResponseData(
+    const std::string& server_id,
+    const std::string& parent_id,
+    bool is_deletion) {
+  return CreateUpdateResponseData(server_id, parent_id, is_deletion,
+                                  syncer::UniquePosition::InitialPosition(
+                                      syncer::UniquePosition::RandomSuffix()));
+}
+
 syncer::UpdateResponseData CreateBookmarkRootUpdateData() {
   syncer::EntityData data;
   data.id = syncer::ModelTypeToRootTag(syncer::BOOKMARKS);
@@ -84,6 +100,23 @@
   return response_data;
 }
 
+std::unique_ptr<sync_pb::EntityMetadata> CreateEntityMetadata(
+    const std::string& server_id,
+    const syncer::UniquePosition& unique_position) {
+  auto metadata = std::make_unique<sync_pb::EntityMetadata>();
+  metadata->set_server_id(server_id);
+  *metadata->mutable_unique_position() = unique_position.ToProto();
+  metadata->set_is_deleted(false);
+  return metadata;
+}
+
+std::unique_ptr<sync_pb::EntityMetadata> CreateEntityMetadata(
+    const std::string& server_id) {
+  return CreateEntityMetadata(server_id,
+                              syncer::UniquePosition::InitialPosition(
+                                  syncer::UniquePosition::RandomSuffix()));
+}
+
 TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest, ShouldIgnoreRootNodes) {
   syncer::UpdateResponseDataList updates;
   updates.push_back(CreateBookmarkRootUpdateData());
@@ -232,19 +265,13 @@
   const std::string kId1 = "id1";
   const std::string kId2 = "id2";
 
-  auto metadata0 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata0->set_server_id(kId0);
-
-  auto metadata1 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata1->set_server_id(kId1);
-
-  auto metadata2 = std::make_unique<sync_pb::EntityMetadata>();
-  metadata2->set_server_id(kId2);
-
   std::vector<NodeMetadataPair> node_metadata_pairs;
-  node_metadata_pairs.emplace_back(node0, std::move(metadata0));
-  node_metadata_pairs.emplace_back(node1, std::move(metadata1));
-  node_metadata_pairs.emplace_back(node2, std::move(metadata2));
+  node_metadata_pairs.emplace_back(node0,
+                                   CreateEntityMetadata(/*server_id=*/kId0));
+  node_metadata_pairs.emplace_back(node1,
+                                   CreateEntityMetadata(/*server_id=*/kId1));
+  node_metadata_pairs.emplace_back(node2,
+                                   CreateEntityMetadata(/*server_id=*/kId2));
 
   SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
                                 std::make_unique<sync_pb::ModelTypeState>());
@@ -268,6 +295,257 @@
   EXPECT_THAT(tracker.TrackedEntitiesCountForTest(), Eq(0U));
 }
 
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
+     ShouldPositionRemoteCreations) {
+  // Prepare creation updates to construct this structure:
+  // bookmark_bar
+  //  |- node0
+  //  |- node1
+  //  |- node2
+
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+  SyncedBookmarkTracker tracker(std::vector<NodeMetadataPair>(),
+                                std::make_unique<sync_pb::ModelTypeState>());
+
+  const std::string kId0 = "id0";
+  const std::string kId1 = "id1";
+  const std::string kId2 = "id2";
+
+  syncer::UniquePosition pos0 = syncer::UniquePosition::InitialPosition(
+      syncer::UniquePosition::RandomSuffix());
+  syncer::UniquePosition pos1 = syncer::UniquePosition::After(
+      pos0, syncer::UniquePosition::RandomSuffix());
+  syncer::UniquePosition pos2 = syncer::UniquePosition::After(
+      pos1, syncer::UniquePosition::RandomSuffix());
+
+  // Constuct the updates list to have creations randomly ordered.
+  syncer::UpdateResponseDataList updates;
+  updates.push_back(CreateBookmarkBarNodeUpdateData());
+  updates.push_back(CreateUpdateResponseData(
+      /*server_id=*/kId2, /*parent_id=*/kBookmarkBarId,
+      /*is_deletion=*/false, /*unique_position=*/pos2));
+  updates.push_back(CreateUpdateResponseData(/*server_id=*/kId0,
+                                             /*parent_id=*/kBookmarkBarId,
+                                             /*is_deletion=*/false,
+                                             /*unique_position=*/pos0));
+  updates.push_back(CreateUpdateResponseData(
+      /*server_id=*/kId1, /*parent_id=*/kBookmarkBarId,
+      /*is_deletion=*/false, /*unique_position=*/pos1));
+
+  BookmarkRemoteUpdatesHandler updates_handler(bookmark_model.get(), &tracker);
+  updates_handler.Process(updates);
+
+  // All nodes should have been added to the model in the correct order.
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+  ASSERT_THAT(bookmark_bar_node->child_count(), Eq(3));
+  EXPECT_THAT(bookmark_bar_node->GetChild(0)->GetTitle(),
+              Eq(ASCIIToUTF16(kId0)));
+  EXPECT_THAT(bookmark_bar_node->GetChild(1)->GetTitle(),
+              Eq(ASCIIToUTF16(kId1)));
+  EXPECT_THAT(bookmark_bar_node->GetChild(2)->GetTitle(),
+              Eq(ASCIIToUTF16(kId2)));
+}
+
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
+     ShouldPositionRemoteMovesToTheLeft) {
+  // Start with structure:
+  // bookmark_bar
+  //  |- node0
+  //  |- node1
+  //  |- node2
+  //  |- node3
+  //  |- node4
+
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+
+  std::vector<std::string> ids;
+  std::vector<const bookmarks::BookmarkNode*> nodes;
+  std::vector<syncer::UniquePosition> positions;
+  std::vector<NodeMetadataPair> node_metadata_pairs;
+  // Add the bookmark bar entry.
+  node_metadata_pairs.emplace_back(bookmark_bar_node,
+                                   CreateEntityMetadata(kBookmarkBarId));
+  syncer::UniquePosition position = syncer::UniquePosition::InitialPosition(
+      syncer::UniquePosition::RandomSuffix());
+  for (int i = 0; i < 5; i++) {
+    ids.push_back("node" + base::NumberToString(i));
+    // Use ids as node titles for simplcity and to match CreateEntityMetadata()
+    // implementation.
+    nodes.push_back(bookmark_model->AddFolder(
+        /*parent=*/bookmark_bar_node, /*index=*/i, base::UTF8ToUTF16(ids[i])));
+    position = syncer::UniquePosition::After(
+        position, syncer::UniquePosition::RandomSuffix());
+    positions.push_back(position);
+    node_metadata_pairs.emplace_back(
+        nodes[i], CreateEntityMetadata(ids[i], positions[i]));
+  }
+
+  SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
+                                std::make_unique<sync_pb::ModelTypeState>());
+  // Change it to this structure by moving node3 after node1.
+  // bookmark_bar
+  //  |- node0
+  //  |- node1
+  //  |- node3
+  //  |- node2
+  //  |- node4
+
+  syncer::UpdateResponseDataList updates;
+  updates.push_back(CreateUpdateResponseData(
+      /*server_id=*/ids[3],
+      /*parent_id=*/kBookmarkBarId,
+      /*is_deletion=*/false,
+      /*unique_position=*/
+      syncer::UniquePosition::Between(positions[1], positions[2],
+                                      syncer::UniquePosition::RandomSuffix())));
+
+  BookmarkRemoteUpdatesHandler updates_handler(bookmark_model.get(), &tracker);
+  updates_handler.Process(updates);
+
+  // Model should have been updated.
+  ASSERT_THAT(bookmark_bar_node->child_count(), Eq(5));
+  EXPECT_THAT(bookmark_bar_node->GetChild(2)->GetTitle(),
+              Eq(ASCIIToUTF16(ids[3])));
+}
+
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
+     ShouldPositionRemoteMovesToTheRight) {
+  // Start with structure:
+  // bookmark_bar
+  //  |- node0
+  //  |- node1
+  //  |- node2
+  //  |- node3
+  //  |- node4
+
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+
+  std::vector<std::string> ids;
+  std::vector<const bookmarks::BookmarkNode*> nodes;
+  std::vector<syncer::UniquePosition> positions;
+  std::vector<NodeMetadataPair> node_metadata_pairs;
+  // Add the bookmark bar entry.
+  node_metadata_pairs.emplace_back(bookmark_bar_node,
+                                   CreateEntityMetadata(kBookmarkBarId));
+  syncer::UniquePosition position = syncer::UniquePosition::InitialPosition(
+      syncer::UniquePosition::RandomSuffix());
+  for (int i = 0; i < 5; i++) {
+    ids.push_back("node" + base::NumberToString(i));
+    // Use ids as node titles for simplcity and to match CreateEntityMetadata()
+    // implementation.
+    nodes.push_back(bookmark_model->AddFolder(
+        /*parent=*/bookmark_bar_node, /*index=*/i, base::UTF8ToUTF16(ids[i])));
+    position = syncer::UniquePosition::After(
+        position, syncer::UniquePosition::RandomSuffix());
+    positions.push_back(position);
+    node_metadata_pairs.emplace_back(
+        nodes[i], CreateEntityMetadata(ids[i], positions[i]));
+  }
+
+  SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
+                                std::make_unique<sync_pb::ModelTypeState>());
+
+  // Change it to this structure by moving node1 after node3.
+  // bookmark_bar
+  //  |- node0
+  //  |- node2
+  //  |- node3
+  //  |- node1
+  //  |- node4
+
+  syncer::UpdateResponseDataList updates;
+  updates.push_back(CreateUpdateResponseData(
+      /*server_id=*/ids[1],
+      /*parent_id=*/kBookmarkBarId,
+      /*is_deletion=*/false,
+      /*unique_position=*/
+      syncer::UniquePosition::Between(positions[3], positions[4],
+                                      syncer::UniquePosition::RandomSuffix())));
+
+  BookmarkRemoteUpdatesHandler updates_handler(bookmark_model.get(), &tracker);
+  updates_handler.Process(updates);
+
+  // Model should have been updated.
+  ASSERT_THAT(bookmark_bar_node->child_count(), Eq(5));
+  EXPECT_THAT(bookmark_bar_node->GetChild(3)->GetTitle(),
+              Eq(ASCIIToUTF16(ids[1])));
+}
+
+TEST(BookmarkRemoteUpdatesHandlerReorderUpdatesTest,
+     ShouldPositionRemoteReparenting) {
+  // Start with structure:
+  // bookmark_bar
+  //  |- node0
+  //  |- node1
+  //  |- node2
+  //  |- node3
+  //  |- node4
+
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model =
+      bookmarks::TestBookmarkClient::CreateModel();
+  const bookmarks::BookmarkNode* bookmark_bar_node =
+      bookmark_model->bookmark_bar_node();
+
+  std::vector<std::string> ids;
+  std::vector<const bookmarks::BookmarkNode*> nodes;
+  std::vector<syncer::UniquePosition> positions;
+  std::vector<NodeMetadataPair> node_metadata_pairs;
+  // Add the bookmark bar entry.
+  node_metadata_pairs.emplace_back(bookmark_bar_node,
+                                   CreateEntityMetadata(kBookmarkBarId));
+  syncer::UniquePosition position = syncer::UniquePosition::InitialPosition(
+      syncer::UniquePosition::RandomSuffix());
+  for (int i = 0; i < 5; i++) {
+    ids.push_back("node" + base::NumberToString(i));
+    // Use ids as node titles for simplcity and to match CreateEntityMetadata()
+    // implementation.
+    nodes.push_back(bookmark_model->AddFolder(
+        /*parent=*/bookmark_bar_node, /*index=*/i, base::UTF8ToUTF16(ids[i])));
+    position = syncer::UniquePosition::After(
+        position, syncer::UniquePosition::RandomSuffix());
+    positions.push_back(position);
+    node_metadata_pairs.emplace_back(
+        nodes[i], CreateEntityMetadata(ids[i], positions[i]));
+  }
+
+  SyncedBookmarkTracker tracker(std::move(node_metadata_pairs),
+                                std::make_unique<sync_pb::ModelTypeState>());
+
+  // Change it to this structure by moving node4 under node1.
+  // bookmark_bar
+  //  |- node0
+  //  |- node1
+  //    |- node4
+  //  |- node2
+  //  |- node3
+
+  syncer::UpdateResponseDataList updates;
+  updates.push_back(CreateUpdateResponseData(
+      /*server_id=*/ids[4],
+      /*parent_id=*/ids[1],
+      /*is_deletion=*/false,
+      /*unique_position=*/
+      syncer::UniquePosition::InitialPosition(
+          syncer::UniquePosition::RandomSuffix())));
+
+  BookmarkRemoteUpdatesHandler updates_handler(bookmark_model.get(), &tracker);
+  updates_handler.Process(updates);
+
+  // Model should have been updated.
+  ASSERT_THAT(bookmark_bar_node->child_count(), Eq(4));
+  ASSERT_THAT(bookmark_bar_node->GetChild(1)->child_count(), Eq(1));
+  EXPECT_THAT(bookmark_bar_node->GetChild(1)->GetChild(0)->GetTitle(),
+              Eq(ASCIIToUTF16(ids[4])));
+}
+
 }  // namespace
 
 }  // namespace sync_bookmarks
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.cc b/components/sync_bookmarks/synced_bookmark_tracker.cc
index c0d6a8be..bfc9fb9 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -11,6 +11,7 @@
 #include "base/sha1.h"
 #include "components/bookmarks/browser/bookmark_node.h"
 #include "components/sync/base/time.h"
+#include "components/sync/base/unique_position.h"
 #include "components/sync/model/entity_data.h"
 
 namespace sync_bookmarks {
@@ -42,15 +43,18 @@
   return metadata_->sequence_number() > metadata_->acked_sequence_number();
 }
 
-bool SyncedBookmarkTracker::Entity::MatchesData(
+bool SyncedBookmarkTracker::Entity::MatchesDataIgnoringParent(
     const syncer::EntityData& data) const {
-  // TODO(crbug.com/516866): Check parent id and unique position.
   // TODO(crbug.com/516866): Compare the actual specifics instead of the
   // specifics hash.
   if (metadata_->is_deleted() || data.is_deleted()) {
     // In case of deletion, no need to check the specifics.
     return metadata_->is_deleted() == data.is_deleted();
   }
+  if (!syncer::UniquePosition::FromProto(metadata_->unique_position())
+           .Equals(syncer::UniquePosition::FromProto(data.unique_position))) {
+    return false;
+  }
   return MatchesSpecificsHash(data.specifics);
 }
 
@@ -214,7 +218,6 @@
 
 std::vector<const SyncedBookmarkTracker::Entity*>
 SyncedBookmarkTracker::GetEntitiesWithLocalChanges(size_t max_entries) const {
-  // TODO(crbug.com/516866): Return no more than |max_entries| after sorting.
   std::vector<const SyncedBookmarkTracker::Entity*> entities_with_local_changes;
   // Entities with local non deletions should be sorted such that parent
   // creation/update comes before child creation/update.
@@ -235,6 +238,13 @@
   for (const Entity* tombstone_entity : ordered_local_tombstones_) {
     ordered_local_changes.push_back(tombstone_entity);
   }
+  if (ordered_local_changes.size() > max_entries) {
+    // TODO(crbug.com/516866): Should be smart and stop building the vector
+    // when |max_entries| is reached.
+    return std::vector<const SyncedBookmarkTracker::Entity*>(
+        ordered_local_changes.begin(),
+        ordered_local_changes.begin() + max_entries);
+  }
   return ordered_local_changes;
 }
 
diff --git a/components/sync_bookmarks/synced_bookmark_tracker.h b/components/sync_bookmarks/synced_bookmark_tracker.h
index 32d12cd..9ac1abc 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker.h
+++ b/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -47,8 +47,9 @@
     // A commit may or may not be in progress at this time.
     bool IsUnsynced() const;
 
-    // Check whether |data| matches the stored specifics hash.
-    bool MatchesData(const syncer::EntityData& data) const;
+    // Check whether |data| matches the stored specifics hash. It ignores parent
+    // information.
+    bool MatchesDataIgnoringParent(const syncer::EntityData& data) const;
 
     // Returns null for tomstones.
     const bookmarks::BookmarkNode* bookmark_node() const {
diff --git a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
index c432191..d609420c 100644
--- a/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
+++ b/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -74,7 +74,8 @@
 
   syncer::EntityData data;
   *data.specifics.mutable_bookmark() = specifics.bookmark();
-  EXPECT_TRUE(entity->MatchesData(data));
+  data.unique_position = unique_position.ToProto();
+  EXPECT_TRUE(entity->MatchesDataIgnoringParent(data));
   EXPECT_THAT(tracker.GetEntityForSyncId("unknown id"), IsNull());
 }
 
diff --git a/components/sync_sessions/session_model_type_controller.cc b/components/sync_sessions/session_model_type_controller.cc
index 4d09e0a..e42c41d 100644
--- a/components/sync_sessions/session_model_type_controller.cc
+++ b/components/sync_sessions/session_model_type_controller.cc
@@ -4,6 +4,8 @@
 
 #include "components/sync_sessions/session_model_type_controller.h"
 
+#include <utility>
+
 #include "components/prefs/pref_service.h"
 #include "components/sync/driver/sync_client.h"
 
@@ -11,9 +13,9 @@
 
 SessionModelTypeController::SessionModelTypeController(
     syncer::SyncClient* sync_client,
-    const scoped_refptr<base::SingleThreadTaskRunner>& model_thread,
+    std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate,
     const std::string& history_disabled_pref_name)
-    : ModelTypeController(syncer::SESSIONS, sync_client, model_thread),
+    : ModelTypeController(syncer::SESSIONS, std::move(delegate), sync_client),
       history_disabled_pref_name_(history_disabled_pref_name) {
   pref_registrar_.Init(sync_client->GetPrefService());
   pref_registrar_.Add(
diff --git a/components/sync_sessions/session_model_type_controller.h b/components/sync_sessions/session_model_type_controller.h
index cea1992a..d854c002 100644
--- a/components/sync_sessions/session_model_type_controller.h
+++ b/components/sync_sessions/session_model_type_controller.h
@@ -5,11 +5,10 @@
 #ifndef COMPONENTS_SYNC_SESSIONS_SESSION_MODEL_TYPE_CONTROLLER_H_
 #define COMPONENTS_SYNC_SESSIONS_SESSION_MODEL_TYPE_CONTROLLER_H_
 
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/single_thread_task_runner.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/sync/driver/model_type_controller.h"
 
@@ -24,7 +23,7 @@
  public:
   SessionModelTypeController(
       syncer::SyncClient* sync_client,
-      const scoped_refptr<base::SingleThreadTaskRunner>& model_thread,
+      std::unique_ptr<syncer::ModelTypeControllerDelegate> delegate,
       const std::string& history_disabled_pref_name);
   ~SessionModelTypeController() override;
 
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper.cc b/components/unified_consent/url_keyed_data_collection_consent_helper.cc
index 6ad5213..067b9592 100644
--- a/components/unified_consent/url_keyed_data_collection_consent_helper.cc
+++ b/components/unified_consent/url_keyed_data_collection_consent_helper.cc
@@ -26,6 +26,7 @@
 
   // UrlKeyedDataCollectionConsentHelper:
   bool IsEnabled() override;
+  bool IsShutDown() override;
 
  private:
   void OnPrefChanged();
@@ -46,6 +47,7 @@
 
   // UrlKeyedDataCollectionConsentHelper:
   bool IsEnabled() override;
+  bool IsShutDown() override;
 
   // syncer::SyncServiceObserver:
   void OnStateChanged(syncer::SyncService* sync) override;
@@ -75,6 +77,10 @@
       prefs::kUrlKeyedAnonymizedDataCollectionEnabled);
 }
 
+bool PrefBasedUrlKeyedDataCollectionConsentHelper::IsShutDown() {
+  return false;
+}
+
 void PrefBasedUrlKeyedDataCollectionConsentHelper::OnPrefChanged() {
   FireOnStateChanged();
 }
@@ -103,6 +109,10 @@
   return sync_data_type_upload_state_ == syncer::UploadState::ACTIVE;
 }
 
+bool SyncBasedUrlKeyedDataCollectionConsentHelper::IsShutDown() {
+  return !sync_service_;
+}
+
 void SyncBasedUrlKeyedDataCollectionConsentHelper::OnStateChanged(
     syncer::SyncService* sync_service) {
   DCHECK_EQ(sync_service_, sync_service);
@@ -117,8 +127,11 @@
 void SyncBasedUrlKeyedDataCollectionConsentHelper::OnSyncShutdown(
     syncer::SyncService* sync_service) {
   DCHECK_EQ(sync_service_, sync_service);
+  DCHECK_EQ(syncer::UploadState::NOT_ACTIVE, sync_data_type_upload_state_);
+
   sync_service_->RemoveObserver(this);
   sync_service_ = nullptr;
+  FireOnShutDown();
 }
 
 }  // namespace
@@ -167,4 +180,9 @@
     observer.OnUrlKeyedDataCollectionConsentStateChanged(this);
 }
 
+void UrlKeyedDataCollectionConsentHelper::FireOnShutDown() {
+  for (auto& observer : observer_list_)
+    observer.OnUrlKeyedDataCollectionConsentHelperShutDown(this);
+}
+
 }  // namespace unified_consent
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper.h b/components/unified_consent/url_keyed_data_collection_consent_helper.h
index f4d8486..455883a1 100644
--- a/components/unified_consent/url_keyed_data_collection_consent_helper.h
+++ b/components/unified_consent/url_keyed_data_collection_consent_helper.h
@@ -25,6 +25,12 @@
     // Called when the state of the URL-keyed data collection changes.
     virtual void OnUrlKeyedDataCollectionConsentStateChanged(
         UrlKeyedDataCollectionConsentHelper* consent_helper) = 0;
+
+    // Called when |consent_helper| is shut down.
+    // See UrlKeyedDataCollectionConsentHelper::IsShutDown for more information
+    // on when a UrlKeyedDataCollectionConsentHelper is shut down.
+    virtual void OnUrlKeyedDataCollectionConsentHelperShutDown(
+        UrlKeyedDataCollectionConsentHelper* consent_helper){};
   };
 
   // Creates a new |UrlKeyedDataCollectionConsentHelper| instance that checks
@@ -67,6 +73,16 @@
   // collection.
   virtual bool IsEnabled() = 0;
 
+  // Returns true if this UrlKeyedDataCollectionConsentHelper was shut down.
+  // For sync backed implementations of consent helper, this matches the state
+  // when the underlying sync service was shut down.
+  //
+  // When |UrlKeyedDataCollectionConsentHelper| is shut down, it is guaranteed
+  // that calls to |IsEnabled| will always return false.
+  // |UrlKeyedDataCollectionConsentHelper| that are shut down will never again
+  // become active.
+  virtual bool IsShutDown() = 0;
+
   // Methods to register or remove observers.
   void AddObserver(Observer* observer);
   void RemoveObserver(Observer* observer);
@@ -77,6 +93,9 @@
   // Fires |OnUrlKeyedDataCollectionConsentStateChanged| on all the observers.
   void FireOnStateChanged();
 
+  // Fires |OnUrlKeyedDataCollectionConsentHelperShutDown| on all the observers.
+  void FireOnShutDown();
+
  private:
   base::ObserverList<Observer, true> observer_list_;
 
diff --git a/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc b/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc
index d677ccb..70d0c70 100644
--- a/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc
+++ b/components/unified_consent/url_keyed_data_collection_consent_helper_unittest.cc
@@ -28,6 +28,10 @@
     for (auto& observer : observers_)
       observer.OnStateChanged(this);
   }
+  void FireOnSyncShutdownOnAllObservers() {
+    for (auto& observer : observers_)
+      observer.OnSyncShutdown(this);
+  }
 
   // syncer::FakeSyncService:
   int GetDisableReasons() const override { return DISABLE_REASON_NONE; }
@@ -83,12 +87,18 @@
 
   void OnUrlKeyedDataCollectionConsentStateChanged(
       UrlKeyedDataCollectionConsentHelper* consent_helper) override {
-    state_changed_notifications.push_back(consent_helper->IsEnabled());
+    state_changed_notifications_.push_back(consent_helper->IsEnabled());
+  }
+
+  void OnUrlKeyedDataCollectionConsentHelperShutDown(
+      UrlKeyedDataCollectionConsentHelper* consent_helper) override {
+    shutdown_notifications_.push_back(consent_helper->IsShutDown());
   }
 
  protected:
   sync_preferences::TestingPrefServiceSyncable pref_service_;
-  std::vector<bool> state_changed_notifications;
+  std::vector<bool> state_changed_notifications_;
+  std::vector<bool> shutdown_notifications_;
   TestSyncService sync_service_;
 };
 
@@ -100,20 +110,20 @@
                                                    &sync_service_);
   helper->AddObserver(this);
   EXPECT_FALSE(helper->IsEnabled());
-  EXPECT_TRUE(state_changed_notifications.empty());
+  EXPECT_TRUE(state_changed_notifications_.empty());
 
   pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
                            true);
   EXPECT_TRUE(helper->IsEnabled());
-  ASSERT_EQ(1U, state_changed_notifications.size());
-  EXPECT_TRUE(state_changed_notifications[0]);
+  ASSERT_EQ(1U, state_changed_notifications_.size());
+  EXPECT_TRUE(state_changed_notifications_[0]);
 
-  state_changed_notifications.clear();
+  state_changed_notifications_.clear();
   pref_service_.SetBoolean(prefs::kUrlKeyedAnonymizedDataCollectionEnabled,
                            false);
   EXPECT_FALSE(helper->IsEnabled());
-  ASSERT_EQ(1U, state_changed_notifications.size());
-  EXPECT_FALSE(state_changed_notifications[0]);
+  ASSERT_EQ(1U, state_changed_notifications_.size());
+  EXPECT_FALSE(state_changed_notifications_[0]);
   helper->RemoveObserver(this);
 }
 
@@ -125,14 +135,14 @@
                                                    &sync_service_);
   helper->AddObserver(this);
   EXPECT_FALSE(helper->IsEnabled());
-  EXPECT_TRUE(state_changed_notifications.empty());
+  EXPECT_TRUE(state_changed_notifications_.empty());
 
   sync_service_.set_sync_initialized(true);
   sync_service_.set_sync_active_data_type(
       syncer::ModelType::HISTORY_DELETE_DIRECTIVES);
   sync_service_.FireOnStateChangeOnAllObservers();
   EXPECT_TRUE(helper->IsEnabled());
-  ASSERT_EQ(1U, state_changed_notifications.size());
+  ASSERT_EQ(1U, state_changed_notifications_.size());
   helper->RemoveObserver(this);
 }
 
@@ -153,13 +163,13 @@
           NewPersonalizedDataCollectionConsentHelper(true, &sync_service_);
   helper->AddObserver(this);
   EXPECT_FALSE(helper->IsEnabled());
-  EXPECT_TRUE(state_changed_notifications.empty());
+  EXPECT_TRUE(state_changed_notifications_.empty());
 
   sync_service_.set_sync_initialized(true);
   sync_service_.set_sync_active_data_type(syncer::ModelType::USER_EVENTS);
   sync_service_.FireOnStateChangeOnAllObservers();
   EXPECT_TRUE(helper->IsEnabled());
-  ASSERT_EQ(1U, state_changed_notifications.size());
+  ASSERT_EQ(1U, state_changed_notifications_.size());
   helper->RemoveObserver(this);
 }
 
@@ -170,34 +180,44 @@
           NewPersonalizedDataCollectionConsentHelper(false, &sync_service_);
   helper->AddObserver(this);
   EXPECT_FALSE(helper->IsEnabled());
-  EXPECT_TRUE(state_changed_notifications.empty());
+  EXPECT_TRUE(state_changed_notifications_.empty());
 
   sync_service_.set_sync_initialized(true);
   sync_service_.set_sync_active_data_type(
       syncer::ModelType::HISTORY_DELETE_DIRECTIVES);
   sync_service_.FireOnStateChangeOnAllObservers();
   EXPECT_TRUE(helper->IsEnabled());
-  ASSERT_EQ(1U, state_changed_notifications.size());
+  ASSERT_EQ(1U, state_changed_notifications_.size());
   helper->RemoveObserver(this);
 }
 
 TEST_F(UrlKeyedDataCollectionConsentHelperTest,
        PersonalizedDataCollection_NullSyncService) {
-  {
+  for (bool is_unified_consent_enabled : {true, false}) {
     std::unique_ptr<UrlKeyedDataCollectionConsentHelper> helper =
         UrlKeyedDataCollectionConsentHelper::
             NewPersonalizedDataCollectionConsentHelper(
-                false /* is_unified_consent_enabled */,
-                nullptr /* sync_service */);
+                is_unified_consent_enabled, nullptr /* sync_service */);
     EXPECT_FALSE(helper->IsEnabled());
+    EXPECT_TRUE(helper->IsShutDown());
   }
-  {
+}
+
+TEST_F(UrlKeyedDataCollectionConsentHelperTest,
+       PersonalizedDataCollection_ShutDown) {
+  for (bool is_unified_consent_enabled : {true, false}) {
+    ASSERT_TRUE(shutdown_notifications_.empty());
     std::unique_ptr<UrlKeyedDataCollectionConsentHelper> helper =
         UrlKeyedDataCollectionConsentHelper::
             NewPersonalizedDataCollectionConsentHelper(
-                true /* is_unified_consent_enabled */,
-                nullptr /* sync_service */);
-    EXPECT_FALSE(helper->IsEnabled());
+                is_unified_consent_enabled, &sync_service_);
+    helper->AddObserver(this);
+    EXPECT_FALSE(helper->IsShutDown());
+    sync_service_.FireOnSyncShutdownOnAllObservers();
+    EXPECT_TRUE(helper->IsShutDown());
+    EXPECT_EQ(1U, shutdown_notifications_.size());
+    helper->RemoveObserver(this);
+    shutdown_notifications_.clear();
   }
 }
 
diff --git a/components/version_ui/resources/about_version.css b/components/version_ui/resources/about_version.css
index 2e744ed5..7c247b6 100644
--- a/components/version_ui/resources/about_version.css
+++ b/components/version_ui/resources/about_version.css
@@ -23,9 +23,9 @@
 }
 
 .label {
-  -webkit-padding-end: 5px;
   font-size: 0.9em;
   font-weight: bold;
+  padding-inline-end: 5px;
   text-align: end;
   vertical-align: top;
   white-space: nowrap;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 6d90f4f..71ba3c44 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -580,6 +580,8 @@
     "cocoa/system_hotkey_map.mm",
     "code_cache/generated_code_cache.cc",
     "code_cache/generated_code_cache.h",
+    "code_cache/generated_code_cache_context.cc",
+    "code_cache/generated_code_cache_context.h",
     "startup_data_impl.cc",
     "startup_data_impl.h",
 
diff --git a/content/browser/appcache/appcache_disk_cache.cc b/content/browser/appcache/appcache_disk_cache.cc
index 8c28d1862..98c1a5a 100644
--- a/content/browser/appcache/appcache_disk_cache.cc
+++ b/content/browser/appcache/appcache_disk_cache.cc
@@ -127,7 +127,7 @@
         new ActiveCall(owner, entry, callback));
     int rv = owner->disk_cache()->CreateEntry(
         base::Int64ToString(key), net::HIGHEST, &active_call->entry_ptr_,
-        base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+        base::BindOnce(&ActiveCall::OnAsyncCompletion, active_call));
     return active_call->HandleImmediateReturnValue(rv);
   }
 
@@ -139,7 +139,7 @@
         new ActiveCall(owner, entry, callback));
     int rv = owner->disk_cache()->OpenEntry(
         base::Int64ToString(key), net::HIGHEST, &active_call->entry_ptr_,
-        base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+        base::BindOnce(&ActiveCall::OnAsyncCompletion, active_call));
     return active_call->HandleImmediateReturnValue(rv);
   }
 
@@ -150,7 +150,7 @@
         new ActiveCall(owner, nullptr, callback));
     int rv = owner->disk_cache()->DoomEntry(
         base::Int64ToString(key), net::HIGHEST,
-        base::Bind(&ActiveCall::OnAsyncCompletion, active_call));
+        base::BindOnce(&ActiveCall::OnAsyncCompletion, active_call));
     return active_call->HandleImmediateReturnValue(rv);
   }
 
@@ -347,8 +347,8 @@
       cache_directory, cache_size, force, nullptr,
       &(create_backend_callback_->backend_ptr_),
       std::move(post_cleanup_callback),
-      base::Bind(&CreateBackendCallbackShim::Callback,
-                 create_backend_callback_));
+      base::BindOnce(&CreateBackendCallbackShim::Callback,
+                     create_backend_callback_));
   if (rv == net::ERR_IO_PENDING)
     init_callback_ = callback;
   else
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc
index 7f291f9..65cc571 100644
--- a/content/browser/appcache/appcache_request_handler.cc
+++ b/content/browser/appcache/appcache_request_handler.cc
@@ -222,17 +222,17 @@
 
 // static
 std::unique_ptr<AppCacheRequestHandler>
-AppCacheRequestHandler::InitializeForNavigationNetworkService(
+AppCacheRequestHandler::InitializeForMainResourceNetworkService(
     const network::ResourceRequest& request,
-    AppCacheNavigationHandleCore* appcache_handle_core,
+    base::WeakPtr<AppCacheHost> appcache_host,
     scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory) {
   std::unique_ptr<AppCacheRequestHandler> handler =
-      appcache_handle_core->host()->CreateRequestHandler(
+      appcache_host->CreateRequestHandler(
           AppCacheURLLoaderRequest::Create(request),
           static_cast<ResourceType>(request.resource_type),
           request.should_reset_appcache);
   handler->network_loader_factory_ = std::move(network_loader_factory);
-  handler->appcache_host_ = appcache_handle_core->host()->GetWeakPtr();
+  handler->appcache_host_ = std::move(appcache_host);
   return handler;
 }
 
diff --git a/content/browser/appcache/appcache_request_handler.h b/content/browser/appcache/appcache_request_handler.h
index b8b8266..3b369c7 100644
--- a/content/browser/appcache/appcache_request_handler.h
+++ b/content/browser/appcache/appcache_request_handler.h
@@ -33,7 +33,6 @@
 
 namespace content {
 class AppCacheJob;
-class AppCacheNavigationHandleCore;
 class AppCacheSubresourceURLFactory;
 class AppCacheRequest;
 class AppCacheRequestHandlerTest;
@@ -106,9 +105,9 @@
                                       LoaderCallback callback);
 
   static std::unique_ptr<AppCacheRequestHandler>
-  InitializeForNavigationNetworkService(
+  InitializeForMainResourceNetworkService(
       const network::ResourceRequest& request,
-      AppCacheNavigationHandleCore* appcache_handle_core,
+      base::WeakPtr<AppCacheHost> appcache_host,
       scoped_refptr<network::SharedURLLoaderFactory> network_loader_factory);
 
   static bool IsMainResourceType(ResourceType type) {
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc
index b700384..79a5f2a 100644
--- a/content/browser/appcache/appcache_storage_impl.cc
+++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -1975,8 +1975,8 @@
   const base::TimeDelta kDelay = base::TimeDelta::FromMinutes(5);
   lazy_commit_timer_.Start(
       FROM_HERE, kDelay,
-      base::Bind(&AppCacheStorageImpl::OnLazyCommitTimer,
-                 weak_factory_.GetWeakPtr()));
+      base::BindOnce(&AppCacheStorageImpl::OnLazyCommitTimer,
+                     weak_factory_.GetWeakPtr()));
 }
 
 void AppCacheStorageImpl::OnLazyCommitTimer() {
diff --git a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
index 2f95096b..a82100f 100644
--- a/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
+++ b/content/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -321,7 +321,7 @@
   }
 
   void GetChannelIDList(net::ChannelIDStore::ChannelIDList* channel_ids) {
-    GetChannelIDStore()->GetAllChannelIDs(base::Bind(
+    GetChannelIDStore()->GetAllChannelIDs(base::BindOnce(
         &RemoveChannelIDTester::GetAllChannelIDsCallback, channel_ids));
   }
 
diff --git a/content/browser/browsing_data/conditional_cache_deletion_helper.cc b/content/browser/browsing_data/conditional_cache_deletion_helper.cc
index fcaa95d6..d0a5a8e 100644
--- a/content/browser/browsing_data/conditional_cache_deletion_helper.cc
+++ b/content/browser/browsing_data/conditional_cache_deletion_helper.cc
@@ -85,8 +85,8 @@
     previous_entry_ = current_entry_;
     error = iterator_->OpenNextEntry(
         &current_entry_,
-        base::Bind(&ConditionalCacheDeletionHelper::IterateOverEntries,
-                   base::Unretained(this)));
+        base::BindOnce(&ConditionalCacheDeletionHelper::IterateOverEntries,
+                       base::Unretained(this)));
   }
 }
 
diff --git a/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc b/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
index df1debd..a6551a0 100644
--- a/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
+++ b/content/browser/browsing_data/storage_partition_http_cache_data_remover.cc
@@ -9,8 +9,11 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/browser/browsing_data/conditional_cache_deletion_helper.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/http_cache.h"
 #include "net/url_request/url_request_context.h"
@@ -24,12 +27,14 @@
     base::Time delete_begin,
     base::Time delete_end,
     net::URLRequestContextGetter* main_context_getter,
-    net::URLRequestContextGetter* media_context_getter)
+    net::URLRequestContextGetter* media_context_getter,
+    GeneratedCodeCacheContext* generated_code_cache_context)
     : url_predicate_(url_predicate),
       delete_begin_(delete_begin),
       delete_end_(delete_end),
       main_context_getter_(main_context_getter),
       media_context_getter_(media_context_getter),
+      generated_code_cache_context_(generated_code_cache_context),
       next_cache_state_(CacheState::NONE),
       cache_(nullptr) {}
 
@@ -42,7 +47,8 @@
   return new StoragePartitionHttpCacheDataRemover(
       base::Callback<bool(const GURL&)>(),  // Null callback.
       delete_begin, delete_end, storage_partition->GetURLRequestContext(),
-      storage_partition->GetMediaURLRequestContext());
+      storage_partition->GetMediaURLRequestContext(),
+      storage_partition->GetGeneratedCodeCacheContext());
 }
 
 // static.
@@ -55,7 +61,8 @@
   return new StoragePartitionHttpCacheDataRemover(
       url_predicate, delete_begin, delete_end,
       storage_partition->GetURLRequestContext(),
-      storage_partition->GetMediaURLRequestContext());
+      storage_partition->GetMediaURLRequestContext(),
+      storage_partition->GetGeneratedCodeCacheContext());
 }
 
 StoragePartitionHttpCacheDataRemover::~StoragePartitionHttpCacheDataRemover() {}
@@ -90,7 +97,8 @@
 
 // The expected state sequence is CacheState::NONE --> CacheState::CREATE_MAIN
 // --> CacheState::DELETE_MAIN --> CacheState::CREATE_MEDIA -->
-// CacheState::DELETE_MEDIA --> CacheState::DONE, and any errors are ignored.
+// CacheState::DELETE_MEDIA --> CacheState::DELETE_CODE --> CacheState::DONE,
+// and any errors are ignored.
 void StoragePartitionHttpCacheDataRemover::DoClearCache(int rv) {
   DCHECK_NE(CacheState::NONE, next_cache_state_);
 
@@ -108,7 +116,7 @@
         if (!getter) {
           next_cache_state_ = (next_cache_state_ == CacheState::CREATE_MAIN)
                                   ? CacheState::CREATE_MEDIA
-                                  : CacheState::DONE;
+                                  : CacheState::DELETE_CODE;
           break;
         }
 
@@ -127,15 +135,15 @@
 
         rv = http_cache->GetBackend(
             &cache_,
-            base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
-                       base::Unretained(this)));
+            base::BindOnce(&StoragePartitionHttpCacheDataRemover::DoClearCache,
+                           base::Unretained(this)));
         break;
       }
       case CacheState::DELETE_MAIN:
       case CacheState::DELETE_MEDIA: {
         next_cache_state_ = (next_cache_state_ == CacheState::DELETE_MAIN)
                                 ? CacheState::CREATE_MEDIA
-                                : CacheState::DONE;
+                                : CacheState::DELETE_CODE;
 
         // |cache_| can be null if it cannot be initialized.
         if (cache_) {
@@ -148,19 +156,38 @@
                          &StoragePartitionHttpCacheDataRemover::DoClearCache,
                          base::Unretained(this)));
           } else if (delete_begin_.is_null() && delete_end_.is_max()) {
-            rv = cache_->DoomAllEntries(
-                base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
-                           base::Unretained(this)));
+            rv = cache_->DoomAllEntries(base::BindOnce(
+                &StoragePartitionHttpCacheDataRemover::DoClearCache,
+                base::Unretained(this)));
           } else {
             rv = cache_->DoomEntriesBetween(
                 delete_begin_, delete_end_,
-                base::Bind(&StoragePartitionHttpCacheDataRemover::DoClearCache,
-                           base::Unretained(this)));
+                base::BindOnce(
+                    &StoragePartitionHttpCacheDataRemover::DoClearCache,
+                    base::Unretained(this)));
           }
           cache_ = nullptr;
         }
         break;
       }
+      case CacheState::DELETE_CODE: {
+        next_cache_state_ = CacheState::DONE;
+        if (base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+          DCHECK(generated_code_cache_context_);
+          GeneratedCodeCache* code_cache =
+              generated_code_cache_context_->generated_code_cache();
+          if (code_cache) {
+            auto callback = base::BindRepeating(
+                &StoragePartitionHttpCacheDataRemover::DoClearCache,
+                base::Unretained(this));
+            // TODO(crbug.com/866419): Currently we just clear the entire cache.
+            // Change it to conditionally clear the entries based on the
+            // filters.
+            rv = code_cache->ClearCache(callback);
+          }
+        }
+        break;
+      }
       case CacheState::DONE: {
         cache_ = nullptr;
         next_cache_state_ = CacheState::NONE;
diff --git a/content/browser/browsing_data/storage_partition_http_cache_data_remover.h b/content/browser/browsing_data/storage_partition_http_cache_data_remover.h
index 6d64417..665a8f4 100644
--- a/content/browser/browsing_data/storage_partition_http_cache_data_remover.h
+++ b/content/browser/browsing_data/storage_partition_http_cache_data_remover.h
@@ -25,6 +25,7 @@
 namespace content {
 
 class StoragePartition;
+class GeneratedCodeCacheContext;
 
 // Helper to remove http cache data from a StoragePartition.
 class StoragePartitionHttpCacheDataRemover {
@@ -56,6 +57,7 @@
     CREATE_MEDIA,
     DELETE_MAIN,
     DELETE_MEDIA,
+    DELETE_CODE,
     DONE
   };
 
@@ -64,7 +66,8 @@
       base::Time delete_begin,
       base::Time delete_end,
       net::URLRequestContextGetter* main_context_getter,
-      net::URLRequestContextGetter* media_context_getter);
+      net::URLRequestContextGetter* media_context_getter,
+      GeneratedCodeCacheContext* generated_code_cache_context);
 
   // StoragePartitionHttpCacheDataRemover deletes itself (using DeleteHelper)
   // and is not supposed to be deleted by other objects so make destructor
@@ -84,6 +87,7 @@
 
   const scoped_refptr<net::URLRequestContextGetter> main_context_getter_;
   const scoped_refptr<net::URLRequestContextGetter> media_context_getter_;
+  const scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
 
   base::OnceClosure done_callback_;
 
diff --git a/content/browser/cache_storage/cache_storage_cache.cc b/content/browser/cache_storage/cache_storage_cache.cc
index f853ed81..198e9280 100644
--- a/content/browser/cache_storage/cache_storage_cache.cc
+++ b/content/browser/cache_storage/cache_storage_cache.cc
@@ -1759,7 +1759,7 @@
 
   auto calculate_size_callback =
       base::AdaptCallbackForRepeating(std::move(callback));
-  int rv = backend_->CalculateSizeOfAllEntries(base::Bind(
+  int rv = backend_->CalculateSizeOfAllEntries(base::BindOnce(
       &CacheStorageCache::InitGotCacheSize, weak_ptr_factory_.GetWeakPtr(),
       calculate_size_callback, cache_create_error));
 
diff --git a/content/browser/code_cache/generated_code_cache.cc b/content/browser/code_cache/generated_code_cache.cc
index 8aa175c0..d0740fe 100644
--- a/content/browser/code_cache/generated_code_cache.cc
+++ b/content/browser/code_cache/generated_code_cache.cc
@@ -140,11 +140,13 @@
 
 GeneratedCodeCache::PendingOperation::~PendingOperation() = default;
 
-// Static factory method.
-std::unique_ptr<GeneratedCodeCache> GeneratedCodeCache::Create(
-    const base::FilePath& path,
-    int max_size_bytes) {
-  return base::WrapUnique(new GeneratedCodeCache(path, max_size_bytes));
+GeneratedCodeCache::GeneratedCodeCache(const base::FilePath& path,
+                                       int max_size_bytes)
+    : backend_state_(kUnInitialized),
+      path_(path),
+      max_size_bytes_(max_size_bytes),
+      weak_ptr_factory_(this) {
+  CreateBackend();
 }
 
 GeneratedCodeCache::~GeneratedCodeCache() = default;
@@ -243,15 +245,6 @@
   return backend_->DoomAllEntries(std::move(callback));
 }
 
-GeneratedCodeCache::GeneratedCodeCache(const base::FilePath& path,
-                                       int max_size_bytes)
-    : backend_state_(kUnInitialized),
-      path_(path),
-      max_size_bytes_(max_size_bytes),
-      weak_ptr_factory_(this) {
-  CreateBackend();
-}
-
 void GeneratedCodeCache::CreateBackend() {
   // Create a new Backend pointer that cleans itself if the GeneratedCodeCache
   // instance is not live when the CreateCacheBackend finishes.
diff --git a/content/browser/code_cache/generated_code_cache.h b/content/browser/code_cache/generated_code_cache.h
index a84b307..36d2991 100644
--- a/content/browser/code_cache/generated_code_cache.h
+++ b/content/browser/code_cache/generated_code_cache.h
@@ -35,8 +35,7 @@
       base::RepeatingCallback<void(scoped_refptr<net::IOBufferWithSize>)>;
 
   // Creates a GeneratedCodeCache with the specified path and the maximum size.
-  static std::unique_ptr<GeneratedCodeCache> Create(const base::FilePath& path,
-                                                    int max_size);
+  GeneratedCodeCache(const base::FilePath& path, int max_size_bytes);
 
   ~GeneratedCodeCache();
 
@@ -76,8 +75,6 @@
   // Data streams corresponding to each entry.
   enum { kDataIndex = 1 };
 
-  GeneratedCodeCache(const base::FilePath& path, int max_size_bytes);
-
   // Creates a simple_disk_cache backend.
   void CreateBackend();
   void DidCreateBackend(
diff --git a/content/browser/code_cache/generated_code_cache_context.cc b/content/browser/code_cache/generated_code_cache_context.cc
new file mode 100644
index 0000000..9aa1621
--- /dev/null
+++ b/content/browser/code_cache/generated_code_cache_context.cc
@@ -0,0 +1,37 @@
+// 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 "content/browser/code_cache/generated_code_cache_context.h"
+#include "base/files/file_path.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+GeneratedCodeCacheContext::GeneratedCodeCacheContext() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+}
+
+void GeneratedCodeCacheContext::Initialize(const base::FilePath& path,
+                                           int max_bytes) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  BrowserThread::PostTask(
+      BrowserThread::IO, FROM_HERE,
+      base::BindOnce(&GeneratedCodeCacheContext::InitializeOnIO, this, path,
+                     max_bytes));
+}
+
+void GeneratedCodeCacheContext::InitializeOnIO(const base::FilePath& path,
+                                               int max_bytes) {
+  generated_code_cache_.reset(new GeneratedCodeCache(path, max_bytes));
+}
+
+GeneratedCodeCache* GeneratedCodeCacheContext::generated_code_cache() const {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  return generated_code_cache_.get();
+}
+
+GeneratedCodeCacheContext::~GeneratedCodeCacheContext() = default;
+
+}  // namespace content
diff --git a/content/browser/code_cache/generated_code_cache_context.h b/content/browser/code_cache/generated_code_cache_context.h
new file mode 100644
index 0000000..4a42beb
--- /dev/null
+++ b/content/browser/code_cache/generated_code_cache_context.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_CONTEXT_H_
+#define CONTENT_BROWSER_CODE_CACHE_GENERATED_CODE_CACHE_CONTEXT_H_
+
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+class GeneratedCodeCache;
+
+// One instance exists per disk-backed (non in-memory) storage contexts. This
+// owns the instance of GeneratedCodeCache that is used to store the data
+// generated by the renderer (for ex: code caches for script resources). This
+// initializes and closes the code cache on the I/O thread. The instance of
+// this class (|this|) itself is constructed on the UI thread.
+class CONTENT_EXPORT GeneratedCodeCacheContext
+    : public base::RefCountedThreadSafe<GeneratedCodeCacheContext> {
+ public:
+  REQUIRE_ADOPTION_FOR_REFCOUNTED_TYPE();
+
+  GeneratedCodeCacheContext();
+
+  // Initialize is called on the UI thread when the StoragePartition is
+  // being setup.
+  void Initialize(const base::FilePath& path, int max_bytes);
+
+  // Call on the IO thread to get the code cache instance.
+  GeneratedCodeCache* generated_code_cache() const;
+
+ private:
+  friend class base::RefCountedThreadSafe<GeneratedCodeCacheContext>;
+  ~GeneratedCodeCacheContext();
+
+  void InitializeOnIO(const base::FilePath& path, int max_bytes);
+
+  // Created, used and deleted on the IO thread.
+  std::unique_ptr<GeneratedCodeCache, BrowserThread::DeleteOnIOThread>
+      generated_code_cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(GeneratedCodeCacheContext);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_CODE_CACHE_GENERATED_CACHE_CONTEXT_H_
diff --git a/content/browser/code_cache/generated_code_cache_unittest.cc b/content/browser/code_cache/generated_code_cache_unittest.cc
index e3ee349..3d50d595 100644
--- a/content/browser/code_cache/generated_code_cache_unittest.cc
+++ b/content/browser/code_cache/generated_code_cache_unittest.cc
@@ -26,7 +26,7 @@
     ASSERT_TRUE(cache_dir_.CreateUniqueTempDir());
     cache_path_ = cache_dir_.GetPath();
     generated_code_cache_ =
-        GeneratedCodeCache::Create(cache_path_, kMaxSizeInBytes);
+        std::make_unique<GeneratedCodeCache>(cache_path_, kMaxSizeInBytes);
   }
 
   void TearDown() override {
@@ -48,9 +48,8 @@
   // to test the pending operaions path.
   void InitializeCacheAndReOpen() {
     InitializeCache();
-    generated_code_cache_.reset();
-    generated_code_cache_ =
-        GeneratedCodeCache::Create(cache_path_, kMaxSizeInBytes);
+    generated_code_cache_.reset(
+        new GeneratedCodeCache(cache_path_, kMaxSizeInBytes));
   }
 
   void WriteToCache(const GURL& url,
@@ -105,6 +104,7 @@
 constexpr char GeneratedCodeCacheTest::kInitialUrl[];
 constexpr char GeneratedCodeCacheTest::kInitialOrigin[];
 constexpr char GeneratedCodeCacheTest::kInitialData[];
+const int GeneratedCodeCacheTest::kMaxSizeInBytes;
 
 TEST_F(GeneratedCodeCacheTest, FetchEntry) {
   GURL url(kInitialUrl);
diff --git a/content/browser/devtools/protocol/tethering_handler.cc b/content/browser/devtools/protocol/tethering_handler.cc
index ce673865..602a907 100644
--- a/content/browser/devtools/protocol/tethering_handler.cc
+++ b/content/browser/devtools/protocol/tethering_handler.cc
@@ -108,8 +108,8 @@
         new net::IOBuffer(kSocketPumpBufferSize);
     int result =
         from->Read(buffer.get(), kSocketPumpBufferSize,
-                   base::Bind(&SocketPump::OnRead, base::Unretained(this), from,
-                              to, buffer));
+                   base::BindOnce(&SocketPump::OnRead, base::Unretained(this),
+                                  from, to, buffer));
     if (result != net::ERR_IO_PENDING)
       OnRead(from, to, buffer, result);
   }
@@ -128,10 +128,11 @@
         new net::DrainableIOBuffer(buffer.get(), total);
 
     ++pending_writes_;
-    result = to->Write(drainable.get(), total,
-                       base::Bind(&SocketPump::OnWritten,
-                                  base::Unretained(this), drainable, from, to),
-                       kTrafficAnnotation);
+    result =
+        to->Write(drainable.get(), total,
+                  base::BindOnce(&SocketPump::OnWritten, base::Unretained(this),
+                                 drainable, from, to),
+                  kTrafficAnnotation);
     if (result != net::ERR_IO_PENDING)
       OnWritten(drainable, from, to, result);
   }
@@ -151,8 +152,8 @@
       ++pending_writes_;
       result =
           to->Write(drainable.get(), drainable->BytesRemaining(),
-                    base::Bind(&SocketPump::OnWritten, base::Unretained(this),
-                               drainable, from, to),
+                    base::BindOnce(&SocketPump::OnWritten,
+                                   base::Unretained(this), drainable, from, to),
                     kTrafficAnnotation);
       if (result != net::ERR_IO_PENDING)
         OnWritten(drainable, from, to, result);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index a687303..d4b857bc 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -306,7 +306,7 @@
         }
       },
       base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
-      base::Passed(&io_callback));
+      std::move(io_callback));
   ui::OzonePlatform::RegisterStartupCallback(std::move(bounce_callback));
 }
 #endif  // defined(USE_OZONE)
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc
index cd079aed..65f0bb6 100644
--- a/content/browser/indexed_db/indexed_db_factory_impl.cc
+++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -191,7 +191,8 @@
   DCHECK(!backing_store_map_[origin]->close_timer()->IsRunning());
   backing_store_map_[origin]->close_timer()->Start(
       FROM_HERE, base::TimeDelta::FromSeconds(kBackingStoreGracePeriodSeconds),
-      base::Bind(&IndexedDBFactoryImpl::MaybeStartPreCloseTasks, this, origin));
+      base::BindOnce(&IndexedDBFactoryImpl::MaybeStartPreCloseTasks, this,
+                     origin));
 }
 
 void IndexedDBFactoryImpl::MaybeStartPreCloseTasks(const Origin& origin) {
diff --git a/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc b/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc
index 0be77f3..74cd227 100644
--- a/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc
+++ b/content/browser/indexed_db/indexed_db_pre_close_task_queue.cc
@@ -45,9 +45,10 @@
     OnComplete();
     return;
   }
-  timeout_timer_->Start(FROM_HERE, timeout_time_,
-                        base::Bind(&IndexedDBPreCloseTaskQueue::StopForTimout,
-                                   ptr_factory_.GetWeakPtr()));
+  timeout_timer_->Start(
+      FROM_HERE, timeout_time_,
+      base::BindOnce(&IndexedDBPreCloseTaskQueue::StopForTimout,
+                     ptr_factory_.GetWeakPtr()));
   leveldb::Status status = std::move(metadata_fetcher).Run(&metadata_);
   if (!status.ok()) {
     StopForMetadataError(status);
diff --git a/content/browser/indexed_db/indexed_db_transaction.cc b/content/browser/indexed_db/indexed_db_transaction.cc
index 78ac2ba..6f721f0 100644
--- a/content/browser/indexed_db/indexed_db_transaction.cc
+++ b/content/browser/indexed_db/indexed_db_transaction.cc
@@ -526,9 +526,9 @@
   // never requests further activity. Read-only transactions don't
   // block other transactions, so don't time those out.
   if (mode_ != blink::kWebIDBTransactionModeReadOnly) {
-    timeout_timer_.Start(
-        FROM_HERE, GetInactivityTimeout(),
-        base::Bind(&IndexedDBTransaction::Timeout, ptr_factory_.GetWeakPtr()));
+    timeout_timer_.Start(FROM_HERE, GetInactivityTimeout(),
+                         base::BindOnce(&IndexedDBTransaction::Timeout,
+                                        ptr_factory_.GetWeakPtr()));
   }
   processing_event_queue_ = false;
 }
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index dbb1b89..6c5184fb 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -15,6 +15,7 @@
 #include "base/trace_event/trace_event.h"
 #include "components/download/public/common/download_stats.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
+#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
@@ -615,8 +616,8 @@
 
     if (appcache_handle_core) {
       std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
-          AppCacheRequestHandler::InitializeForNavigationNetworkService(
-              *resource_request_, appcache_handle_core,
+          AppCacheRequestHandler::InitializeForMainResourceNetworkService(
+              *resource_request_, appcache_handle_core->host()->GetWeakPtr(),
               network_loader_factory_);
       if (appcache_interceptor)
         interceptors_.push_back(std::move(appcache_interceptor));
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index d8d744e..a1ba8fe9 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -1551,9 +1551,9 @@
   // messages.
   base::RunLoop run_loop;
   base::OneShotTimer timer;
-  timer.Start(
-      FROM_HERE, base::TimeDelta::FromMilliseconds(210),
-      base::Bind(&base::RunLoop::QuitWhenIdle, base::Unretained(&run_loop)));
+  timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(210),
+              base::BindOnce(&base::RunLoop::QuitWhenIdle,
+                             base::Unretained(&run_loop)));
   run_loop.Run();
 
   // The prefetch should be cancelled by now.
diff --git a/content/browser/loader/resource_hints_impl.cc b/content/browser/loader/resource_hints_impl.cc
index 3ebe0570..bdb06548 100644
--- a/content/browser/loader/resource_hints_impl.cc
+++ b/content/browser/loader/resource_hints_impl.cc
@@ -102,7 +102,7 @@
   resolve_info.set_is_speculative(true);
   return resolver->Resolve(
       resolve_info, net::IDLE, raw_addresses,
-      base::Bind(&OnResolveComplete, base::Passed(&addresses), callback),
+      base::BindOnce(&OnResolveComplete, std::move(addresses), callback),
       out_request, net::NetLogWithSource());
 }
 
diff --git a/content/browser/media/audio_stream_monitor.cc b/content/browser/media/audio_stream_monitor.cc
index 324f310..17b5cb76 100644
--- a/content/browser/media/audio_stream_monitor.cc
+++ b/content/browser/media/audio_stream_monitor.cc
@@ -212,10 +212,9 @@
   if (should_stop_timer) {
     off_timer_.Stop();
   } else if (!off_timer_.IsRunning()) {
-    off_timer_.Start(
-        FROM_HERE,
-        off_time - now,
-        base::Bind(&AudioStreamMonitor::MaybeToggle, base::Unretained(this)));
+    off_timer_.Start(FROM_HERE, off_time - now,
+                     base::BindOnce(&AudioStreamMonitor::MaybeToggle,
+                                    base::Unretained(this)));
   }
 }
 
diff --git a/content/browser/renderer_host/cursor_manager.cc b/content/browser/renderer_host/cursor_manager.cc
index 724d64c..6d5ec95 100644
--- a/content/browser/renderer_host/cursor_manager.cc
+++ b/content/browser/renderer_host/cursor_manager.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 "cursor_manager.h"
+#include "content/browser/renderer_host/cursor_manager.h"
 
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
 
diff --git a/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc b/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
index a13243f..6056b1f 100644
--- a/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
+++ b/content/browser/renderer_host/input/mouse_wheel_phase_handler.cc
@@ -186,8 +186,9 @@
                        TRACE_EVENT_SCOPE_THREAD);
   mouse_wheel_end_dispatch_timer_.Start(
       FROM_HERE, timeout,
-      base::Bind(&MouseWheelPhaseHandler::SendSyntheticWheelEventWithPhaseEnded,
-                 base::Unretained(this), should_route_event));
+      base::BindOnce(
+          &MouseWheelPhaseHandler::SendSyntheticWheelEventWithPhaseEnded,
+          base::Unretained(this), should_route_event));
 }
 
 bool MouseWheelPhaseHandler::IsWithinSlopRegion(
diff --git a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
index ffac149..2f9723a 100644
--- a/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
+++ b/content/browser/renderer_host/media/audio_input_device_manager_unittest.cc
@@ -50,7 +50,8 @@
 // TODO(henrika): there are special restrictions for Android since
 // AudioInputDeviceManager::Open() must be called on the audio thread.
 // This test suite must be modified to run on Android.
-#if defined(OS_ANDROID)
+// Flaky on Linux. See http://crbug.com/867397.
+#if defined(OS_ANDROID) || defined(OS_LINUX)
 #define MAYBE_AudioInputDeviceManagerTest DISABLED_AudioInputDeviceManagerTest
 #else
 #define MAYBE_AudioInputDeviceManagerTest AudioInputDeviceManagerTest
diff --git a/content/browser/renderer_host/media/audio_output_authorization_handler.cc b/content/browser/renderer_host/media/audio_output_authorization_handler.cc
index 239c8be..5d888b45 100644
--- a/content/browser/renderer_host/media/audio_output_authorization_handler.cc
+++ b/content/browser/renderer_host/media/audio_output_authorization_handler.cc
@@ -254,8 +254,8 @@
   media_stream_manager_->media_devices_manager()->EnumerateDevices(
       devices_to_enumerate,
       base::BindOnce(&AudioOutputAuthorizationHandler::TranslateDeviceID,
-                     weak_factory_.GetWeakPtr(), base::Passed(&trace_scope),
-                     base::Passed(&cb), device_id, std::move(salt),
+                     weak_factory_.GetWeakPtr(), std::move(trace_scope),
+                     std::move(cb), device_id, std::move(salt),
                      std::move(security_origin)));
 }
 
diff --git a/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc b/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc
index 5a72602..15a70a6 100644
--- a/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc
+++ b/content/browser/renderer_host/media/audio_output_authorization_handler_unittest.cc
@@ -167,7 +167,7 @@
 
     media_stream_manager_->media_devices_manager()->EnumerateDevices(
         devices_to_enumerate,
-        base::Bind(
+        base::BindOnce(
             [](std::string* out, const MediaDeviceEnumeration& result) {
               // Index 0 is default, so use 1.
               CHECK(result[MediaDeviceType::MEDIA_DEVICE_TYPE_AUDIO_OUTPUT]
diff --git a/content/browser/renderer_host/media/media_devices_dispatcher_host.cc b/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
index c87ff86..1812e21 100644
--- a/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_devices_dispatcher_host.cc
@@ -207,7 +207,7 @@
       requested_types,
       base::BindOnce(
           &MediaDevicesDispatcherHost::FinalizeGetVideoInputCapabilities,
-          weak_factory_.GetWeakPtr(), base::Passed(&client_callback),
+          weak_factory_.GetWeakPtr(), std::move(client_callback),
           std::move(salt_and_origin), std::move(default_device_id)));
 }
 
diff --git a/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
index 228ef45..1d70504 100644
--- a/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_devices_dispatcher_host_unittest.cc
@@ -149,8 +149,8 @@
     devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_OUTPUT] = true;
     media_stream_manager_->media_devices_manager()->EnumerateDevices(
         devices_to_enumerate,
-        base::Bind(&PhysicalDevicesEnumerated, run_loop.QuitClosure(),
-                   &physical_devices_));
+        base::BindOnce(&PhysicalDevicesEnumerated, run_loop.QuitClosure(),
+                       &physical_devices_));
     run_loop.Run();
 
     ASSERT_GT(physical_devices_[MEDIA_DEVICE_TYPE_AUDIO_INPUT].size(), 0u);
diff --git a/content/browser/renderer_host/media/media_devices_manager.cc b/content/browser/renderer_host/media/media_devices_manager.cc
index c9fcb5e..354699f 100644
--- a/content/browser/renderer_host/media/media_devices_manager.cc
+++ b/content/browser/renderer_host/media/media_devices_manager.cc
@@ -666,7 +666,7 @@
       internal_requested_types,
       base::BindOnce(&MediaDevicesManager::OnDevicesEnumerated,
                      weak_factory_.GetWeakPtr(), requested_types,
-                     request_video_input_capabilities, base::Passed(&callback),
+                     request_video_input_capabilities, std::move(callback),
                      std::move(salt_and_origin), has_permissions));
 }
 
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 688ce18..b28cffc1 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -298,8 +298,8 @@
     devices_to_enumerate[MEDIA_DEVICE_TYPE_AUDIO_INPUT] = true;
     media_stream_manager_->media_devices_manager()->EnumerateDevices(
         devices_to_enumerate,
-        base::Bind(&AudioInputDevicesEnumerated, run_loop.QuitClosure(),
-                   &audio_device_descriptions_));
+        base::BindOnce(&AudioInputDevicesEnumerated, run_loop.QuitClosure(),
+                       &audio_device_descriptions_));
     run_loop.Run();
 
     ASSERT_GT(audio_device_descriptions_.size(), 0u);
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index eb94f21..e054d3c 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -968,8 +968,9 @@
   devices_to_enumerate[MEDIA_DEVICE_TYPE_VIDEO_INPUT] = request_video_input;
   media_devices_manager_->EnumerateDevices(
       devices_to_enumerate,
-      base::Bind(&MediaStreamManager::DevicesEnumerated, base::Unretained(this),
-                 request_audio_input, request_video_input, label));
+      base::BindOnce(&MediaStreamManager::DevicesEnumerated,
+                     base::Unretained(this), request_audio_input,
+                     request_video_input, label));
 }
 
 std::string MediaStreamManager::AddRequest(DeviceRequest* request) {
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/content/browser/renderer_host/media/media_stream_ui_proxy.cc
index 2f13d1d2..065432a 100644
--- a/content/browser/renderer_host/media/media_stream_ui_proxy.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_proxy.cc
@@ -125,9 +125,9 @@
 
   render_delegate->RequestMediaAccessPermission(
       *request,
-      base::Bind(&Core::ProcessAccessRequestResponse,
-                 weak_factory_.GetWeakPtr(), request->render_process_id,
-                 request->render_frame_id));
+      base::BindOnce(&Core::ProcessAccessRequestResponse,
+                     weak_factory_.GetWeakPtr(), request->render_process_id,
+                     request->render_frame_id));
 }
 
 void MediaStreamUIProxy::Core::OnStarted(gfx::NativeViewId* window_id) {
diff --git a/content/browser/renderer_host/media/video_capture_unittest.cc b/content/browser/renderer_host/media/video_capture_unittest.cc
index 6cebba5..fbcef86 100644
--- a/content/browser/renderer_host/media/video_capture_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_unittest.cc
@@ -142,9 +142,9 @@
       devices_to_enumerate[MEDIA_DEVICE_TYPE_VIDEO_INPUT] = true;
       media_stream_manager_->media_devices_manager()->EnumerateDevices(
           devices_to_enumerate,
-          base::Bind(&VideoInputDevicesEnumerated, run_loop.QuitClosure(),
-                     browser_context_.GetMediaDeviceIDSalt(), security_origin,
-                     &video_devices));
+          base::BindOnce(&VideoInputDevicesEnumerated, run_loop.QuitClosure(),
+                         browser_context_.GetMediaDeviceIDSalt(),
+                         security_origin, &video_devices));
       run_loop.Run();
     }
     ASSERT_FALSE(video_devices.empty());
diff --git a/content/browser/renderer_host/p2p/socket_dispatcher_host.cc b/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
index 270b2aae..563f517 100644
--- a/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
+++ b/content/browser/renderer_host/p2p/socket_dispatcher_host.cc
@@ -81,8 +81,8 @@
     net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
     int result = resolver_->Resolve(
         info, net::DEFAULT_PRIORITY, &addresses_,
-        base::Bind(&P2PSocketDispatcherHost::DnsRequest::OnDone,
-                   base::Unretained(this)),
+        base::BindOnce(&P2PSocketDispatcherHost::DnsRequest::OnDone,
+                       base::Unretained(this)),
         &request_, net::NetLogWithSource());
     if (result != net::ERR_IO_PENDING)
       OnDone(result);
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc
index efc6c63..348c940 100644
--- a/content/browser/renderer_host/p2p/socket_host_tcp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -251,9 +251,8 @@
                                 read_buffer_->RemainingCapacity());
     }
     result = socket_->Read(
-        read_buffer_.get(),
-        read_buffer_->RemainingCapacity(),
-        base::Bind(&P2PSocketHostTcp::OnRead, base::Unretained(this)));
+        read_buffer_.get(), read_buffer_->RemainingCapacity(),
+        base::BindOnce(&P2PSocketHostTcp::OnRead, base::Unretained(this)));
     DidCompleteRead(result);
   } while (result > 0);
 }
@@ -341,7 +340,7 @@
          !write_pending_) {
     int result = socket_->Write(
         write_buffer_.buffer.get(), write_buffer_.buffer->BytesRemaining(),
-        base::Bind(&P2PSocketHostTcp::OnWritten, base::Unretained(this)),
+        base::BindOnce(&P2PSocketHostTcp::OnWritten, base::Unretained(this)),
         net::NetworkTrafficAnnotationTag(write_buffer_.traffic_annotation));
     HandleWriteResult(result);
   }
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.cc b/content/browser/renderer_host/p2p/socket_host_udp.cc
index 318ed0bb..311d174 100644
--- a/content/browser/renderer_host/p2p/socket_host_udp.cc
+++ b/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -207,7 +207,7 @@
   do {
     result = socket_->RecvFrom(
         recv_buffer_.get(), kUdpReadBufferSize, &recv_address_,
-        base::Bind(&P2PSocketHostUdp::OnRecv, base::Unretained(this)));
+        base::BindOnce(&P2PSocketHostUdp::OnRecv, base::Unretained(this)));
     if (result == net::ERR_IO_PENDING)
       return;
     HandleReadResult(result);
diff --git a/content/browser/renderer_host/pepper/pepper_lookup_request.h b/content/browser/renderer_host/pepper/pepper_lookup_request.h
index 128b363..0739b3dc 100644
--- a/content/browser/renderer_host/pepper/pepper_lookup_request.h
+++ b/content/browser/renderer_host/pepper/pepper_lookup_request.h
@@ -36,11 +36,11 @@
         callback_(callback) {}
 
   void Start() {
-    int result =
-        resolver_->Resolve(request_info_, priority_, &addresses_,
-                           base::Bind(&PepperLookupRequest<T>::OnLookupFinished,
-                                      base::Unretained(this)),
-                           &request_, net::NetLogWithSource());
+    int result = resolver_->Resolve(
+        request_info_, priority_, &addresses_,
+        base::BindOnce(&PepperLookupRequest<T>::OnLookupFinished,
+                       base::Unretained(this)),
+        &request_, net::NetLogWithSource());
     if (result != net::ERR_IO_PENDING)
       OnLookupFinished(result);
   }
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
index 3a8cb7c6..429d3d2 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc
@@ -141,11 +141,9 @@
   ppapi::host::ReplyMessageContext reply_context(
       context->MakeReplyMessageContext());
   int net_result = socket_->Accept(
-      &accepted_socket_,
-      &accepted_address_,
+      &accepted_socket_, &accepted_address_,
       base::Bind(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted,
-                 base::Unretained(this),
-                 reply_context));
+                 base::Unretained(this), reply_context));
   if (net_result != net::ERR_IO_PENDING)
     OnAcceptCompleted(reply_context, net_result);
   return PP_OK_COMPLETIONPENDING;
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 17d9f02..8f7b4d57 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -348,9 +348,8 @@
   const ppapi::host::ReplyMessageContext reply_context(
       context->MakeReplyMessageContext());
   int net_result = ssl_socket_->Connect(
-      base::Bind(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted,
-                 base::Unretained(this),
-                 reply_context));
+      base::BindOnce(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted,
+                     base::Unretained(this), reply_context));
   if (net_result != net::ERR_IO_PENDING)
     OnSSLHandshakeCompleted(reply_context, net_result);
   return PP_OK_COMPLETIONPENDING;
@@ -376,20 +375,16 @@
   int net_result = net::ERR_FAILED;
   if (socket_) {
     DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED);
-    net_result =
-        socket_->Read(read_buffer_.get(),
-                      bytes_to_read,
-                      base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
-                                 base::Unretained(this),
-                                 reply_context));
+    net_result = socket_->Read(
+        read_buffer_.get(), bytes_to_read,
+        base::BindOnce(&PepperTCPSocketMessageFilter::OnReadCompleted,
+                       base::Unretained(this), reply_context));
   } else if (ssl_socket_) {
     DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED);
     net_result = ssl_socket_->Read(
-        read_buffer_.get(),
-        bytes_to_read,
-        base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
-                   base::Unretained(this),
-                   reply_context));
+        read_buffer_.get(), bytes_to_read,
+        base::BindOnce(&PepperTCPSocketMessageFilter::OnReadCompleted,
+                       base::Unretained(this), reply_context));
   }
   if (net_result != net::ERR_IO_PENDING)
     OnReadCompleted(reply_context, net_result);
@@ -463,11 +458,9 @@
   ppapi::host::ReplyMessageContext reply_context(
       context->MakeReplyMessageContext());
   int net_result = socket_->Accept(
-      &accepted_socket_,
-      &accepted_address_,
+      &accepted_socket_, &accepted_address_,
       base::Bind(&PepperTCPSocketMessageFilter::OnAcceptCompleted,
-                 base::Unretained(this),
-                 reply_context));
+                 base::Unretained(this), reply_context));
   if (net_result != net::ERR_IO_PENDING)
     OnAcceptCompleted(reply_context, net_result);
   return PP_OK_COMPLETIONPENDING;
@@ -653,8 +646,8 @@
 
   int net_result = host_resolver->Resolve(
       request_info, net::DEFAULT_PRIORITY, &address_list_,
-      base::Bind(&PepperTCPSocketMessageFilter::OnResolveCompleted,
-                 base::Unretained(this), context),
+      base::BindOnce(&PepperTCPSocketMessageFilter::OnResolveCompleted,
+                     base::Unretained(this), context),
       &request_, net::NetLogWithSource());
   if (net_result != net::ERR_IO_PENDING)
     OnResolveCompleted(context, net_result);
@@ -741,15 +734,15 @@
     DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED);
     net_result = socket_->Write(
         write_buffer_.get(), write_buffer_->BytesRemaining(),
-        base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
-                   base::Unretained(this), context),
+        base::BindOnce(&PepperTCPSocketMessageFilter::OnWriteCompleted,
+                       base::Unretained(this), context),
         traffic_annotation);
   } else if (ssl_socket_) {
     DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED);
     net_result = ssl_socket_->Write(
         write_buffer_.get(), write_buffer_->BytesRemaining(),
-        base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
-                   base::Unretained(this), context),
+        base::BindOnce(&PepperTCPSocketMessageFilter::OnWriteCompleted,
+                       base::Unretained(this), context),
         traffic_annotation);
   }
   if (net_result != net::ERR_IO_PENDING)
@@ -837,9 +830,8 @@
 
   int net_result = socket_->Connect(
       address_list_[address_index_],
-      base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
-                 base::Unretained(this),
-                 context));
+      base::BindOnce(&PepperTCPSocketMessageFilter::OnConnectCompleted,
+                     base::Unretained(this), context));
   if (net_result != net::ERR_IO_PENDING)
     OnConnectCompleted(context, net_result);
 }
diff --git a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
index 141d0b84..7a83dc0 100644
--- a/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.cc
@@ -558,8 +558,8 @@
   int net_result = socket_->RecvFrom(
       recvfrom_buffer_.get(), UDPSocketResourceConstants::kMaxReadSize,
       &recvfrom_address_,
-      base::Bind(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
-                 base::Unretained(this)));
+      base::BindOnce(&PepperUDPSocketMessageFilter::OnRecvFromCompleted,
+                     base::Unretained(this)));
   if (net_result != net::ERR_IO_PENDING)
     OnRecvFromCompleted(net_result);
 }
@@ -620,11 +620,10 @@
   // See OnMsgRecvFrom() for the reason why we use base::Unretained(this)
   // when calling |socket_| methods.
   int net_result = socket_->SendTo(
-      pending_send.buffer.get(),
-      pending_send.buffer->size(),
+      pending_send.buffer.get(), pending_send.buffer->size(),
       net::IPEndPoint(pending_send.address, pending_send.port),
-      base::Bind(&PepperUDPSocketMessageFilter::OnSendToCompleted,
-                 base::Unretained(this)));
+      base::BindOnce(&PepperUDPSocketMessageFilter::OnSendToCompleted,
+                     base::Unretained(this)));
   return net_result;
 }
 
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 8ca3b5e..b551c967 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -96,7 +96,8 @@
     net::URLRequestContextGetter* request_context,
     RenderWidgetHelper* render_widget_helper,
     MediaInternals* media_internals,
-    CacheStorageContextImpl* cache_storage_context)
+    CacheStorageContextImpl* cache_storage_context,
+    GeneratedCodeCacheContext* generated_code_cache_context)
     : BrowserMessageFilter(kRenderFilteredMessageClasses,
                            arraysize(kRenderFilteredMessageClasses)),
       BrowserAssociatedInterface<mojom::RenderMessageFilter>(this, this),
@@ -107,6 +108,7 @@
       render_process_id_(render_process_id),
       media_internals_(media_internals),
       cache_storage_context_(cache_storage_context),
+      generated_code_cache_context_(generated_code_cache_context),
       weak_ptr_factory_(this) {
   DCHECK(request_context_.get());
 
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index b90944a..3f9f5e6 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -58,6 +58,7 @@
 class RenderWidgetHelper;
 class ResourceContext;
 class ResourceDispatcherHostImpl;
+class GeneratedCodeCacheContext;
 
 // This class filters out incoming IPC messages for the renderer process on the
 // IPC thread.
@@ -72,7 +73,8 @@
                       net::URLRequestContextGetter* request_context,
                       RenderWidgetHelper* render_widget_helper,
                       MediaInternals* media_internals,
-                      CacheStorageContextImpl* cache_storage_context);
+                      CacheStorageContextImpl* cache_storage_context,
+                      GeneratedCodeCacheContext* generated_code_cache_context);
 
   // BrowserMessageFilter methods:
   bool OnMessageReceived(const IPC::Message& message) override;
@@ -151,6 +153,10 @@
   MediaInternals* media_internals_;
   CacheStorageContextImpl* cache_storage_context_;
 
+  // TODO(crbug.com/867347): Consider registering its own Mojo interface rather
+  // than going through RenderMessageFilter.
+  GeneratedCodeCacheContext* generated_code_cache_context_;
+
   base::WeakPtrFactory<RenderMessageFilter> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(RenderMessageFilter);
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index d46596be..bb3a8d6 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -732,7 +732,9 @@
 // Note: This test can't run when the Mojo Renderer is used since it does not
 // create audio streams through the normal audio pathways; at present this is
 // only used by Chromecast.
-#if BUILDFLAG(ENABLE_MOJO_RENDERER)
+//
+// crbug.com/864476: flaky on Android for unclear reasons.
+#if BUILDFLAG(ENABLE_MOJO_RENDERER) || defined(OS_ANDROID)
 #define KillProcessZerosAudioStreams DISABLED_KillProcessZerosAudioStreams
 #endif
 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, KillProcessZerosAudioStreams) {
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5dcfede..a5e1d2c 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1795,11 +1795,14 @@
 
   scoped_refptr<net::URLRequestContextGetter> request_context(
       storage_partition_impl_->GetURLRequestContext());
+  // TODO(crbug.com/867347): Consider registering Mojo interface for
+  // GeneratedCodeCache rather than going through RenderMessageFilter.
   scoped_refptr<RenderMessageFilter> render_message_filter =
       base::MakeRefCounted<RenderMessageFilter>(
           GetID(), GetBrowserContext(), request_context.get(),
           widget_helper_.get(), media_internals,
-          storage_partition_impl_->GetCacheStorageContext());
+          storage_partition_impl_->GetCacheStorageContext(),
+          storage_partition_impl_->GetGeneratedCodeCacheContext());
   AddFilter(render_message_filter.get());
 
   render_frame_message_filter_ = new RenderFrameMessageFilter(
diff --git a/content/browser/resolve_proxy_msg_helper.cc b/content/browser/resolve_proxy_msg_helper.cc
index 08885d8..347e7ef 100644
--- a/content/browser/resolve_proxy_msg_helper.cc
+++ b/content/browser/resolve_proxy_msg_helper.cc
@@ -91,8 +91,8 @@
   // Start the request.
   int result = proxy_resolution_service_->ResolveProxy(
       req.url, std::string(), &proxy_info_,
-      base::Bind(&ResolveProxyMsgHelper::OnResolveProxyCompleted,
-                 base::Unretained(this)),
+      base::BindOnce(&ResolveProxyMsgHelper::OnResolveProxyCompleted,
+                     base::Unretained(this)),
       &req.request, nullptr, net::NetLogWithSource());
 
   // Completed synchronously.
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index d8275ba..77718865 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -671,8 +671,8 @@
             wrapper()->context()->AsWeakPtr(), &remote_endpoints_.back());
     host->SetDocumentUrl(
         embedded_test_server()->GetURL("/service_worker/host"));
-    host->AssociateRegistration(registration_.get(),
-                                false /* notify_controllerchange */);
+    host->SetControllerRegistration(registration_,
+                                    false /* notify_controllerchange */);
     wrapper()->context()->AddProviderHost(std::move(host));
   }
 
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler.cc b/content/browser/service_worker/service_worker_controllee_request_handler.cc
index f7949ba..1f017c5f 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler.cc
@@ -121,7 +121,7 @@
 }
 
 void ServiceWorkerControlleeRequestHandler::MaybeScheduleUpdate() {
-  if (!provider_host_ || !provider_host_->active_version())
+  if (!provider_host_ || !provider_host_->controller())
     return;
 
   if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
@@ -145,9 +145,9 @@
     return;
 
   if (is_main_resource_load_)
-    provider_host_->active_version()->ScheduleUpdate();
+    provider_host_->controller()->ScheduleUpdate();
   else
-    provider_host_->active_version()->DeferScheduledUpdate();
+    provider_host_->controller()->DeferScheduledUpdate();
 }
 
 net::URLRequestJob* ServiceWorkerControlleeRequestHandler::MaybeCreateJob(
@@ -277,7 +277,7 @@
 
   // DidLookupRegistrationForMainResource() for the request didn't find
   // a matching service worker for this request, and
-  // ServiceWorkerProviderHost::AssociateRegistration() was not called.
+  // ServiceWorkerProviderHost::SetControllerRegistration() was not called.
   if (!provider_host_ || !provider_host_->controller())
     return base::nullopt;
 
@@ -315,9 +315,10 @@
       "ServiceWorker",
       "ServiceWorkerControlleeRequestHandler::PrepareForMainResource",
       url_job_.get(), "URL", url.spec());
-  // The corresponding provider_host may already have associated a registration
-  // in redirect case, unassociate it now.
-  provider_host_->DisassociateRegistration();
+  // The provider host may already have set a controller in redirect case,
+  // unset it now.
+  provider_host_->SetControllerRegistration(
+      nullptr, false /* notify_controllerchange */);
 
   // Also prevent a registration from claiming this host while it's not
   // yet execution ready.
@@ -506,8 +507,8 @@
     return;
   }
 
-  provider_host_->AssociateRegistration(registration.get(),
-                                        false /* notify_controllerchange */);
+  provider_host_->SetControllerRegistration(
+      registration, false /* notify_controllerchange */);
 
   // TODO(falken): Change these to DCHECK if it holds, or else figure out
   // how this happens.
@@ -606,14 +607,13 @@
   // because a permanent failure occurred when trying to start it.
   //
   // As this is an exceptional case, just error out.
-  // TODO(falken): Figure out if |active_version| can change to |controller| and
-  // do it or document the findings.
-  if (!provider_host_->active_version()) {
+  ServiceWorkerVersion* controller = provider_host_->controller();
+  if (!controller) {
     url_job_->FailDueToLostController();
     return;
   }
 
-  MaybeForwardToServiceWorker(url_job_.get(), provider_host_->active_version());
+  MaybeForwardToServiceWorker(url_job_.get(), controller);
 }
 
 void ServiceWorkerControlleeRequestHandler::OnPrepareToRestart() {
@@ -628,11 +628,11 @@
     *result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_PROVIDER_HOST;
     return nullptr;
   }
-  if (!provider_host_->active_version()) {
+  if (!provider_host_->controller()) {
     *result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_ACTIVE_VERSION;
     return nullptr;
   }
-  return provider_host_->active_version();
+  return provider_host_->controller();
 }
 
 bool ServiceWorkerControlleeRequestHandler::RequestStillValid(
diff --git a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
index 8def8fa4..54d82459 100644
--- a/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_controllee_request_handler_unittest.cc
@@ -279,11 +279,10 @@
   base::RunLoop().RunUntilIdle();
 
   // The handler should have fallen back to network and destroyed the job. The
-  // registration should not be associated with the provider host, since it is
-  // not controlled. However it should be a matching registration so it can be
-  // used for .ready and claim().
+  // provider host should not be controlled. However it should add the
+  // registration as a matching registration so it can be used for .ready and
+  // claim().
   EXPECT_FALSE(job);
-  EXPECT_FALSE(provider_host_->associated_registration());
   EXPECT_FALSE(version_->HasControllee());
   EXPECT_FALSE(provider_host_->controller());
   EXPECT_EQ(registration_.get(), provider_host_->MatchRegistration());
@@ -341,14 +340,12 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(version_->HasControllee());
   EXPECT_EQ(version_, provider_host_->controller());
-  EXPECT_EQ(version_, provider_host_->active_version());
 
   // Unset the active version.
   provider_host_->NotifyControllerLost();
   registration_->SetActiveVersion(nullptr);
   EXPECT_FALSE(version_->HasControllee());
   EXPECT_FALSE(provider_host_->controller());
-  EXPECT_FALSE(provider_host_->active_version());
 
   // Conduct a subresource load.
   ServiceWorkerRequestTestResources sub_test_resources(
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 4d904de..87824a9 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -306,6 +306,8 @@
 
   // Remove |this| as an observer of ServiceWorkerRegistrations.
   // TODO(falken): Use ScopedObserver instead of this explicit call.
+  controller_.reset();
+  controller_registration_.reset();
   RemoveAllMatchingRegistrations();
 
   // This host may be destroyed before it received the anticipated
@@ -376,8 +378,6 @@
 
 void ServiceWorkerProviderHost::OnRegistrationFailed(
     ServiceWorkerRegistration* registration) {
-  if (associated_registration_ == registration)
-    DisassociateRegistration();
   RemoveMatchingRegistration(registration);
 }
 
@@ -388,18 +388,15 @@
 
 void ServiceWorkerProviderHost::OnSkippedWaiting(
     ServiceWorkerRegistration* registration) {
-  if (associated_registration_ != registration)
+  if (controller_registration_ != registration)
     return;
-  // A client is "using" a registration if it is controlled by the active
-  // worker of the registration. skipWaiting doesn't cause a client to start
-  // using the registration.
-  if (!controller_)
-    return;
-  ServiceWorkerVersion* active_version = registration->active_version();
-  DCHECK(active_version);
-  DCHECK_EQ(active_version->status(), ServiceWorkerVersion::ACTIVATING);
-  SetControllerVersionAttribute(active_version,
-                                true /* notify_controllerchange */);
+
+  DCHECK(controller());
+  ServiceWorkerVersion* active = controller_registration_->active_version();
+  DCHECK(active);
+  DCHECK_NE(active, controller());
+  DCHECK_EQ(active->status(), ServiceWorkerVersion::ACTIVATING);
+  UpdateController(true /* notify_controllerchange */);
 }
 
 mojom::ControllerServiceWorkerPtr
@@ -417,6 +414,7 @@
 
 void ServiceWorkerProviderHost::SetDocumentUrl(const GURL& url) {
   DCHECK(!url.has_ref());
+  DCHECK(!controller());
   document_url_ = url;
   if (IsProviderForClient())
     SyncMatchingRegistrations();
@@ -432,9 +430,10 @@
   return topmost_frame_url_;
 }
 
-void ServiceWorkerProviderHost::SetControllerVersionAttribute(
-    ServiceWorkerVersion* version,
-    bool notify_controllerchange) {
+void ServiceWorkerProviderHost::UpdateController(bool notify_controllerchange) {
+  ServiceWorkerVersion* version =
+      controller_registration_ ? controller_registration_->active_version()
+                               : nullptr;
   CHECK(!version || IsContextSecureForServiceWorker());
   if (version == controller_.get())
     return;
@@ -444,8 +443,7 @@
 
   if (version)
     version->AddControllee(this);
-
-  if (previous_version.get())
+  if (previous_version)
     previous_version->RemoveControllee(client_uuid_);
 
   // SetController message should be sent only for clients.
@@ -495,28 +493,22 @@
   return blink::mojom::ServiceWorkerClientType::kWindow;
 }
 
-void ServiceWorkerProviderHost::AssociateRegistration(
-    ServiceWorkerRegistration* registration,
+void ServiceWorkerProviderHost::SetControllerRegistration(
+    scoped_refptr<ServiceWorkerRegistration> controller_registration,
     bool notify_controllerchange) {
-  CHECK(IsContextSecureForServiceWorker());
   DCHECK(IsProviderForClient());
-  DCHECK(registration);
-  DCHECK(!associated_registration_);
-  DCHECK(allow_association_);
-  DCHECK(base::ContainsKey(matching_registrations_,
-                           registration->pattern().spec().size()));
 
-  associated_registration_ = registration;
-  SetControllerVersionAttribute(registration->active_version(),
-                                notify_controllerchange);
-}
+  if (controller_registration) {
+    CHECK(IsContextSecureForServiceWorker());
+    DCHECK(allow_association_);
+    DCHECK(controller_registration->active_version());
+#if DCHECK_IS_ON()
+    DCHECK(IsMatchingRegistration(controller_registration.get()));
+#endif  // DCHECK_IS_ON()
+  }
 
-void ServiceWorkerProviderHost::DisassociateRegistration() {
-  DCHECK(IsProviderForClient());
-  if (!associated_registration_.get())
-    return;
-  associated_registration_ = nullptr;
-  SetControllerVersionAttribute(nullptr, false /* notify_controllerchange */);
+  controller_registration_ = controller_registration;
+  UpdateController(notify_controllerchange);
 }
 
 void ServiceWorkerProviderHost::AddMatchingRegistration(
@@ -535,9 +527,13 @@
 
 void ServiceWorkerProviderHost::RemoveMatchingRegistration(
     ServiceWorkerRegistration* registration) {
-  size_t key = registration->pattern().spec().size();
-  DCHECK(base::ContainsKey(matching_registrations_, key));
+  DCHECK_NE(controller_registration_, registration);
+#if DCHECK_IS_ON()
+  DCHECK(IsMatchingRegistration(registration));
+#endif  // DCHECK_IS_ON()
+
   registration->RemoveListener(this);
+  size_t key = registration->pattern().spec().size();
   matching_registrations_.erase(key);
 }
 
@@ -578,7 +574,7 @@
 }
 
 void ServiceWorkerProviderHost::NotifyControllerLost() {
-  SetControllerVersionAttribute(nullptr, true /* notify_controllerchange */);
+  SetControllerRegistration(nullptr, true /* notify_controllerchange */);
 }
 
 void ServiceWorkerProviderHost::AddServiceWorkerToUpdate(
@@ -682,22 +678,19 @@
 }
 
 void ServiceWorkerProviderHost::ClaimedByRegistration(
-    ServiceWorkerRegistration* registration) {
+    scoped_refptr<ServiceWorkerRegistration> registration) {
   DCHECK(registration->active_version());
   // TODO(falken): This should just early return, or DCHECK. claim() should have
   // no effect on a page that's already using the registration.
-  if (registration == associated_registration_) {
-    SetControllerVersionAttribute(registration->active_version(),
-                                  true /* notify_controllerchange */);
+  if (registration == controller_registration_) {
+    UpdateController(true /* notify_controllerchange */);
     return;
   }
 
   // TODO(crbug.com/866353): It shouldn't be necesary to check
   // |allow_association_|. See the comment for SetAllowAssociation().
-  if (allow_association_) {
-    DisassociateRegistration();
-    AssociateRegistration(registration, true /* notify_controllerchange */);
-  }
+  if (allow_association_)
+    SetControllerRegistration(registration, true /* notify_controllerchange */);
 }
 
 void ServiceWorkerProviderHost::CompleteNavigationInitialized(
@@ -789,6 +782,8 @@
 
 void ServiceWorkerProviderHost::SyncMatchingRegistrations() {
   DCHECK(context_);
+  DCHECK(!controller_registration());
+
   RemoveAllMatchingRegistrations();
   const auto& registrations = context_->GetLiveRegistrations();
   for (const auto& key_registration : registrations) {
@@ -800,7 +795,23 @@
   }
 }
 
+#if DCHECK_IS_ON()
+bool ServiceWorkerProviderHost::IsMatchingRegistration(
+    ServiceWorkerRegistration* registration) const {
+  std::string spec = registration->pattern().spec();
+  size_t key = spec.size();
+
+  auto iter = matching_registrations_.find(key);
+  if (iter == matching_registrations_.end())
+    return false;
+  if (iter->second.get() != registration)
+    return false;
+  return true;
+}
+#endif  // DCHECK_IS_ON()
+
 void ServiceWorkerProviderHost::RemoveAllMatchingRegistrations() {
+  DCHECK(!controller_registration());
   for (const auto& it : matching_registrations_) {
     ServiceWorkerRegistration* registration = it.second.get();
     registration->RemoveListener(this);
@@ -845,8 +856,8 @@
     return;
   }
 
-  DCHECK(associated_registration_);
-  DCHECK_EQ(associated_registration_->active_version(), controller_.get());
+  DCHECK(controller_registration());
+  DCHECK_EQ(controller_registration_->active_version(), controller_.get());
 
   controller_info->mode = GetControllerMode();
 
@@ -872,6 +883,18 @@
                             notify_controllerchange);
 }
 
+#if DCHECK_IS_ON()
+void ServiceWorkerProviderHost::CheckControllerConsistency() const {
+  if (!controller_) {
+    DCHECK(!controller_registration_);
+    return;
+  }
+  DCHECK(IsProviderForClient());
+  DCHECK(controller_registration_);
+  DCHECK_EQ(controller_->registration_id(), controller_registration_->id());
+}
+#endif
+
 void ServiceWorkerProviderHost::Register(
     const GURL& script_url,
     blink::mojom::ServiceWorkerRegistrationOptionsPtr options,
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 3f11077bd..a6906b6b 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -198,33 +198,21 @@
   // and if it has a fetch event handler.
   blink::mojom::ControllerServiceWorkerMode GetControllerMode() const;
 
-  // Returns this provider's controller. The controller is typically the same as
-  // active_version() but can differ in the following cases:
-  // (1) The client had a controller but NotifyControllerLost() was called due
-  // to an exceptional circumstance.
-  // (2) During algorithms such as the update, skipWaiting(), and claim() steps,
-  // the active version and controller may temporarily differ. For example, to
-  // perform skipWaiting(), the registration's active version is updated first
-  // and then the provider host's controlling version is updated to match it.
+  // For service worker clients. Returns this client's controller.
   ServiceWorkerVersion* controller() const {
-    // Only clients can have controllers.
-    DCHECK(!controller_ || IsProviderForClient());
+#if DCHECK_IS_ON()
+    CheckControllerConsistency();
+#endif  // DCHECK_IS_ON()
+
     return controller_.get();
   }
 
-  ServiceWorkerVersion* active_version() const {
-    return associated_registration_.get()
-               ? associated_registration_->active_version()
-               : nullptr;
-  }
+  ServiceWorkerRegistration* controller_registration() const {
+#if DCHECK_IS_ON()
+    CheckControllerConsistency();
+#endif  // DCHECK_IS_ON()
 
-  // Returns the associated registration. This is typically the registration of
-  // the controller() if it exists. It may also exist when controller() is null
-  // after NotifyControllerLost().
-  ServiceWorkerRegistration* associated_registration() const {
-    // Only clients can have an associated registration.
-    DCHECK(!associated_registration_ || IsProviderForClient());
-    return associated_registration_.get();
+    return controller_registration_.get();
   }
 
   // For service worker execution contexts. The version of the service worker.
@@ -248,10 +236,9 @@
   //
   // - During navigation, right after a request handler for the main resource
   //   has found the matching registration and has started the worker.
-  // - When a controller is updated by SetControllerVersionAttribute() (e.g.
-  //   by OnSkippedWaiting, {Dis,}AssociateRegistration, NotifyControllerLost
-  //   or ClaimedByRegistration). In some cases the controller worker may not
-  //   be started yet.
+  // - When a controller is updated by UpdateController() (e.g.
+  //   by OnSkippedWaiting() or SetControllerRegistration()).
+  //   In some cases the controller worker may not be started yet.
   //
   // This may return nullptr if the controller service worker does not have a
   // fetch handler, i.e. when the renderer does not need the controller ptr.
@@ -301,14 +288,13 @@
   // Can only be called when IsProviderForClient() is true.
   blink::mojom::ServiceWorkerClientType client_type() const;
 
-  // For service worker clients. Associates to |registration| to set the
-  // controller. If |notify_controllerchange| is true, instructs the renderer to
-  // dispatch a 'controllerchange' event.
-  void AssociateRegistration(ServiceWorkerRegistration* registration,
-                             bool notify_controllerchange);
-
-  // For service worker clients. Clears the controller.
-  void DisassociateRegistration();
+  // For service worker clients. Makes this client be controlled by
+  // |registration|'s active worker, or makes this client be not
+  // controlled if |registration| is null. If |notify_controllerchange| is true,
+  // instructs the renderer to dispatch a 'controllerchange' event.
+  void SetControllerRegistration(
+      scoped_refptr<ServiceWorkerRegistration> controller_registration,
+      bool notify_controllerchange);
 
   // Returns a handler for a request. May return nullptr if the request doesn't
   // require special handling.
@@ -370,7 +356,8 @@
   void CountFeature(blink::mojom::WebFeature feature);
 
   // |registration| claims the document to be controlled.
-  void ClaimedByRegistration(ServiceWorkerRegistration* registration);
+  void ClaimedByRegistration(
+      scoped_refptr<ServiceWorkerRegistration> registration);
 
   // For service worker clients. Completes initialization of
   // provider hosts used for navigation requests.
@@ -502,15 +489,20 @@
       ServiceWorkerRegistration* registration) override;
   void OnSkippedWaiting(ServiceWorkerRegistration* registration) override;
 
-  // Sets the controller field to |version| or if |version| is nullptr, clears
-  // the field. If |notify_controllerchange| is true, instructs the renderer to
-  // dispatch a 'controller' change event.
-  void SetControllerVersionAttribute(ServiceWorkerVersion* version,
-                                     bool notify_controllerchange);
+  // Sets the controller to |controller_registration_->active_version()| or null
+  // if there is no associated registration.
+  //
+  // If |notify_controllerchange| is true, instructs the renderer to dispatch a
+  // 'controller' change event.
+  void UpdateController(bool notify_controllerchange);
 
   // Syncs matching registrations with live registrations.
   void SyncMatchingRegistrations();
 
+#if DCHECK_IS_ON()
+  bool IsMatchingRegistration(ServiceWorkerRegistration* registration) const;
+#endif  // DCHECK_IS_ON()
+
   // Discards all references to matching registrations.
   void RemoveAllMatchingRegistrations();
 
@@ -521,6 +513,10 @@
   // instructs the renderer to dispatch a 'controllerchange' event.
   void SendSetControllerServiceWorker(bool notify_controllerchange);
 
+#if DCHECK_IS_ON()
+  void CheckControllerConsistency() const;
+#endif  // DCHECK_IS_ON()
+
   // Implements mojom::ServiceWorkerContainerHost.
   void Register(const GURL& script_url,
                 blink::mojom::ServiceWorkerRegistrationOptionsPtr options,
@@ -607,16 +603,13 @@
   GURL document_url_;
   GURL topmost_frame_url_;
 
-  // The registration of |controller_|, if it exists. This might also be
-  // set even if |controller_| is null due to NotifyControllerLost.
-  scoped_refptr<ServiceWorkerRegistration> associated_registration_;
-
   // Keyed by registration scope URL length.
   using ServiceWorkerRegistrationMap =
       std::map<size_t, scoped_refptr<ServiceWorkerRegistration>>;
   // Contains all living registrations whose pattern this document's URL
-  // starts with. It is empty if IsContextSecureForServiceWorker() is
-  // false.
+  // starts with, used for .ready and claim(). It is empty if
+  // IsContextSecureForServiceWorker() is false. See also
+  // AddMatchingRegistration().
   ServiceWorkerRegistrationMap matching_registrations_;
 
   // Contains all ServiceWorkerRegistrationObjectHost instances corresponding to
@@ -644,8 +637,15 @@
   std::unique_ptr<GetRegistrationForReadyCallback> get_ready_callback_;
 
   // For service worker clients. The controller service worker (i.e.,
-  // ServiceWorkerContainer#controller).
+  // ServiceWorkerContainer#controller) and its registration. The controller is
+  // typically the same as the registration's active version, but during
+  // algorithms such as the update, skipWaiting(), and claim() steps, the active
+  // version and controller may temporarily differ. For example, to perform
+  // skipWaiting(), the registration's active version is updated first and then
+  // the provider host's controller is updated to match it.
   scoped_refptr<ServiceWorkerVersion> controller_;
+  scoped_refptr<ServiceWorkerRegistration> controller_registration_;
+
   // For service worker execution contexts. The ServiceWorkerVersion of the
   // service worker this is a provider for. This is nullptr if the service
   // worker is still being started up (until CompleteStartWorkerPreparation() is
diff --git a/content/browser/service_worker/service_worker_provider_host_unittest.cc b/content/browser/service_worker/service_worker_provider_host_unittest.cc
index 42b9f0c..20e17ad4 100644
--- a/content/browser/service_worker/service_worker_provider_host_unittest.cc
+++ b/content/browser/service_worker/service_worker_provider_host_unittest.cc
@@ -477,18 +477,18 @@
 
   // Finish the navigation.
   FinishNavigation(host.get(), std::move(info));
-  host->AssociateRegistration(registration1_.get(),
-                              false /* notify_controllerchange */);
+  host->SetControllerRegistration(registration1_,
+                                  false /* notify_controllerchange */);
   base::RunLoop().RunUntilIdle();
 
   // The page should be controlled since there was an active version at the
   // time navigation started. The SetController IPC should have been sent.
-  EXPECT_TRUE(host->active_version());
-  EXPECT_EQ(host->active_version(), host->controller());
+  EXPECT_TRUE(host->controller());
   EXPECT_TRUE(container->was_set_controller_called());
+  EXPECT_EQ(registration1_.get(), host->MatchRegistration());
 }
 
-TEST_P(ServiceWorkerProviderHostTest, ActiveIsNotController) {
+TEST_P(ServiceWorkerProviderHostTest, UncontrolledWithMatchingRegistration) {
   // Create a host.
   base::WeakPtr<ServiceWorkerProviderHost> host =
       ServiceWorkerProviderHost::PreCreateNavigationHost(
@@ -507,11 +507,8 @@
       1 /* version_id */, helper_->context()->AsWeakPtr());
   registration1_->SetInstallingVersion(version);
 
-
   // Finish the navigation.
   FinishNavigation(host.get(), std::move(info));
-  host->AssociateRegistration(registration1_.get(),
-                              false /* notify_controllerchange */);
   // Promote the worker to active while navigation is still happening.
   registration1_->SetActiveVersion(version);
   base::RunLoop().RunUntilIdle();
@@ -519,9 +516,11 @@
   // The page should not be controlled since there was no active version at the
   // time navigation started. Furthermore, no SetController IPC should have been
   // sent.
-  EXPECT_TRUE(host->active_version());
   EXPECT_FALSE(host->controller());
   EXPECT_FALSE(container->was_set_controller_called());
+  // However, the host should know the registration is its best match, for
+  // .ready and claim().
+  EXPECT_EQ(registration1_.get(), host->MatchRegistration());
 }
 
 TEST_P(ServiceWorkerProviderHostTest,
@@ -928,7 +927,7 @@
   // Make the active worker the controller and give it an ongoing request. This
   // way when a waiting worker calls SkipWaiting(), activation won't trigger
   // until we're ready.
-  provider_host1->AssociateRegistration(registration1_.get(), false);
+  provider_host1->SetControllerRegistration(registration1_, false);
   EXPECT_EQ(version1.get(), provider_host1->controller());
   // The worker must be running to have a request.
   version1->StartWorker(ServiceWorkerMetrics::EventType::PUSH,
diff --git a/content/browser/service_worker/service_worker_request_handler.cc b/content/browser/service_worker/service_worker_request_handler.cc
index 1503320..1090e1e3 100644
--- a/content/browser/service_worker/service_worker_request_handler.cc
+++ b/content/browser/service_worker/service_worker_request_handler.cc
@@ -284,7 +284,7 @@
   ServiceWorkerRequestHandler* handler = GetHandler(request);
   if (!handler || !handler->provider_host_)
     return false;
-  return handler->provider_host_->associated_registration() ||
+  return handler->provider_host_->controller() ||
          handler->provider_host_->running_hosted_version();
 }
 
diff --git a/content/browser/service_worker/service_worker_url_request_job_unittest.cc b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
index a73fa4c9..a0a30b12 100644
--- a/content/browser/service_worker/service_worker_url_request_job_unittest.cc
+++ b/content/browser/service_worker/service_worker_url_request_job_unittest.cc
@@ -254,8 +254,8 @@
     provider_host_ = provider_host->AsWeakPtr();
     provider_host->SetDocumentUrl(GURL("https://example.com/"));
     registration_->SetActiveVersion(version_);
-    provider_host->AssociateRegistration(registration_.get(),
-                                         false /* notify_controllerchange */);
+    provider_host->SetControllerRegistration(
+        registration_, false /* notify_controllerchange */);
 
     // Set up scaffolding for handling URL requests.
     ChromeBlobStorageContext* chrome_blob_storage_context =
@@ -389,11 +389,11 @@
       *result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_PROVIDER_HOST;
       return nullptr;
     }
-    if (!provider_host_->active_version()) {
+    if (!provider_host_->controller()) {
       *result = ServiceWorkerMetrics::REQUEST_JOB_ERROR_NO_ACTIVE_VERSION;
       return nullptr;
     }
-    return provider_host_->active_version();
+    return provider_host_->controller();
   }
 
   bool RequestStillValid(
diff --git a/content/browser/service_worker/service_worker_version.cc b/content/browser/service_worker/service_worker_version.cc
index b9ae2602..9a00d9a 100644
--- a/content/browser/service_worker/service_worker_version.cc
+++ b/content/browser/service_worker/service_worker_version.cc
@@ -498,8 +498,8 @@
   // and soon no one might hold a reference to us.
   context_->ProtectVersion(base::WrapRefCounted(this));
   update_timer_.Start(FROM_HERE, kUpdateDelay,
-                      base::Bind(&ServiceWorkerVersion::StartUpdate,
-                                 weak_factory_.GetWeakPtr()));
+                      base::BindOnce(&ServiceWorkerVersion::StartUpdate,
+                                     weak_factory_.GetWeakPtr()));
 }
 
 void ServiceWorkerVersion::StartUpdate() {
@@ -755,6 +755,10 @@
 }
 
 void ServiceWorkerVersion::Doom() {
+  // Protect |this| because NotifyControllerLost() and Stop() callees
+  // may drop references to |this|.
+  scoped_refptr<ServiceWorkerVersion> protect(this);
+
   // Tell controllees that this version is dead. Each controllee will call
   // ServiceWorkerVersion::RemoveControllee(), so be careful with iterators.
   auto iter = controllee_map_.begin();
@@ -1215,7 +1219,7 @@
     binding_.Close();
     return;
   }
-  if (provider_host->active_version() != this) {
+  if (provider_host->controller() != this) {
     std::move(callback).Run(
         false /* success */, nullptr /* client */,
         std::string(
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index dbd520b0..5219078 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -559,7 +559,7 @@
       true /* is_parent_frame_secure */, helper_->context()->AsWeakPtr(),
       &remote_endpoint);
   host->SetDocumentUrl(registration_->pattern());
-  host->AssociateRegistration(registration_.get(), false);
+  host->SetControllerRegistration(registration_, false);
   EXPECT_TRUE(version_->HasControllee());
   EXPECT_TRUE(host->controller());
 
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index 407310c..aa29ba3 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -9,6 +9,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/unguessable_token.h"
+#include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/devtools/shared_worker_devtools_manager.h"
 #include "content/browser/interface_provider_filtering.h"
 #include "content/browser/renderer_interface_binders.h"
@@ -416,6 +417,12 @@
   worker_->BindDevToolsAgent(std::move(request));
 }
 
+void SharedWorkerHost::SetAppCacheHandle(
+    std::unique_ptr<AppCacheNavigationHandle> appcache_handle) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  appcache_handle_ = std::move(appcache_handle);
+}
+
 void SharedWorkerHost::OnClientConnectionLost() {
   // We'll get a notification for each dropped connection.
   for (auto it = clients_.begin(); it != clients_.end(); ++it) {
diff --git a/content/browser/shared_worker/shared_worker_host.h b/content/browser/shared_worker/shared_worker_host.h
index 95f9f2c2..d8c7382 100644
--- a/content/browser/shared_worker/shared_worker_host.h
+++ b/content/browser/shared_worker/shared_worker_host.h
@@ -33,6 +33,8 @@
 }
 
 namespace content {
+
+class AppCacheNavigationHandle;
 class SharedWorkerContentSettingsProxyImpl;
 class SharedWorkerInstance;
 class SharedWorkerServiceImpl;
@@ -86,6 +88,9 @@
 
   void BindDevToolsAgent(blink::mojom::DevToolsAgentAssociatedRequest request);
 
+  void SetAppCacheHandle(
+      std::unique_ptr<AppCacheNavigationHandle> appcache_handle);
+
   SharedWorkerInstance* instance() { return instance_.get(); }
   int process_id() const { return process_id_; }
   bool IsAvailable() const;
@@ -172,6 +177,11 @@
   mojo::Binding<service_manager::mojom::InterfaceProvider>
       interface_provider_binding_;
 
+  // NetworkService:
+  // The handle owns the precreated AppCacheHost until it's claimed by the
+  // renderer after main script loading finishes.
+  std::unique_ptr<AppCacheNavigationHandle> appcache_handle_;
+
   Phase phase_ = Phase::kInitial;
 
   base::WeakPtrFactory<SharedWorkerHost> weak_factory_;
diff --git a/content/browser/shared_worker/shared_worker_script_loader.cc b/content/browser/shared_worker/shared_worker_script_loader.cc
index 81fb376..d363f74 100644
--- a/content/browser/shared_worker/shared_worker_script_loader.cc
+++ b/content/browser/shared_worker/shared_worker_script_loader.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/shared_worker/shared_worker_script_loader.h"
 
+#include "content/browser/appcache/appcache_request_handler.h"
 #include "content/browser/loader/navigation_loader_interceptor.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/public/browser/resource_context.h"
@@ -20,6 +21,7 @@
     const network::ResourceRequest& resource_request,
     network::mojom::URLLoaderClientPtr client,
     base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
+    base::WeakPtr<AppCacheHost> appcache_host,
     ResourceContext* resource_context,
     scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation)
@@ -37,9 +39,19 @@
   DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
 
   if (service_worker_provider_host_) {
-    service_worker_interceptor_ =
+    std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor =
         ServiceWorkerRequestHandler::InitializeForSharedWorker(
             resource_request_, service_worker_provider_host_);
+    if (service_worker_interceptor)
+      interceptors_.push_back(std::move(service_worker_interceptor));
+  }
+
+  if (appcache_host) {
+    std::unique_ptr<NavigationLoaderInterceptor> appcache_interceptor =
+        AppCacheRequestHandler::InitializeForMainResourceNetworkService(
+            resource_request_, appcache_host, default_loader_factory_);
+    if (appcache_interceptor)
+      interceptors_.push_back(std::move(appcache_interceptor));
   }
 
   Start();
@@ -48,12 +60,12 @@
 SharedWorkerScriptLoader::~SharedWorkerScriptLoader() = default;
 
 void SharedWorkerScriptLoader::Start() {
-  if (service_worker_interceptor_) {
-    service_worker_interceptor_->MaybeCreateLoader(
+  if (interceptor_index_ < interceptors_.size()) {
+    auto* interceptor = interceptors_[interceptor_index_++].get();
+    interceptor->MaybeCreateLoader(
         resource_request_, resource_context_,
         base::BindOnce(&SharedWorkerScriptLoader::MaybeStartLoader,
-                       weak_factory_.GetWeakPtr(),
-                       service_worker_interceptor_.get()));
+                       weak_factory_.GetWeakPtr(), interceptor));
     return;
   }
 
@@ -63,6 +75,16 @@
 void SharedWorkerScriptLoader::MaybeStartLoader(
     NavigationLoaderInterceptor* interceptor,
     SingleRequestURLLoaderFactory::RequestHandler single_request_handler) {
+  DCHECK(interceptor);
+
+  // TODO(nhiroki): Create SubresourceLoaderParams for intercepting subresource
+  // requests and populating the "controller" field in ServiceWorkerContainer,
+  // and send the params to the renderer when we create the SharedWorker.
+  // Note that we shouldn't try the next interceptor if this interceptor
+  // provides SubresourceLoaderParams. See comments on
+  // NavigationLoaderInterceptor::MaybeCreateSubresourceLoaderParams() for
+  // details.
+
   if (single_request_handler) {
     // The interceptor elected to handle the request. Use it.
     network::mojom::URLLoaderClientPtr client;
@@ -76,7 +98,8 @@
     return;
   }
 
-  LoadFromNetwork();
+  // Continue until all the interceptors are tried.
+  Start();
 }
 
 void SharedWorkerScriptLoader::LoadFromNetwork() {
@@ -117,6 +140,7 @@
   resource_request_.referrer_policy = redirect_info_->new_referrer_policy;
 
   // Restart the request.
+  interceptor_index_ = 0;
   url_loader_client_binding_.Unbind();
   redirect_info_.reset();
   Start();
diff --git a/content/browser/shared_worker/shared_worker_script_loader.h b/content/browser/shared_worker/shared_worker_script_loader.h
index e7eb646..4730433 100644
--- a/content/browser/shared_worker/shared_worker_script_loader.h
+++ b/content/browser/shared_worker/shared_worker_script_loader.h
@@ -17,6 +17,8 @@
 }  // namespace network
 
 namespace content {
+
+class AppCacheHost;
 class NavigationLoaderInterceptor;
 class ResourceContext;
 class ServiceWorkerProviderHost;
@@ -47,6 +49,7 @@
       const network::ResourceRequest& resource_request,
       network::mojom::URLLoaderClientPtr client,
       base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
+      base::WeakPtr<AppCacheHost> appcache_host,
       ResourceContext* resource_context,
       scoped_refptr<network::SharedURLLoaderFactory> default_loader_factory,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation);
@@ -85,8 +88,10 @@
       SingleRequestURLLoaderFactory::RequestHandler single_request_handler);
   void LoadFromNetwork();
 
-  // TODO(falken): Add other interceptors like in NavigationURLLoaderImpl.
-  std::unique_ptr<NavigationLoaderInterceptor> service_worker_interceptor_;
+  // The order of the interceptors is important. The former interceptor can
+  // preferentially get a chance to intercept a network request.
+  std::vector<std::unique_ptr<NavigationLoaderInterceptor>> interceptors_;
+  size_t interceptor_index_ = 0;
 
   const int32_t routing_id_;
   const int32_t request_id_;
diff --git a/content/browser/shared_worker/shared_worker_script_loader_factory.cc b/content/browser/shared_worker/shared_worker_script_loader_factory.cc
index 6a21c378..c4a876b 100644
--- a/content/browser/shared_worker/shared_worker_script_loader_factory.cc
+++ b/content/browser/shared_worker/shared_worker_script_loader_factory.cc
@@ -10,6 +10,7 @@
 #include "content/browser/service_worker/service_worker_provider_host.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/browser/shared_worker/shared_worker_script_loader.h"
+#include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -21,17 +22,22 @@
 SharedWorkerScriptLoaderFactory::SharedWorkerScriptLoaderFactory(
     ServiceWorkerContextWrapper* context,
     base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host,
+    base::WeakPtr<AppCacheHost> appcache_host,
     ResourceContext* resource_context,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
-    : service_worker_provider_host_(service_worker_provider_host),
+    : service_worker_provider_host_(std::move(service_worker_provider_host)),
+      appcache_host_(std::move(appcache_host)),
       resource_context_(resource_context),
       loader_factory_(std::move(loader_factory)) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   DCHECK(blink::ServiceWorkerUtils::IsServicificationEnabled());
   DCHECK_EQ(service_worker_provider_host_->provider_type(),
             blink::mojom::ServiceWorkerProviderType::kForSharedWorker);
 }
 
-SharedWorkerScriptLoaderFactory::~SharedWorkerScriptLoaderFactory() {}
+SharedWorkerScriptLoaderFactory::~SharedWorkerScriptLoaderFactory() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
 
 void SharedWorkerScriptLoaderFactory::CreateLoaderAndStart(
     network::mojom::URLLoaderRequest request,
@@ -41,6 +47,8 @@
     const network::ResourceRequest& resource_request,
     network::mojom::URLLoaderClientPtr client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
   // Handle only the main script (RESOURCE_TYPE_SHARED_WORKER). Import scripts
   // should go to the network loader or controller.
   if (resource_request.resource_type != RESOURCE_TYPE_SHARED_WORKER) {
@@ -54,8 +62,8 @@
   mojo::MakeStrongBinding(
       std::make_unique<SharedWorkerScriptLoader>(
           routing_id, request_id, options, resource_request, std::move(client),
-          service_worker_provider_host_, resource_context_, loader_factory_,
-          traffic_annotation),
+          service_worker_provider_host_, appcache_host_, resource_context_,
+          loader_factory_, traffic_annotation),
       std::move(request));
 }
 
diff --git a/content/browser/shared_worker/shared_worker_script_loader_factory.h b/content/browser/shared_worker/shared_worker_script_loader_factory.h
index 2e42cfaa..356baea 100644
--- a/content/browser/shared_worker/shared_worker_script_loader_factory.h
+++ b/content/browser/shared_worker/shared_worker_script_loader_factory.h
@@ -14,6 +14,7 @@
 
 namespace content {
 
+class AppCacheHost;
 class ServiceWorkerContextWrapper;
 class ServiceWorkerProviderHost;
 class ResourceContext;
@@ -38,6 +39,7 @@
   SharedWorkerScriptLoaderFactory(
       ServiceWorkerContextWrapper* context,
       base::WeakPtr<ServiceWorkerProviderHost> provider_host,
+      base::WeakPtr<AppCacheHost> appcache_host,
       ResourceContext* resource_context,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
   ~SharedWorkerScriptLoaderFactory() override;
@@ -55,6 +57,7 @@
 
  private:
   base::WeakPtr<ServiceWorkerProviderHost> service_worker_provider_host_;
+  base::WeakPtr<AppCacheHost> appcache_host_;
   ResourceContext* resource_context_ = nullptr;
   scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
 
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc
index d6b462f..165dca9 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -10,10 +10,12 @@
 #include <iterator>
 
 #include "base/callback.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/task_scheduler/post_task.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
+#include "content/browser/appcache/appcache_navigation_handle_core.h"
 #include "content/browser/file_url_loader_factory.h"
 #include "content/browser/shared_worker/shared_worker_host.h"
 #include "content/browser/shared_worker/shared_worker_instance.h"
@@ -31,6 +33,7 @@
 #include "content/public/common/bind_interface_helpers.h"
 #include "mojo/public/cpp/bindings/strong_associated_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/message_port/message_port_channel.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "url/origin.h"
@@ -89,6 +92,7 @@
     std::unique_ptr<URLLoaderFactoryBundleInfo>
         factory_bundle_for_renderer_info,
     scoped_refptr<ServiceWorkerContextWrapper> context,
+    AppCacheNavigationHandleCore* appcache_handle_core,
     std::unique_ptr<network::SharedURLLoaderFactoryInfo>
         blob_url_loader_factory_info,
     int process_id,
@@ -128,12 +132,20 @@
     factory_bundle->SetDefaultFactory(std::move(network_factory_ptr));
   }
 
+  // It's safe for |appcache_handle_core| to be a raw pointer. The core is owned
+  // by AppCacheNavigationHandle on the UI thread, which posts a task to delete
+  // the core on the IO thread on destruction, which must happen after this
+  // task.
+  base::WeakPtr<AppCacheHost> appcache_host =
+      appcache_handle_core ? appcache_handle_core->host()->GetWeakPtr()
+                           : nullptr;
+
   // Create the SharedWorkerScriptLoaderFactory.
   network::mojom::URLLoaderFactoryAssociatedPtrInfo script_loader_factory;
   mojo::MakeStrongAssociatedBinding(
       std::make_unique<SharedWorkerScriptLoaderFactory>(
-          context.get(), host->AsWeakPtr(), context->resource_context(),
-          std::move(url_loader_factory)),
+          context.get(), host->AsWeakPtr(), std::move(appcache_host),
+          context->resource_context(), std::move(url_loader_factory)),
       mojo::MakeRequest(&script_loader_factory));
 
   // We continue in StartWorker.
@@ -294,8 +306,9 @@
 
   StoragePartitionImpl* storage_partition =
       service_worker_context_->storage_partition();
-  // Bounce to the IO thread to setup service worker support in case the request
-  // for the worker script will need to be intercepted by service workers.
+
+  // Bounce to the IO thread to setup service worker and appcache support in
+  // case the request for the worker script will need to be intercepted by them.
   if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
     if (!storage_partition) {
       // The context is shutting down. Just drop the request.
@@ -312,9 +325,15 @@
         CreateFactoryBundle(process_id, storage_partition,
                             constructor_uses_file_url);
 
-    // TODO(nhiroki): Create an instance of AppCacheNavigationHandle from
-    // |appcache_service_| and pass its core() to the IO thread in order to set
-    // up an interceptor for AppCache.
+    // An appcache interceptor is available only when the network service is
+    // enabled.
+    AppCacheNavigationHandleCore* appcache_handle_core = nullptr;
+    if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+      auto appcache_handle =
+          std::make_unique<AppCacheNavigationHandle>(appcache_service_.get());
+      appcache_handle_core = appcache_handle->core();
+      weak_host->SetAppCacheHandle(std::move(appcache_handle));
+    }
 
     BrowserThread::PostTask(
         BrowserThread::IO, FROM_HERE,
@@ -324,6 +343,7 @@
                 ->url_loader_factory_getter(),
             std::move(factory_bundle_for_browser),
             std::move(factory_bundle_for_renderer), service_worker_context_,
+            appcache_handle_core,
             blob_url_loader_factory ? blob_url_loader_factory->Clone()
                                     : nullptr,
             process_id,
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 13f5538..ca76b2c 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -25,6 +25,7 @@
 #include "content/browser/browser_main_loop.h"
 #include "content/browser/browsing_data/storage_partition_http_cache_data_remover.h"
 #include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/cookie_store/cookie_store_context.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
 #include "content/browser/gpu/shader_cache_factory.h"
@@ -551,7 +552,8 @@
 std::unique_ptr<StoragePartitionImpl> StoragePartitionImpl::Create(
     BrowserContext* context,
     bool in_memory,
-    const base::FilePath& relative_partition_path) {
+    const base::FilePath& relative_partition_path,
+    const std::string& partition_domain) {
   // Ensure that these methods are called on the UI thread, except for
   // unittests where a UI thread might not have been created.
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
@@ -671,6 +673,36 @@
   partition->cookie_store_context_->Initialize(
       partition->service_worker_context_, base::DoNothing());
 
+  if (base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+    // TODO(crbug.com/867552): Currently we misuse GetCachePath to check if
+    // code caching is enabled. Fix this by having a better API.
+
+    // For Incognito mode, we should not persist anything on the disk so
+    // we do not create a code cache. Caching the generated code in memory
+    // is not useful, since V8 already maintains one copy in memory.
+    if (!in_memory && !context->GetCachePath().empty()) {
+      partition->generated_code_cache_context_ =
+          base::MakeRefCounted<GeneratedCodeCacheContext>();
+
+      base::FilePath code_cache_path;
+      if (partition_domain.empty()) {
+        code_cache_path = context->GetCachePath().AppendASCII("Code Cache");
+      } else {
+        // For site isolated partitions use the config directory.
+        code_cache_path = context->GetPath()
+                              .Append(relative_partition_path)
+                              .AppendASCII("Code Cache");
+      }
+
+      // TODO(crbug.com/867552): Currently it is set to an arbitary value.
+      // Update it based on data. Also add a mechanism similar to QuotaSettings
+      // to let embedders control the size of this cache.
+      constexpr int kSizeInBytes = 10 * 1024 * 1024;
+      partition->GetGeneratedCodeCacheContext()->Initialize(code_cache_path,
+                                                            kSizeInBytes);
+    }
+  }
+
   return partition;
 }
 
@@ -816,6 +848,11 @@
   return cookie_store_context_.get();
 }
 
+GeneratedCodeCacheContext*
+StoragePartitionImpl::GetGeneratedCodeCacheContext() {
+  return generated_code_cache_context_.get();
+}
+
 void StoragePartitionImpl::OpenLocalStorage(
     const url::Origin& origin,
     blink::mojom::StorageAreaRequest request) {
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 9bffbf53f..6f6c5c1e 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -49,6 +49,7 @@
 class BlobRegistryWrapper;
 class PrefetchURLLoaderService;
 class WebPackageContextImpl;
+class GeneratedCodeCacheContext;
 
 class CONTENT_EXPORT StoragePartitionImpl
     : public StoragePartition,
@@ -99,6 +100,7 @@
   CacheStorageContextImpl* GetCacheStorageContext() override;
   ServiceWorkerContextWrapper* GetServiceWorkerContext() override;
   SharedWorkerServiceImpl* GetSharedWorkerService() override;
+  GeneratedCodeCacheContext* GetGeneratedCodeCacheContext() override;
 #if !defined(OS_ANDROID)
   HostZoomMap* GetHostZoomMap() override;
   HostZoomLevelContext* GetHostZoomLevelContext() override;
@@ -234,7 +236,8 @@
   static std::unique_ptr<StoragePartitionImpl> Create(
       BrowserContext* context,
       bool in_memory,
-      const base::FilePath& relative_partition_path);
+      const base::FilePath& relative_partition_path,
+      const std::string& partition_domain);
 
   StoragePartitionImpl(BrowserContext* browser_context,
                        const base::FilePath& partition_path,
@@ -314,6 +317,7 @@
   scoped_refptr<BlobRegistryWrapper> blob_registry_;
   scoped_refptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
   scoped_refptr<CookieStoreContext> cookie_store_context_;
+  scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
 
   // BindingSet for StoragePartitionService, using the process id as the
   // binding context type. The process id can subsequently be used during
diff --git a/content/browser/storage_partition_impl_map.cc b/content/browser/storage_partition_impl_map.cc
index 9f56c4c..3a478286c 100644
--- a/content/browser/storage_partition_impl_map.cc
+++ b/content/browser/storage_partition_impl_map.cc
@@ -25,6 +25,7 @@
 #include "content/browser/appcache/chrome_appcache_service.h"
 #include "content/browser/background_fetch/background_fetch_context.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/cookie_store/cookie_store_context.h"
 #include "content/browser/devtools/devtools_url_request_interceptor.h"
 #include "content/browser/fileapi/browser_file_system_helper.h"
@@ -44,6 +45,7 @@
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_constants.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "crypto/sha2.h"
@@ -396,7 +398,7 @@
 
   std::unique_ptr<StoragePartitionImpl> partition_ptr(
       StoragePartitionImpl::Create(browser_context_, in_memory,
-                                   relative_partition_path));
+                                   relative_partition_path, partition_domain));
   StoragePartitionImpl* partition = partition_ptr.get();
   partitions_[partition_config] = std::move(partition_ptr);
 
diff --git a/content/browser/storage_partition_impl_unittest.cc b/content/browser/storage_partition_impl_unittest.cc
index b151ad3..2a3c801 100644
--- a/content/browser/storage_partition_impl_unittest.cc
+++ b/content/browser/storage_partition_impl_unittest.cc
@@ -13,11 +13,14 @@
 #include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/services/leveldb/public/cpp/util.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/dom_storage/local_storage_database.pb.h"
 #include "content/browser/gpu/shader_cache_factory.h"
 #include "content/browser/storage_partition_impl.h"
 #include "content/public/browser/local_storage_usage_info.h"
 #include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -58,6 +61,7 @@
 const char kTestOrigin2[] = "http://host2:1/";
 const char kTestOrigin3[] = "http://host3:1/";
 const char kTestOriginDevTools[] = "chrome-devtools://abcdefghijklmnopqrstuvw/";
+const char kTestURL[] = "http://host4/script.js";
 
 #if BUILDFLAG(ENABLE_PLUGINS)
 const char kWidevineCdmPluginId[] = "application_x-ppapi-widevine-cdm";
@@ -68,6 +72,7 @@
 const GURL kOrigin2(kTestOrigin2);
 const GURL kOrigin3(kTestOrigin3);
 const GURL kOriginDevTools(kTestOriginDevTools);
+const GURL kResourceURL(kTestURL);
 
 const blink::mojom::StorageType kTemporary =
     blink::mojom::StorageType::kTemporary;
@@ -272,6 +277,49 @@
   DISALLOW_COPY_AND_ASSIGN(RemoveLocalStorageTester);
 };
 
+class RemoveCodeCacheTester {
+ public:
+  explicit RemoveCodeCacheTester(GeneratedCodeCacheContext* code_cache_context)
+      : code_cache_context_(code_cache_context) {}
+
+  bool ContainsEntry(GURL url, url::Origin origin) {
+    entry_exists_ = false;
+    GeneratedCodeCache::ReadDataCallback callback = base::BindRepeating(
+        &RemoveCodeCacheTester::FetchEntryCallback, base::Unretained(this));
+    code_cache_context_->generated_code_cache()->FetchEntry(url, origin,
+                                                            callback);
+    await_completion_.BlockUntilNotified();
+    return entry_exists_;
+  }
+
+  void AddEntry(GURL url, url::Origin origin, const std::string& data) {
+    scoped_refptr<net::IOBufferWithSize> buffer(
+        new net::IOBufferWithSize(data.length()));
+    memcpy(buffer->data(), data.c_str(), data.length());
+    code_cache_context_->generated_code_cache()->WriteData(url, origin, buffer);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  std::string received_data() { return received_data_; }
+
+ private:
+  void FetchEntryCallback(scoped_refptr<net::IOBufferWithSize> buffer) {
+    if (buffer && buffer->data()) {
+      entry_exists_ = true;
+      received_data_ = std::string(buffer->data(), buffer->size());
+    } else {
+      entry_exists_ = false;
+    }
+    await_completion_.Notify();
+  }
+
+  bool entry_exists_;
+  AwaitCompletionHelper await_completion_;
+  GeneratedCodeCacheContext* code_cache_context_;
+  std::string received_data_;
+  DISALLOW_COPY_AND_ASSIGN(RemoveCodeCacheTester);
+};
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 class RemovePluginPrivateDataTester {
  public:
@@ -605,6 +653,15 @@
       time, time, run_loop->QuitClosure());
 }
 
+void ClearCodeCache(content::StoragePartition* partition,
+                    base::RunLoop* run_loop) {
+  base::Time delete_begin;
+  base::Time delete_end;
+  partition->ClearHttpAndMediaCaches(
+      delete_begin, delete_end, base::RepeatingCallback<bool(const GURL&)>(),
+      run_loop->QuitClosure());
+}
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 void ClearPluginPrivateData(content::StoragePartition* partition,
                             const GURL& storage_origin,
@@ -1255,6 +1312,32 @@
   EXPECT_TRUE(tester.DOMStorageExistsForOrigin(kOrigin3));
 }
 
+TEST_F(StoragePartitionImplTest, ClearCodeCache) {
+  // Run this test only when the IsolatedCodeCache feature is enabled
+  if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache))
+    return;
+
+  StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
+      BrowserContext::GetDefaultStoragePartition(browser_context()));
+  // Ensure code cache is initialized.
+  base::RunLoop().RunUntilIdle();
+
+  RemoveCodeCacheTester tester(partition->GetGeneratedCodeCacheContext());
+
+  url::Origin origin = url::Origin::Create(kOrigin1);
+  std::string data("SomeData");
+  tester.AddEntry(kResourceURL, origin, data);
+  EXPECT_TRUE(tester.ContainsEntry(kResourceURL, origin));
+  EXPECT_EQ(tester.received_data(), data);
+
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&ClearCodeCache, partition, &run_loop));
+  run_loop.Run();
+
+  EXPECT_FALSE(tester.ContainsEntry(kResourceURL, origin));
+}
+
 #if BUILDFLAG(ENABLE_PLUGINS)
 TEST_F(StoragePartitionImplTest, RemovePluginPrivateDataForever) {
   StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
diff --git a/content/browser/tracing/background_tracing_rule.cc b/content/browser/tracing/background_tracing_rule.cc
index f6961675..b39524d3 100644
--- a/content/browser/tracing/background_tracing_rule.cc
+++ b/content/browser/tracing/background_tracing_rule.cc
@@ -373,9 +373,10 @@
   void StartTimer() {
     int time_to_wait = base::RandInt(kReactiveTraceRandomStartTimeMin,
                                      kReactiveTraceRandomStartTimeMax);
-    trigger_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(time_to_wait),
-                         base::Bind(&TraceAtRandomIntervalsRule::OnTriggerTimer,
-                                    base::Unretained(this)));
+    trigger_timer_.Start(
+        FROM_HERE, base::TimeDelta::FromSeconds(time_to_wait),
+        base::BindOnce(&TraceAtRandomIntervalsRule::OnTriggerTimer,
+                       base::Unretained(this)));
   }
 
   int GetTraceDelay() const override {
diff --git a/content/browser/tracing/tracing_ui.cc b/content/browser/tracing/tracing_ui.cc
index fd922b3e9..c4da05c 100644
--- a/content/browser/tracing/tracing_ui.cc
+++ b/content/browser/tracing/tracing_ui.cc
@@ -237,9 +237,8 @@
   TraceUploader::UploadProgressCallback progress_callback =
       base::Bind(&TracingUI::OnTraceUploadProgress,
       weak_factory_.GetWeakPtr());
-  TraceUploader::UploadDoneCallback done_callback =
-      base::Bind(&TracingUI::OnTraceUploadComplete,
-      weak_factory_.GetWeakPtr());
+  TraceUploader::UploadDoneCallback done_callback = base::BindOnce(
+      &TracingUI::OnTraceUploadComplete, weak_factory_.GetWeakPtr());
 
   trace_uploader_ = delegate_->GetTraceUploader(
       BrowserContext::GetDefaultStoragePartition(
diff --git a/content/browser/webauth/authenticator_impl.cc b/content/browser/webauth/authenticator_impl.cc
index 80b9599..caf24411 100644
--- a/content/browser/webauth/authenticator_impl.cc
+++ b/content/browser/webauth/authenticator_impl.cc
@@ -464,7 +464,7 @@
 
   timer_->Start(
       FROM_HERE, options->adjusted_timeout,
-      base::Bind(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
+      base::BindOnce(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
   if (!connector_)
     connector_ = ServiceManagerConnection::GetForProcess()->GetConnector();
 
@@ -567,7 +567,7 @@
 
   timer_->Start(
       FROM_HERE, options->adjusted_timeout,
-      base::Bind(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
+      base::BindOnce(&AuthenticatorImpl::OnTimeout, base::Unretained(this)));
 
   if (!connector_)
     connector_ = ServiceManagerConnection::GetForProcess()->GetConnector();
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 279b13f..ab2d05c 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -439,6 +439,9 @@
   WebRuntimeFeatures::EnableCacheInlineScriptCode(
       base::FeatureList::IsEnabled(features::kCacheInlineScriptCode));
 
+  WebRuntimeFeatures::EnableIsolatedCodeCache(
+      base::FeatureList::IsEnabled(features::kIsolatedCodeCache));
+
   // Make srcset on link rel=preload work with SignedHTTPExchange flag too.
   if (base::FeatureList::IsEnabled(features::kSignedHTTPExchange))
     WebRuntimeFeatures::EnablePreloadImageSrcSetEnabled(true);
diff --git a/content/public/android/java/src/org/chromium/content/browser/Gamepad.java b/content/public/android/java/src/org/chromium/content/browser/Gamepad.java
index 0ce9b6a..b960fba7 100644
--- a/content/public/android/java/src/org/chromium/content/browser/Gamepad.java
+++ b/content/public/android/java/src/org/chromium/content/browser/Gamepad.java
@@ -6,22 +6,28 @@
 
 import android.content.Context;
 
+import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.WebContents;
+import org.chromium.content_public.browser.WebContents.UserDataFactory;
 import org.chromium.device.gamepad.GamepadList;
 
 /**
  * Encapsulates component class {@link GamepadList} for use in content, with regards
  * to its state according to content being attached to/detached from window.
  */
-public class Gamepad implements WindowEventObserver {
-    private Context mContext;
+class Gamepad implements WindowEventObserver {
+    private final Context mContext;
 
-    public static Gamepad create(Context context, WebContents webContents) {
-        return new Gamepad(context, webContents);
+    private static final class UserDataFactoryLazyHolder {
+        private static final UserDataFactory<Gamepad> INSTANCE = Gamepad::new;
     }
 
-    private Gamepad(Context context, WebContents webContents) {
-        mContext = context;
+    public static Gamepad from(WebContents webContents) {
+        return webContents.getOrSetUserData(Gamepad.class, UserDataFactoryLazyHolder.INSTANCE);
+    }
+
+    public Gamepad(WebContents webContents) {
+        mContext = ((WebContentsImpl) webContents).getContext();
         WindowEventObserverManager.from(webContents).addObserver(this);
     }
 
diff --git a/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java b/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java
index 9efcc9b..b022bd7 100644
--- a/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java
+++ b/content/public/android/java/src/org/chromium/content/browser/TapDisambiguator.java
@@ -15,6 +15,7 @@
 import org.chromium.content.browser.PopupZoomer.OnTapListener;
 import org.chromium.content.browser.PopupZoomer.OnVisibilityChangedListener;
 import org.chromium.content.browser.input.ImeAdapterImpl;
+import org.chromium.content.browser.webcontents.WebContentsImpl;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContents.UserDataFactory;
@@ -27,28 +28,17 @@
  */
 @JNINamespace("content")
 public class TapDisambiguator implements ImeEventObserver, PopupController.HideablePopup {
-    private final WebContents mWebContents;
+    private final WebContentsImpl mWebContents;
     private PopupZoomer mPopupView;
-    private boolean mInitialized;
     private long mNativeTapDisambiguator;
 
     private static final class UserDataFactoryLazyHolder {
         private static final UserDataFactory<TapDisambiguator> INSTANCE = TapDisambiguator::new;
     }
 
-    public static TapDisambiguator create(
-            Context context, WebContents webContents, ViewGroup containerView) {
-        TapDisambiguator tabDismabiguator = webContents.getOrSetUserData(
-                TapDisambiguator.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert tabDismabiguator != null;
-        assert !tabDismabiguator.initialized();
-
-        tabDismabiguator.init(context, containerView);
-        return tabDismabiguator;
-    }
-
     public static TapDisambiguator fromWebContents(WebContents webContents) {
-        return webContents.getOrSetUserData(TapDisambiguator.class, null);
+        return webContents.getOrSetUserData(
+                TapDisambiguator.class, UserDataFactoryLazyHolder.INSTANCE);
     }
 
     /**
@@ -56,10 +46,10 @@
      * @param webContents WebContents instance with which this TapDisambiguator is associated.
      */
     public TapDisambiguator(WebContents webContents) {
-        mWebContents = webContents;
-    }
+        mWebContents = (WebContentsImpl) webContents;
+        Context context = mWebContents.getContext();
+        ViewGroup containerView = mWebContents.getViewAndroidDelegate().getContainerView();
 
-    private void init(Context context, ViewGroup containerView) {
         // OnVisibilityChangedListener, OnTapListener can only be used to add and remove views
         // from the container view at creation.
         OnVisibilityChangedListener visibilityListener = new OnVisibilityChangedListener() {
@@ -98,15 +88,11 @@
                 nativeResolveTapDisambiguation(mNativeTapDisambiguator, timeMs, x, y, isLongPress);
             }
         };
-        mPopupView = new PopupZoomer(context, containerView, visibilityListener, tapListener);
+        mPopupView = new PopupZoomer(
+                mWebContents.getContext(), containerView, visibilityListener, tapListener);
         mNativeTapDisambiguator = nativeInit(mWebContents);
         ImeAdapterImpl.fromWebContents(mWebContents).addEventObserver(this);
         PopupController.register(mWebContents, this);
-        mInitialized = true;
-    }
-
-    private boolean initialized() {
-        return mInitialized;
     }
 
     // ImeEventObserver
diff --git a/content/public/android/java/src/org/chromium/content/browser/ViewEventSinkImpl.java b/content/public/android/java/src/org/chromium/content/browser/ViewEventSinkImpl.java
index bd053e1..6c3f4f0b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ViewEventSinkImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ViewEventSinkImpl.java
@@ -4,7 +4,6 @@
 
 package org.chromium.content.browser;
 
-import android.content.Context;
 import android.content.res.Configuration;
 
 import org.chromium.base.TraceEvent;
@@ -20,7 +19,6 @@
  */
 public final class ViewEventSinkImpl implements ViewEventSink, ActivityStateObserver {
     private final WebContentsImpl mWebContents;
-    private Context mContext;
 
     // Whether the container view has view-level focus.
     private Boolean mHasViewFocus;
@@ -40,35 +38,15 @@
         private static final UserDataFactory<ViewEventSinkImpl> INSTANCE = ViewEventSinkImpl::new;
     }
 
-    public static ViewEventSinkImpl create(Context context, WebContents webContents) {
-        ViewEventSinkImpl manager = webContents.getOrSetUserData(
-                ViewEventSinkImpl.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert manager != null;
-        assert !manager.initialized();
-        manager.init(context);
-        return manager;
-    }
-
     public static ViewEventSinkImpl from(WebContents webContents) {
-        return webContents.getOrSetUserData(ViewEventSinkImpl.class, null);
+        return webContents.getOrSetUserData(
+                ViewEventSinkImpl.class, UserDataFactoryLazyHolder.INSTANCE);
     }
 
     public ViewEventSinkImpl(WebContents webContents) {
         mWebContents = (WebContentsImpl) webContents;
     }
 
-    private void init(Context context) {
-        mContext = context;
-    }
-
-    private boolean initialized() {
-        return mContext != null;
-    }
-
-    public Context getContext() {
-        return mContext;
-    }
-
     @Override
     public void setAccessDelegate(ViewEventSink.InternalAccessDelegate accessDelegate) {
         GestureListenerManagerImpl.fromWebContents(mWebContents).setScrollDelegate(accessDelegate);
diff --git a/content/public/android/java/src/org/chromium/content/browser/WindowEventObserverManager.java b/content/public/android/java/src/org/chromium/content/browser/WindowEventObserverManager.java
index 22ee0b7..ca63a30 100644
--- a/content/public/android/java/src/org/chromium/content/browser/WindowEventObserverManager.java
+++ b/content/public/android/java/src/org/chromium/content/browser/WindowEventObserverManager.java
@@ -41,7 +41,6 @@
 
     private WindowEventObserverManager(WebContents webContents) {
         mViewEventSink = ViewEventSinkImpl.from(webContents);
-        assert mViewEventSink != null;
         WindowAndroid window = webContents.getTopLevelNativeWindow();
         if (window != null) onWindowAndroidChanged(window);
         addObserver((WebContentsImpl) webContents);
@@ -54,6 +53,7 @@
     public void addObserver(WindowEventObserver observer) {
         assert !mWindowEventObservers.hasObserver(observer);
         mWindowEventObservers.addObserver(observer);
+        if (mAttachedToWindow) observer.onAttachedToWindow();
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
index b36a652..9bc7922 100644
--- a/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/accessibility/WebContentsAccessibilityImpl.java
@@ -78,7 +78,7 @@
 
     private final WebContentsImpl mWebContents;
     protected AccessibilityManager mAccessibilityManager;
-    protected Context mContext;
+    protected final Context mContext;
     private String mProductVersion;
     protected long mNativeObj;
     private Rect mAccessibilityFocusRect;
@@ -116,8 +116,6 @@
     // Accessibility touch exploration state.
     private boolean mTouchExplorationEnabled;
 
-    private boolean mInitialized;
-
     /**
      * Create a WebContentsAccessibilityImpl object.
      */
@@ -140,40 +138,24 @@
         private static final UserDataFactory<WebContentsAccessibilityImpl> INSTANCE = new Factory();
     }
 
-    public static WebContentsAccessibilityImpl create(Context context, ViewGroup containerView,
-            WebContents webContents, String productVersion) {
-        WebContentsAccessibilityImpl wcax = webContents.getOrSetUserData(
-                WebContentsAccessibilityImpl.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert wcax != null && !wcax.initialized();
-        wcax.init(context, containerView, productVersion);
-        return wcax;
-    }
-
     public static WebContentsAccessibilityImpl fromWebContents(WebContents webContents) {
-        return webContents.getOrSetUserData(WebContentsAccessibilityImpl.class, null);
+        return webContents.getOrSetUserData(
+                WebContentsAccessibilityImpl.class, UserDataFactoryLazyHolder.INSTANCE);
     }
 
     protected WebContentsAccessibilityImpl(WebContents webContents) {
         mWebContents = (WebContentsImpl) webContents;
-    }
-
-    private void init(Context context, ViewGroup containerView, String productVersion) {
-        mContext = context;
-        mView = containerView;
-        mProductVersion = productVersion;
+        mContext = mWebContents.getContext();
+        mView = mWebContents.getViewAndroidDelegate().getContainerView();
+        mProductVersion = mWebContents.getProductVersion();
         mAccessibilityManager =
                 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         mCaptioningController = new CaptioningController(mWebContents);
         WindowEventObserverManager.from(mWebContents).addObserver(this);
 
-        mInitialized = true;
         // Native is initialized lazily, when node provider is actually requested.
     }
 
-    private boolean initialized() {
-        return mInitialized;
-    }
-
     /**
      * Called after the native a11y part is initialized. Overridable by subclasses
      * to do initialization that is not required until the native is set up.
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
index a72e768..ad9bc52 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapterImpl.java
@@ -166,33 +166,14 @@
     }
 
     /**
-     * Create {@link ImeAdapterImpl} instance.
-     * @param webContents WebContents instance with which this ImeAdapter is associated.
-     * @param wrapper InputMethodManagerWrapper that should receive all the call directed to
-     *                InputMethodManager.
-     */
-    public static ImeAdapterImpl create(
-            WebContents webContents, InputMethodManagerWrapper wrapper) {
-        ImeAdapterImpl imeAdapter = webContents.getOrSetUserData(
-                ImeAdapterImpl.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert imeAdapter != null && !imeAdapter.initialized();
-        imeAdapter.init(wrapper);
-        return imeAdapter;
-    }
-
-    private boolean initialized() {
-        return mNativeImeAdapterAndroid != 0;
-    }
-
-    /**
      * Get {@link ImeAdapter} object used for the give WebContents.
      * {@link #create()} should precede any calls to this.
      * @param webContents {@link WebContents} object.
-     * @return {@link ImeAdapter} object. {@code null} if not available because
-     *         {@link #create()} is not called yet.
+     * @return {@link ImeAdapter} object.
      */
     public static ImeAdapterImpl fromWebContents(WebContents webContents) {
-        return webContents.getOrSetUserData(ImeAdapterImpl.class, null);
+        return webContents.getOrSetUserData(
+                ImeAdapterImpl.class, UserDataFactoryLazyHolder.INSTANCE);
     }
 
     /**
@@ -211,14 +192,8 @@
         mWebContents = (WebContentsImpl) webContents;
         mViewDelegate = mWebContents.getViewAndroidDelegate();
         assert mViewDelegate != null;
-    }
-
-    /**
-     * @param wrapper InputMethodManagerWrapper that should receive all the call directed to
-     *                InputMethodManager.
-     */
-    private void init(InputMethodManagerWrapper wrapper) {
-        mInputMethodManagerWrapper = wrapper;
+        InputMethodManagerWrapper wrapper =
+                createDefaultInputMethodManagerWrapper(mWebContents.getContext());
 
         // Deep copy newConfig so that we can notice the difference.
         mCurrentConfig = new Configuration(getContainerView().getResources().getConfiguration());
@@ -251,6 +226,7 @@
         } else {
             mCursorAnchorInfoController = null;
         }
+        mInputMethodManagerWrapper = wrapper;
         mNativeImeAdapterAndroid = nativeInit(mWebContents);
         WindowEventObserverManager.from(mWebContents).addObserver(this);
     }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
index e4a48e4..279534c5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/SelectPopup.java
@@ -46,31 +46,17 @@
     }
 
     private final WebContentsImpl mWebContents;
-    private Context mContext;
+    private final Context mContext;
     private View mContainerView;
     private Ui mPopupView;
     private long mNativeSelectPopup;
     private long mNativeSelectPopupSourceFrame;
-    private boolean mInitialized;
 
     private static final class UserDataFactoryLazyHolder {
         private static final UserDataFactory<SelectPopup> INSTANCE = SelectPopup::new;
     }
 
     /**
-     * Create {@link SelectPopup} instance.
-     * @param context Context instance.
-     * @param webContents WebContents instance.
-     */
-    public static SelectPopup create(Context context, WebContents webContents) {
-        SelectPopup selectPopup =
-                webContents.getOrSetUserData(SelectPopup.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert selectPopup != null && !selectPopup.initialized();
-        selectPopup.init(context);
-        return selectPopup;
-    }
-
-    /**
      * Get {@link SelectPopup} object used for the give WebContents. {@link #create()} should
      * precede any calls to this.
      * @param webContents {@link WebContents} object.
@@ -78,7 +64,7 @@
      *         {@link #create()} is not called yet.
      */
     public static SelectPopup fromWebContents(WebContents webContents) {
-        return webContents.getOrSetUserData(SelectPopup.class, null);
+        return webContents.getOrSetUserData(SelectPopup.class, UserDataFactoryLazyHolder.INSTANCE);
     }
 
     /**
@@ -87,10 +73,7 @@
      */
     public SelectPopup(WebContents webContents) {
         mWebContents = (WebContentsImpl) webContents;
-    }
-
-    private void init(Context context) {
-        mContext = context;
+        mContext = mWebContents.getContext();
         ViewAndroidDelegate viewDelegate = mWebContents.getViewAndroidDelegate();
         assert viewDelegate != null;
         mContainerView = viewDelegate.getContainerView();
@@ -98,11 +81,6 @@
         mNativeSelectPopup = nativeInit(mWebContents);
         PopupController.register(mWebContents, this);
         WindowEventObserverManager.from(mWebContents).addObserver(this);
-        mInitialized = true;
-    }
-
-    private boolean initialized() {
-        return mInitialized;
     }
 
     /**
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
index 5914751..ae8a70a3 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/TextSuggestionHost.java
@@ -28,46 +28,28 @@
 public class TextSuggestionHost implements WindowEventObserver, HideablePopup {
     private long mNativeTextSuggestionHost;
     private final WebContentsImpl mWebContents;
+    private final Context mContext;
+    private final ViewAndroidDelegate mViewDelegate;
 
-    private Context mContext;
-    private ViewAndroidDelegate mViewDelegate;
     private boolean mIsAttachedToWindow;
     private WindowAndroid mWindowAndroid;
 
     private SpellCheckPopupWindow mSpellCheckPopupWindow;
     private TextSuggestionsPopupWindow mTextSuggestionsPopupWindow;
 
-    private boolean mInitialized;
-
     private static final class UserDataFactoryLazyHolder {
         private static final UserDataFactory<TextSuggestionHost> INSTANCE = TextSuggestionHost::new;
     }
 
     /**
-     * Create {@link TextSuggestionHost} instance.
-     * @param context Context for action mode.
-     * @param webContents WebContents instance.
-     * @param windowAndroid The current WindowAndroid instance.
-     */
-    public static TextSuggestionHost create(
-            Context context, WebContents webContents, WindowAndroid windowAndroid) {
-        TextSuggestionHost host = webContents.getOrSetUserData(
-                TextSuggestionHost.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert host != null;
-        assert !host.initialized();
-        host.init(context, windowAndroid);
-        return host;
-    }
-
-    /**
      * Get {@link TextSuggestionHost} object used for the give WebContents.
      * {@link #create()} should precede any calls to this.
      * @param webContents {@link WebContents} object.
-     * @return {@link TextSuggestionHost} object. {@code null} if not available because
-     *         {@link #create()} is not called yet.
+     * @return {@link TextSuggestionHost} object.
      */
     public static TextSuggestionHost fromWebContents(WebContents webContents) {
-        return webContents.getOrSetUserData(TextSuggestionHost.class, null);
+        return webContents.getOrSetUserData(
+                TextSuggestionHost.class, UserDataFactoryLazyHolder.INSTANCE);
     }
 
     /**
@@ -76,21 +58,13 @@
      */
     public TextSuggestionHost(WebContents webContents) {
         mWebContents = (WebContentsImpl) webContents;
-    }
-
-    private void init(Context context, WindowAndroid windowAndroid) {
-        mContext = context;
-        mWindowAndroid = windowAndroid;
+        mContext = mWebContents.getContext();
+        mWindowAndroid = mWebContents.getTopLevelNativeWindow();
         mViewDelegate = mWebContents.getViewAndroidDelegate();
         assert mViewDelegate != null;
         mNativeTextSuggestionHost = nativeInit(mWebContents);
         PopupController.register(mWebContents, this);
         WindowEventObserverManager.from(mWebContents).addObserver(this);
-        mInitialized = true;
-    }
-
-    private boolean initialized() {
-        return mInitialized;
     }
 
     private float getContentOffsetYPix() {
diff --git a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
index 04bc717..000284b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/selection/SelectionPopupControllerImpl.java
@@ -46,11 +46,11 @@
 import org.chromium.content.browser.GestureListenerManagerImpl;
 import org.chromium.content.browser.PopupController;
 import org.chromium.content.browser.PopupController.HideablePopup;
-import org.chromium.content.browser.ViewEventSinkImpl;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.WindowEventObserverManager;
 import org.chromium.content.browser.input.ImeAdapterImpl;
 import org.chromium.content.browser.webcontents.WebContentsImpl;
+import org.chromium.content.browser.webcontents.WebContentsUserData;
 import org.chromium.content_public.browser.ActionModeCallbackHelper;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.SelectionClient;
@@ -166,8 +166,6 @@
 
     private boolean mPreserveSelectionOnNextLossOfFocus;
 
-    private boolean mInitialized;
-
     /**
      * The {@link SelectionInsertionHandleObserver} that processes handle events, or {@code null} if
      * none exists.
@@ -194,22 +192,6 @@
     }
 
     /**
-     * Create {@link SelectionPopupController} instance.
-     * @param context Context for action mode.
-     * @param window WindowAndroid instance.
-     * @param webContents WebContents instance.
-     */
-    public static SelectionPopupControllerImpl create(
-            Context context, WindowAndroid window, WebContents webContents) {
-        SelectionPopupControllerImpl controller = webContents.getOrSetUserData(
-                SelectionPopupControllerImpl.class, UserDataFactoryLazyHolder.INSTANCE);
-        assert controller != null && !controller.initialized();
-        controller.init(context, window, true);
-        controller.setActionModeCallback(ActionModeCallbackHelper.EMPTY_CALLBACK);
-        return controller;
-    }
-
-    /**
      * Get {@link SelectionPopupController} object used for the give WebContents.
      * {@link #create()} should precede any calls to this.
      * @param webContents {@link WebContents} object.
@@ -217,31 +199,23 @@
      *         {@link #create()} is not called yet.
      */
     public static SelectionPopupControllerImpl fromWebContents(WebContents webContents) {
-        return webContents.getOrSetUserData(SelectionPopupControllerImpl.class, null);
+        return WebContentsUserData.fromWebContents(webContents, SelectionPopupControllerImpl.class,
+                UserDataFactoryLazyHolder.INSTANCE);
     }
 
     /**
      * Create {@link SelectionPopupController} instance. Note that it will create an instance with
      * no link to native side for testing only.
-     * @param context Context for action mode.
-     * @param window WindowAndroid instance.
-     * @param webContents WebContents instance.
+     * @param webContents {@link WebContents} mocked for testing.
      * @param popupController {@link PopupController} mocked for testing.
      */
-    public static SelectionPopupControllerImpl createForTesting(Context context,
-            WindowAndroid window, WebContents webContents, PopupController popupController) {
-        SelectionPopupControllerImpl controller = new SelectionPopupControllerImpl(webContents);
-
-        // Tests that do not fully initialize contents (therefore passing nulled-out window)
-        // still need to instantiate ViewEventSinkImpl to get the test flow working.
-        if (window == null) ViewEventSinkImpl.create(context, webContents);
-        controller.setPopupControllerForTesting(popupController);
-        controller.init(context, window, false);
-        return controller;
+    public static SelectionPopupControllerImpl createForTesting(
+            WebContents webContents, PopupController popupController) {
+        return new SelectionPopupControllerImpl(webContents, popupController, false);
     }
 
-    private void setPopupControllerForTesting(PopupController popupController) {
-        mPopupController = popupController;
+    public static SelectionPopupControllerImpl createForTesting(WebContents webContents) {
+        return new SelectionPopupControllerImpl(webContents, null, false);
     }
 
     /**
@@ -249,21 +223,21 @@
      * @param webContents WebContents instance.
      */
     public SelectionPopupControllerImpl(WebContents webContents) {
-        mWebContents = (WebContentsImpl) webContents;
+        this(webContents, null, true);
+        setActionModeCallback(ActionModeCallbackHelper.EMPTY_CALLBACK);
     }
 
-    /**
-     * @param context Context for action mode.
-     * @param window WindowAndroid instance.
-     * @param viewDelegate {@link ViewAndroidDelegate} to get the current container view from.
-     * @param iniatializeNative Used for tests. Set to {@code false} to skip native initialization.
-     */
-    private void init(Context context, WindowAndroid window, boolean initializeNative) {
-        mContext = context;
-        mWindowAndroid = window;
+    private SelectionPopupControllerImpl(
+            WebContents webContents, PopupController popupController, boolean initializeNative) {
+        mWebContents = (WebContentsImpl) webContents;
+        mPopupController = popupController;
+        mContext = mWebContents.getContext();
+        mWindowAndroid = mWebContents.getTopLevelNativeWindow();
         ViewAndroidDelegate viewDelegate = mWebContents.getViewAndroidDelegate();
-        mView = viewDelegate != null ? viewDelegate.getContainerView() : null;
-        if (viewDelegate != null) viewDelegate.addObserver(this);
+        if (viewDelegate != null) {
+            mView = viewDelegate.getContainerView();
+            viewDelegate.addObserver(this);
+        }
 
         // The menu items are allowed by default.
         mAllowedMenuItems = MENU_ITEM_SHARE | MENU_ITEM_WEB_SEARCH | MENU_ITEM_PROCESS_TEXT;
@@ -279,20 +253,20 @@
         };
 
         WindowEventObserverManager manager = WindowEventObserverManager.from(mWebContents);
-        if (manager != null) manager.addObserver(this);
-        ImeAdapterImpl imeAdapter = ImeAdapterImpl.fromWebContents(mWebContents);
-        if (imeAdapter != null) imeAdapter.addEventObserver(this);
+        if (manager != null) {
+            manager.addObserver(this);
+        }
+        if (initializeNative) {
+            mNativeSelectionPopupController = nativeInit(mWebContents);
+            ImeAdapterImpl imeAdapter = ImeAdapterImpl.fromWebContents(mWebContents);
+            if (imeAdapter != null) imeAdapter.addEventObserver(this);
+        }
+
         mResultCallback = new SmartSelectionCallback();
         mLastSelectedText = "";
         initHandleObserver();
         mAdditionalMenuItemProvider = ContentClassFactory.get().createAddtionalMenuItemProvider();
-        if (initializeNative) mNativeSelectionPopupController = nativeInit(mWebContents);
         getPopupController().registerPopup(this);
-        mInitialized = true;
-    }
-
-    private boolean initialized() {
-        return mInitialized;
     }
 
     public static String sanitizeQuery(String query, int maxLength) {
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index bd5d07c..048edab 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -24,19 +24,15 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content.browser.AppWebMessagePort;
-import org.chromium.content.browser.Gamepad;
 import org.chromium.content.browser.MediaSessionImpl;
 import org.chromium.content.browser.RenderCoordinatesImpl;
-import org.chromium.content.browser.TapDisambiguator;
 import org.chromium.content.browser.ViewEventSinkImpl;
 import org.chromium.content.browser.WindowEventObserver;
 import org.chromium.content.browser.WindowEventObserverManager;
 import org.chromium.content.browser.accessibility.WebContentsAccessibilityImpl;
 import org.chromium.content.browser.framehost.RenderFrameHostDelegate;
 import org.chromium.content.browser.framehost.RenderFrameHostImpl;
-import org.chromium.content.browser.input.ImeAdapterImpl;
 import org.chromium.content.browser.input.SelectPopup;
-import org.chromium.content.browser.input.TextSuggestionHost;
 import org.chromium.content.browser.selection.SelectionPopupControllerImpl;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
@@ -160,25 +156,15 @@
 
     private EventForwarder mEventForwarder;
 
-    private static class DefaultInternalsHolder implements InternalsHolder {
-        private WebContentsInternals mInternals;
-
-        @Override
-        public void set(WebContentsInternals internals) {
-            mInternals = internals;
-        }
-
-        @Override
-        public WebContentsInternals get() {
-            return mInternals;
-        }
-    }
-
     // Cached copy of all positions and scales as reported by the renderer.
     private RenderCoordinatesImpl mRenderCoordinates;
 
     private InternalsHolder mInternalsHolder;
 
+    private String mProductVersion;
+
+    private boolean mInitialized;
+
     private static class WebContentsInternalsImpl implements WebContentsInternals {
         public HashMap<Class<?>, WebContentsUserData> userDataMap;
         public ViewAndroidDelegate viewAndroidDelegate;
@@ -188,18 +174,6 @@
             long nativeWebContentsAndroid, NavigationController navigationController) {
         mNativeWebContentsAndroid = nativeWebContentsAndroid;
         mNavigationController = navigationController;
-
-        // Initialize |mInternalsHolder| with a default one that keeps all the internals
-        // inside WebContentsImpl. It holds a strong reference until an embedder invokes
-        // |setInternalsHolder| to get the internals handed over to it.
-        WebContentsInternalsImpl internals = new WebContentsInternalsImpl();
-        internals.userDataMap = new HashMap<>();
-
-        mRenderCoordinates = new RenderCoordinatesImpl();
-        mRenderCoordinates.reset();
-
-        mInternalsHolder = new DefaultInternalsHolder();
-        mInternalsHolder.set(internals);
     }
 
     @CalledByNative
@@ -209,31 +183,45 @@
     }
 
     @Override
-    public void initialize(Context context, String productVersion, ViewAndroidDelegate viewDelegate,
-            InternalAccessDelegate internalDispatcher, WindowAndroid windowAndroid) {
+    public void initialize(String productVersion, ViewAndroidDelegate viewDelegate,
+            InternalAccessDelegate accessDelegate, WindowAndroid windowAndroid,
+            InternalsHolder internalsHolder) {
         // Makes sure |initialize| is not called more than once.
-        assert ViewEventSinkImpl.from(this) == null;
+        assert !mInitialized;
+        assert internalsHolder != null;
 
-        // TODO(jinsukkim): Consider creating objects using observer pattern so that WebContents
-        //     doesn't have to have direct references to them.
-        ViewEventSinkImpl.create(context, this);
+        mProductVersion = productVersion;
+
+        mInternalsHolder = internalsHolder;
+        WebContentsInternalsImpl internals = new WebContentsInternalsImpl();
+        internals.userDataMap = new HashMap<>();
+        mInternalsHolder.set(internals);
+
+        mRenderCoordinates = new RenderCoordinatesImpl();
+        mRenderCoordinates.reset();
+
+        mInitialized = true;
 
         setViewAndroidDelegate(viewDelegate);
         setTopLevelNativeWindow(windowAndroid);
 
-        ImeAdapterImpl.create(this, ImeAdapterImpl.createDefaultInputMethodManagerWrapper(context));
-        SelectionPopupControllerImpl.create(context, windowAndroid, this);
-        WebContentsAccessibilityImpl.create(
-                context, viewDelegate.getContainerView(), this, productVersion);
-        TapDisambiguator.create(context, this, viewDelegate.getContainerView());
-        TextSuggestionHost.create(context, this, windowAndroid);
-        SelectPopup.create(context, this);
-        Gamepad.create(context, this);
-
-        ViewEventSinkImpl.from(this).setAccessDelegate(internalDispatcher);
+        ViewEventSinkImpl.from(this).setAccessDelegate(accessDelegate);
         getRenderCoordinates().setDeviceScaleFactor(windowAndroid.getDisplay().getDipScale());
     }
 
+    @Nullable
+    public Context getContext() {
+        assert mInitialized;
+
+        WindowAndroid window = getTopLevelNativeWindow();
+        return window != null ? window.getContext().get() : null;
+    }
+
+    public String getProductVersion() {
+        assert mInitialized;
+        return mProductVersion;
+    }
+
     @CalledByNative
     private void clearNativePtr() {
         mNativeWebContentsAndroid = 0;
@@ -244,14 +232,6 @@
         }
     }
 
-    @Override
-    public void setInternalsHolder(InternalsHolder internalsHolder) {
-        // Ensure |setInternalsHolder()| is be called at most once.
-        assert mInternalsHolder instanceof DefaultInternalsHolder;
-        internalsHolder.set(mInternalsHolder.get());
-        mInternalsHolder = internalsHolder;
-    }
-
     // =================== RenderFrameHostDelegate overrides ===================
     @Override
     public void renderFrameCreated(RenderFrameHostImpl host) {
@@ -807,6 +787,9 @@
 
     @Override
     public <T> T getOrSetUserData(Class<T> key, UserDataFactory<T> userDataFactory) {
+        // For tests that go without calling |initialize|.
+        if (!mInitialized) return null;
+
         Map<Class<?>, WebContentsUserData> userDataMap = getUserDataMap();
 
         // Map can be null after WebView gets gc'ed on its way to destruction.
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java
index d99acbf..24094574 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsUserData.java
@@ -39,8 +39,10 @@
      * @param key Class instance of the object used as the key.
      * @param userDataFactory Factory that creates an object of the generic class. Creates a new
      *        instance and returns it if not created yet.
-     * @return The object of the given web contents. Can be null if the object was not set
-     *         or the user data map is already garbage-collected.
+     * @return The object of the given web contents. Can be null if the object was not set,
+     *         the user data map is already garbage-collected, or {@link WebContents#initialize()}
+     *         is not called yet.
+     *
      */
     public static <T> T fromWebContents(
             WebContents webContents, Class<T> key, UserDataFactory<T> userDataFactory) {
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/SelectionPopupController.java b/content/public/android/java/src/org/chromium/content_public/browser/SelectionPopupController.java
index 069ba0fc2..3334389 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/SelectionPopupController.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/SelectionPopupController.java
@@ -4,7 +4,6 @@
 
 package org.chromium.content_public.browser;
 
-import android.content.Context;
 import android.content.Intent;
 import android.view.ActionMode;
 import android.view.textclassifier.TextClassifier;
@@ -140,8 +139,7 @@
      * @return {@link SelectionPopupController} object used for the give WebContents.
      *         Creates one if not present.
      */
-    static SelectionPopupController createForTesting(
-            Context context, WindowAndroid window, WebContents webContents) {
-        return SelectionPopupControllerImpl.createForTesting(context, window, webContents, null);
+    static SelectionPopupController createForTesting(WebContents webContents) {
+        return SelectionPopupControllerImpl.createForTesting(webContents);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index f2b0e19..e2baf1fb 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -4,10 +4,10 @@
 
 package org.chromium.content_public.browser;
 
-import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Parcelable;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 
 import org.chromium.base.Callback;
@@ -60,6 +60,26 @@
     }
 
     /**
+     * @return a default implementation of {@link InternalsHolder} that holds a reference to
+     * {@link WebContentsInternals} object owned by {@link WebContents} instance.
+     */
+    public static InternalsHolder createDefaultInternalsHolder() {
+        return new InternalsHolder() {
+            private WebContentsInternals mInternals;
+
+            @Override
+            public void set(WebContentsInternals internals) {
+                mInternals = internals;
+            }
+
+            @Override
+            public WebContentsInternals get() {
+                return mInternals;
+            }
+        };
+    }
+
+    /**
      * Factory interface passed to {@link #setUserData()} for instantiation of
      * class as user data.
      *
@@ -84,26 +104,16 @@
     public interface UserDataFactory<T> { T create(WebContents webContents); }
 
     /**
-     * Sets holder of the objects used internally by WebContents for various features.
-     * This transfers the ownership of the objects to the caller since they will have the same
-     * lifecycle as that of the caller. The caller doesn't have to care about the objects inside
-     * the holder but should hold a reference to it and manage its lifetime.
-     *
-     * @param holder {@link #InternalsHolder} used to transfer the internal objects
-     *        from WebContents to the caller.
-     */
-    void setInternalsHolder(InternalsHolder holder);
-
-    /**
      * Initialize various content objects of {@link WebContents} lifetime.
-     * @param context The context used to create this object.
      * @param productVersion Product version for accessibility.
      * @param viewDelegate Delegate to add/remove anchor views.
      * @param accessDelegate Handles dispatching all hidden or super methods to the containerView.
      * @param windowAndroid An instance of the WindowAndroid.
+     * @param internalsHolder A holder of objects used internally by WebContents.
      */
-    void initialize(Context context, String productVersion, ViewAndroidDelegate viewDelegate,
-            ViewEventSink.InternalAccessDelegate accessDelegate, WindowAndroid windowAndroid);
+    void initialize(String productVersion, ViewAndroidDelegate viewDelegate,
+            ViewEventSink.InternalAccessDelegate accessDelegate, WindowAndroid windowAndroid,
+            @NonNull InternalsHolder internalsHolder);
 
     /**
      * @return The top level WindowAndroid associated with this WebContents.  This can be null.
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
index dee8f9e..4f14b06 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/SelectPopupTest.java
@@ -92,7 +92,7 @@
     @RetryOnFailure
     public void testReloadWhilePopupShowing() throws InterruptedException, Exception, Throwable {
         // The popup should be hidden before the click.
-        CriteriaHelper.pollInstrumentationThread(new PopupHiddenCriteria());
+        CriteriaHelper.pollUiThread(new PopupHiddenCriteria());
 
         final WebContents webContents = mActivityTestRule.getWebContents();
         final TestCallbackHelperContainer viewClient = new TestCallbackHelperContainer(webContents);
@@ -104,21 +104,19 @@
 
         // Reload the test page.
         int currentCallCount = onPageFinishedHelper.getCallCount();
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                // Now reload the page while the popup is showing, it gets hidden.
-                mActivityTestRule.getWebContents().getNavigationController().reload(true);
-            }
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            // Now reload the page while the popup is showing, it gets hidden.
+            mActivityTestRule.getWebContents().getNavigationController().reload(true);
         });
         onPageFinishedHelper.waitForCallback(currentCallCount, 1,
                 WAIT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
 
         // The popup should be hidden after the page reload.
-        CriteriaHelper.pollInstrumentationThread(new PopupHiddenCriteria());
+        CriteriaHelper.pollUiThread(new PopupHiddenCriteria());
 
         // Click the select and wait for the popup to show.
         DOMUtils.clickNode(webContents, "select");
-        CriteriaHelper.pollInstrumentationThread(new PopupShowingCriteria());
+        CriteriaHelper.pollUiThread(new PopupShowingCriteria());
     }
 }
diff --git a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
index 43bd89a..8ff9ed99 100644
--- a/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
+++ b/content/public/android/junit/src/org/chromium/content/browser/selection/SelectionPopupControllerTest.java
@@ -154,8 +154,9 @@
         when(mWebContents.getRenderCoordinates()).thenReturn(mRenderCoordinates);
         when(mRenderCoordinates.getDeviceScaleFactor()).thenReturn(1.f);
         when(mWebContents.getViewAndroidDelegate()).thenReturn(mViewAndroidDelegate);
-        mController = SelectionPopupControllerImpl.createForTesting(
-                mContext, mWindowAndroid, mWebContents, mPopupController);
+        when(mWebContents.getContext()).thenReturn(mContext);
+        when(mWebContents.getTopLevelNativeWindow()).thenReturn(mWindowAndroid);
+        mController = SelectionPopupControllerImpl.createForTesting(mWebContents, mPopupController);
     }
 
     @After
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index b81c3e6..28ba0306 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -236,6 +236,9 @@
   // Returns the path of the directory where this context's data is stored.
   virtual base::FilePath GetPath() const = 0;
 
+  // Returns the path of the directory where the code is cached.
+  virtual base::FilePath GetCachePath() const = 0;
+
   // Return whether this context is incognito. Default is false.
   virtual bool IsOffTheRecord() const = 0;
 
diff --git a/content/public/browser/storage_partition.h b/content/public/browser/storage_partition.h
index c709a20a..f55e28d 100644
--- a/content/public/browser/storage_partition.h
+++ b/content/public/browser/storage_partition.h
@@ -54,6 +54,7 @@
 class CacheStorageContext;
 class DOMStorageContext;
 class IndexedDBContext;
+class GeneratedCodeCacheContext;
 class PlatformNotificationContext;
 class ServiceWorkerContext;
 class SharedWorkerService;
@@ -106,6 +107,7 @@
   virtual ServiceWorkerContext* GetServiceWorkerContext() = 0;
   virtual SharedWorkerService* GetSharedWorkerService() = 0;
   virtual CacheStorageContext* GetCacheStorageContext() = 0;
+  virtual GeneratedCodeCacheContext* GetGeneratedCodeCacheContext() = 0;
 #if !defined(OS_ANDROID)
   virtual HostZoomMap* GetHostZoomMap() = 0;
   virtual HostZoomLevelContext* GetHostZoomLevelContext() = 0;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 04d6bae..262de84 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -178,6 +178,11 @@
 const base::Feature kImageCaptureAPI{"ImageCaptureAPI",
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Use the requester origin as a second key to enfore site isolation policy for
+// code caches.
+const base::Feature kIsolatedCodeCache{"IsolatedCodeCache",
+                                       base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Alternative to switches::kIsolateOrigins, for turning on origin isolation.
 // List of origins to isolate has to be specified via
 // kIsolateOriginsFieldTrialParamName.
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index d6249a7..ed06848 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -30,6 +30,7 @@
 CONTENT_EXPORT extern const base::Feature kBlockCredentialedSubresources;
 CONTENT_EXPORT extern const base::Feature kBrotliEncoding;
 CONTENT_EXPORT extern const base::Feature kCacheInlineScriptCode;
+CONTENT_EXPORT extern const base::Feature kIsolatedCodeCache;
 CONTENT_EXPORT extern const base::Feature kCanvas2DImageChromium;
 CONTENT_EXPORT extern const base::Feature kCompositeOpaqueFixedPosition;
 CONTENT_EXPORT extern const base::Feature kCompositeOpaqueScrollers;
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
index 1d44ef3..5b7ff0a61 100644
--- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
+++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/mock/MockWebContents.java
@@ -5,7 +5,6 @@
 package org.chromium.content.browser.test.mock;
 
 import android.annotation.SuppressLint;
-import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Parcel;
@@ -34,8 +33,9 @@
     public RenderFrameHost renderFrameHost;
 
     @Override
-    public void initialize(Context context, String productVersion, ViewAndroidDelegate viewDelegate,
-            ViewEventSink.InternalAccessDelegate accessDelegate, WindowAndroid windowAndroid) {}
+    public void initialize(String productVersion, ViewAndroidDelegate viewDelegate,
+            ViewEventSink.InternalAccessDelegate accessDelegate, WindowAndroid windowAndroid,
+            WebContents.InternalsHolder internalsHolder) {}
 
     @Override
     public int describeContents() {
@@ -46,9 +46,6 @@
     public void writeToParcel(Parcel dest, int flags) {}
 
     @Override
-    public void setInternalsHolder(InternalsHolder holder) {}
-
-    @Override
     public WindowAndroid getTopLevelNativeWindow() {
         return null;
     }
diff --git a/content/public/test/cache_test_util.cc b/content/public/test/cache_test_util.cc
index 9e444547..6c869cf 100644
--- a/content/public/test/cache_test_util.cc
+++ b/content/public/test/cache_test_util.cc
@@ -141,7 +141,7 @@
 
     error = iterator_->OpenNextEntry(
         &current_entry_,
-        base::Bind(&CacheTestUtil::GetNextKey, base::Unretained(this)));
+        base::BindOnce(&CacheTestUtil::GetNextKey, base::Unretained(this)));
   }
 }
 
diff --git a/content/public/test/test_browser_context.cc b/content/public/test/test_browser_context.cc
index e61da8ba..1c15a32d0 100644
--- a/content/public/test/test_browser_context.cc
+++ b/content/public/test/test_browser_context.cc
@@ -97,6 +97,10 @@
   return browser_context_dir_.GetPath();
 }
 
+base::FilePath TestBrowserContext::GetCachePath() const {
+  return browser_context_dir_.GetPath();
+}
+
 #if !defined(OS_ANDROID)
 std::unique_ptr<ZoomLevelDelegate> TestBrowserContext::CreateZoomLevelDelegate(
     const base::FilePath& partition_path) {
diff --git a/content/public/test/test_browser_context.h b/content/public/test/test_browser_context.h
index 7a231877..6ad6aa21 100644
--- a/content/public/test/test_browser_context.h
+++ b/content/public/test/test_browser_context.h
@@ -45,6 +45,7 @@
 
   // BrowserContext implementation.
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
 #if !defined(OS_ANDROID)
   std::unique_ptr<ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
diff --git a/content/public/test/test_storage_partition.cc b/content/public/test/test_storage_partition.cc
index cc19639..2ec9c67d 100644
--- a/content/public/test/test_storage_partition.cc
+++ b/content/public/test/test_storage_partition.cc
@@ -77,6 +77,11 @@
   return cache_storage_context_;
 }
 
+GeneratedCodeCacheContext*
+TestStoragePartition::GetGeneratedCodeCacheContext() {
+  return generated_code_cache_context_;
+}
+
 PlatformNotificationContext*
 TestStoragePartition::GetPlatformNotificationContext() {
   return nullptr;
diff --git a/content/public/test/test_storage_partition.h b/content/public/test/test_storage_partition.h
index 765d857..b6ce428 100644
--- a/content/public/test/test_storage_partition.h
+++ b/content/public/test/test_storage_partition.h
@@ -113,6 +113,11 @@
   }
   CacheStorageContext* GetCacheStorageContext() override;
 
+  void set_generated_code_cache_context(GeneratedCodeCacheContext* context) {
+    generated_code_cache_context_ = context;
+  }
+  GeneratedCodeCacheContext* GetGeneratedCodeCacheContext() override;
+
   void set_platform_notification_context(PlatformNotificationContext* context) {
     platform_notification_context_ = context;
   }
@@ -187,6 +192,7 @@
   ServiceWorkerContext* service_worker_context_ = nullptr;
   SharedWorkerService* shared_worker_service_ = nullptr;
   CacheStorageContext* cache_storage_context_ = nullptr;
+  GeneratedCodeCacheContext* generated_code_cache_context_ = nullptr;
   PlatformNotificationContext* platform_notification_context_ = nullptr;
   WebPackageContext* web_package_context_ = nullptr;
 #if !defined(OS_ANDROID)
diff --git a/content/renderer/input/main_thread_event_queue.cc b/content/renderer/input/main_thread_event_queue.cc
index 3503cbb..386d47b 100644
--- a/content/renderer/input/main_thread_event_queue.cc
+++ b/content/renderer/input/main_thread_event_queue.cc
@@ -522,7 +522,7 @@
     if (use_raf_fallback_timer_) {
       raf_fallback_timer_.Start(
           FROM_HERE, kMaxRafDelay,
-          base::Bind(&MainThreadEventQueue::RafFallbackTimerFired, this));
+          base::BindOnce(&MainThreadEventQueue::RafFallbackTimerFired, this));
     }
     if (client_)
       client_->SetNeedsMainFrame();
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc
index 21f0d75..9b70963 100644
--- a/content/renderer/media/renderer_webmediaplayer_delegate.cc
+++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -222,8 +222,8 @@
   if (!idle_cleanup_timer_.IsRunning() && !pending_update_task_) {
     idle_cleanup_timer_.Start(
         FROM_HERE, idle_cleanup_interval_,
-        base::Bind(&RendererWebMediaPlayerDelegate::UpdateTask,
-                   base::Unretained(this)));
+        base::BindOnce(&RendererWebMediaPlayerDelegate::UpdateTask,
+                       base::Unretained(this)));
   }
 }
 
@@ -492,8 +492,8 @@
   if (!idle_player_map_.empty()) {
     idle_cleanup_timer_.Start(
         FROM_HERE, idle_cleanup_interval_,
-        base::Bind(&RendererWebMediaPlayerDelegate::UpdateTask,
-                   base::Unretained(this)));
+        base::BindOnce(&RendererWebMediaPlayerDelegate::UpdateTask,
+                       base::Unretained(this)));
   }
 }
 
diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
index 57ae21e..d00e437c 100644
--- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
+++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.cc
@@ -194,28 +194,7 @@
 }
 
 bool WebRtcVideoCapturerAdapter::IsScreencast() const {
-  // IsScreencast() is misleading since content hints were added to
-  // MediaStreamTracks. What IsScreencast() really signals is whether or not
-  // video frames should ever be scaled before being handed over to WebRTC.
-  // TODO(pbos): Remove the need for IsScreencast() -> ShouldAdaptResolution()
-  // by inlining VideoCapturer::AdaptFrame() and removing it from VideoCapturer.
-  return !ShouldAdaptResolution();
-}
-
-bool WebRtcVideoCapturerAdapter::ShouldAdaptResolution() const {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  if (content_hint_ ==
-      blink::WebMediaStreamTrack::ContentHintType::kVideoMotion) {
-    return true;
-  }
-  if (content_hint_ ==
-          blink::WebMediaStreamTrack::ContentHintType::kVideoDetail ||
-      content_hint_ ==
-          blink::WebMediaStreamTrack::ContentHintType::kVideoText) {
-    return false;
-  }
-  // Screencast does not adapt by default.
-  return !is_screencast_;
+  return is_screencast_;
 }
 
 bool WebRtcVideoCapturerAdapter::GetBestCaptureFormat(
diff --git a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h
index f51e395..921b373 100644
--- a/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h
+++ b/content/renderer/media/webrtc/webrtc_video_capturer_adapter.h
@@ -56,8 +56,6 @@
                             cricket::VideoFormat* best_format) override;
   bool IsScreencast() const override;
 
-  bool ShouldAdaptResolution() const;
-
   // |thread_checker_| is bound to the libjingle worker thread.
   base::ThreadChecker thread_checker_;
 
diff --git a/content/renderer/pepper/pepper_platform_audio_output_dev.cc b/content/renderer/pepper/pepper_platform_audio_output_dev.cc
index 7c7f53a..aff362b2 100644
--- a/content/renderer/pepper/pepper_platform_audio_output_dev.cc
+++ b/content/renderer/pepper/pepper_platform_audio_output_dev.cc
@@ -290,9 +290,9 @@
     auth_timeout_action_.reset(new base::OneShotTimer());
     auth_timeout_action_->Start(
         FROM_HERE, auth_timeout_,
-        base::Bind(&PepperPlatformAudioOutputDev::OnDeviceAuthorized, this,
-                   media::OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT,
-                   media::AudioParameters(), std::string()));
+        base::BindOnce(&PepperPlatformAudioOutputDev::OnDeviceAuthorized, this,
+                       media::OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT,
+                       media::AudioParameters(), std::string()));
   }
 }
 
diff --git a/content/renderer/visual_state_browsertest.cc b/content/renderer/visual_state_browsertest.cc
index e01ae0c..c32ee51 100644
--- a/content/renderer/visual_state_browsertest.cc
+++ b/content/renderer/visual_state_browsertest.cc
@@ -116,8 +116,9 @@
       base::Bind(&VisualStateTest::AssertIsIdle, base::Unretained(this)));
 
   // Insert a visual state callback.
-  shell()->web_contents()->GetMainFrame()->InsertVisualStateCallback(base::Bind(
-      &VisualStateTest::InvokeVisualStateCallback, base::Unretained(this)));
+  shell()->web_contents()->GetMainFrame()->InsertVisualStateCallback(
+      base::BindOnce(&VisualStateTest::InvokeVisualStateCallback,
+                     base::Unretained(this)));
 
   // Verify that the callback is invoked and a new commit completed.
   PostTaskToInProcessRendererAndWait(base::Bind(
diff --git a/content/shell/android/java/src/org/chromium/content_shell/Shell.java b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
index a07087f..fcbfe1c 100644
--- a/content/shell/android/java/src/org/chromium/content_shell/Shell.java
+++ b/content/shell/android/java/src/org/chromium/content_shell/Shell.java
@@ -296,7 +296,8 @@
         Context context = getContext();
         ContentView cv = ContentView.createContentView(context, webContents);
         mViewAndroidDelegate = new ShellViewAndroidDelegate(cv);
-        webContents.initialize(context, "", mViewAndroidDelegate, cv, mWindow);
+        webContents.initialize(
+                "", mViewAndroidDelegate, cv, mWindow, WebContents.createDefaultInternalsHolder());
         mWebContents = webContents;
         SelectionPopupController.fromWebContents(webContents)
                 .setActionModeCallback(defaultActionCallback());
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc
index 06fc3546..4e7a6c2 100644
--- a/content/shell/browser/shell_browser_context.cc
+++ b/content/shell/browser/shell_browser_context.cc
@@ -144,6 +144,10 @@
   return path_;
 }
 
+base::FilePath ShellBrowserContext::GetCachePath() const {
+  return path_;
+}
+
 bool ShellBrowserContext::IsOffTheRecord() const {
   return off_the_record_;
 }
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h
index f3af162..e3e991a 100644
--- a/content/shell/browser/shell_browser_context.h
+++ b/content/shell/browser/shell_browser_context.h
@@ -47,6 +47,7 @@
 
   // BrowserContext implementation.
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
 #if !defined(OS_ANDROID)
   std::unique_ptr<ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
diff --git a/content/shell/test_runner/test_runner_for_specific_view.cc b/content/shell/test_runner/test_runner_for_specific_view.cc
index 1805a0f8..21a227d 100644
--- a/content/shell/test_runner/test_runner_for_specific_view.cc
+++ b/content/shell/test_runner/test_runner_for_specific_view.cc
@@ -313,8 +313,8 @@
   return delegate()->GetBluetoothManualChooserEvents(base::BindOnce(
       &TestRunnerForSpecificView::GetBluetoothManualChooserEventsCallback,
       weak_factory_.GetWeakPtr(),
-      base::Passed(v8::UniquePersistent<v8::Function>(
-          blink::MainThreadIsolate(), callback))));
+      v8::UniquePersistent<v8::Function>(blink::MainThreadIsolate(),
+                                         callback)));
 }
 
 void TestRunnerForSpecificView::GetBluetoothManualChooserEventsCallback(
@@ -390,8 +390,8 @@
       base::BindOnce(
           &TestRunnerForSpecificView::DispatchBeforeInstallPromptCallback,
           weak_factory_.GetWeakPtr(),
-          base::Passed(v8::UniquePersistent<v8::Function>(
-              blink::MainThreadIsolate(), callback))));
+          v8::UniquePersistent<v8::Function>(blink::MainThreadIsolate(),
+                                             callback)));
 }
 
 void TestRunnerForSpecificView::DispatchBeforeInstallPromptCallback(
diff --git a/content/test/gpu/gpu_tests/gpu_integration_test.py b/content/test/gpu/gpu_tests/gpu_integration_test.py
index bf2715c..2a4e4581 100644
--- a/content/test/gpu/gpu_tests/gpu_integration_test.py
+++ b/content/test/gpu/gpu_tests/gpu_integration_test.py
@@ -48,6 +48,12 @@
       browser_args = []
     cls._finder_options = cls._original_finder_options.Copy()
     browser_options = cls._finder_options.browser_options
+    # A non-sandboxed, 15-seconds-delayed gpu process is currently running in
+    # the browser to collect gpu info. A command line switch is added here to
+    # skip this gpu process for all gpu integration tests to prevent any
+    # interference with the test results.
+    browser_args.append(
+      '--disable-gpu-process-for-dx12-vulkan-info-collection')
     # Append the new arguments.
     browser_options.AppendExtraBrowserArgs(browser_args)
     cls._last_launched_browser_args = set(browser_args)
@@ -142,7 +148,7 @@
         # expectations, and since minidump symbolization is slow
         # (upwards of one minute on a fast laptop), symbolizing all the
         # stacks could slow down the tests' running time unacceptably.
-        self._SymbolizeUnsymbolizedMinidumps()
+        self.browser.LogSymbolizedUnsymbolizedMinidumps(logging.ERROR)
         # This failure might have been caused by a browser or renderer
         # crash, so restart the browser to make sure any state doesn't
         # propagate to the next test iteration.
@@ -190,25 +196,6 @@
         logging.warning(
             '%s was expected to fail, but passed.\n', test_name)
 
-  def _SymbolizeUnsymbolizedMinidumps(self):
-    # The fakes used for unit tests don't mock this entry point yet.
-    if not hasattr(self.browser, 'GetAllUnsymbolizedMinidumpPaths'):
-      return
-    i = 10
-    if self.browser.GetAllUnsymbolizedMinidumpPaths():
-      logging.error('Symbolizing minidump paths: ' + str(
-        self.browser.GetAllUnsymbolizedMinidumpPaths()))
-    else:
-      logging.error('No minidump paths to symbolize')
-    while i > 0 and self.browser.GetAllUnsymbolizedMinidumpPaths():
-      i = i - 1
-      sym = self.browser.SymbolizeMinidump(
-        self.browser.GetAllUnsymbolizedMinidumpPaths()[0])
-      if sym[0]:
-        logging.error('Symbolized minidump:\n' + sym[1])
-      else:
-        logging.error('Minidump symbolization failed:\n' + sym[1])
-
   @classmethod
   def GenerateGpuTests(cls, options):
     """Subclasses must implement this to yield (test_name, url, args)
diff --git a/extensions/browser/api/alarms/alarm_manager.cc b/extensions/browser/api/alarms/alarm_manager.cc
index 2440e0c..f4b3e5a 100644
--- a/extensions/browser/api/alarms/alarm_manager.cc
+++ b/extensions/browser/api/alarms/alarm_manager.cc
@@ -96,8 +96,8 @@
   for (size_t i = 0; i < alarms.size(); ++i) {
     std::unique_ptr<base::DictionaryValue> alarm =
         alarms[i]->js_alarm->ToValue();
-    alarm->Set(kAlarmGranularity,
-               base::CreateTimeDeltaValue(alarms[i]->granularity));
+    alarm->SetKey(kAlarmGranularity,
+                  base::CreateTimeDeltaValue(alarms[i]->granularity));
     list->Append(std::move(alarm));
   }
   return list;
diff --git a/extensions/browser/api/file_system/file_system_api.cc b/extensions/browser/api/file_system/file_system_api.cc
index 7915787..3bff4b1 100644
--- a/extensions/browser/api/file_system/file_system_api.cc
+++ b/extensions/browser/api/file_system/file_system_api.cc
@@ -226,8 +226,9 @@
 void SetLastChooseEntryDirectory(ExtensionPrefs* prefs,
                                  const std::string& extension_id,
                                  const base::FilePath& path) {
-  prefs->UpdateExtensionPref(extension_id, kLastChooseEntryDirectory,
-                             base::CreateFilePathValue(path));
+  prefs->UpdateExtensionPref(
+      extension_id, kLastChooseEntryDirectory,
+      base::Value::ToUniquePtrValue(base::CreateFilePathValue(path)));
 }
 
 }  // namespace file_system_api
diff --git a/extensions/shell/browser/shell_prefs_unittest.cc b/extensions/shell/browser/shell_prefs_unittest.cc
index a81dc21..a2330902 100644
--- a/extensions/shell/browser/shell_prefs_unittest.cc
+++ b/extensions/shell/browser/shell_prefs_unittest.cc
@@ -30,6 +30,8 @@
     return path.AppendASCII("shell_prefs");
   }
 
+  base::FilePath GetCachePath() const override { return GetPath(); }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(PrefsTestBrowserContext);
 };
diff --git a/gpu/command_buffer/service/gl_utils.cc b/gpu/command_buffer/service/gl_utils.cc
index a0ffc5f6..af2ac7e 100644
--- a/gpu/command_buffer/service/gl_utils.cc
+++ b/gpu/command_buffer/service/gl_utils.cc
@@ -39,6 +39,17 @@
     {5, 5},  {6, 5},  {6, 6},  {8, 5},   {8, 6},   {8, 8},
     {10, 5}, {10, 6}, {10, 8}, {10, 10}, {12, 10}, {12, 12}};
 
+bool IsValidPVRTCSize(GLint level, GLsizei size) {
+  return GLES2Util::IsPOT(size);
+}
+
+bool IsValidS3TCSizeForWebGL(GLint level, GLsizei size) {
+  // WebGL only allows multiple-of-4 sizes, except for levels > 0 where it also
+  // allows 1 or 2. See WEBGL_compressed_texture_s3tc.
+  return (level && size == 1) || (level && size == 2) ||
+         !(size % kS3TCBlockWidth);
+}
+
 const char* GetDebugSourceString(GLenum source) {
   switch (source) {
     case GL_DEBUG_SOURCE_API:
@@ -501,6 +512,272 @@
   return true;
 }
 
+bool ValidateCompressedTexSubDimensions(GLenum target,
+                                        GLint level,
+                                        GLint xoffset,
+                                        GLint yoffset,
+                                        GLint zoffset,
+                                        GLsizei width,
+                                        GLsizei height,
+                                        GLsizei depth,
+                                        GLenum format,
+                                        Texture* texture,
+                                        bool restrict_for_webgl,
+                                        const char** error_message) {
+  if (xoffset < 0 || yoffset < 0 || zoffset < 0) {
+    *error_message = "x/y/z offset < 0";
+    return false;
+  }
+
+  switch (format) {
+    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: {
+      const int kBlockWidth = 4;
+      const int kBlockHeight = 4;
+      if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
+        *error_message = "xoffset or yoffset not multiple of 4";
+        return false;
+      }
+      GLsizei tex_width = 0;
+      GLsizei tex_height = 0;
+      if (!texture->GetLevelSize(target, level, &tex_width, &tex_height,
+                                 nullptr) ||
+          width - xoffset > tex_width || height - yoffset > tex_height) {
+        *error_message = "dimensions out of range";
+        return false;
+      }
+      if ((((width % kBlockWidth) != 0) && (width + xoffset != tex_width)) ||
+          (((height % kBlockHeight) != 0) &&
+           (height + yoffset != tex_height))) {
+        *error_message = "dimensions do not align to a block boundary";
+        return false;
+      }
+      return true;
+    }
+    case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: {
+      const int index =
+          (format < GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR)
+              ? static_cast<int>(format - GL_COMPRESSED_RGBA_ASTC_4x4_KHR)
+              : static_cast<int>(format -
+                                 GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
+
+      const int kBlockWidth = kASTCBlockArray[index].blockWidth;
+      const int kBlockHeight = kASTCBlockArray[index].blockHeight;
+
+      if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
+        *error_message = "xoffset or yoffset not multiple of 4";
+        return false;
+      }
+      GLsizei tex_width = 0;
+      GLsizei tex_height = 0;
+      if (!texture->GetLevelSize(target, level, &tex_width, &tex_height,
+                                 nullptr) ||
+          width - xoffset > tex_width || height - yoffset > tex_height) {
+        *error_message = "dimensions out of range";
+        return false;
+      }
+      if ((((width % kBlockWidth) != 0) && (width + xoffset != tex_width)) ||
+          (((height % kBlockHeight) != 0) &&
+           (height + yoffset != tex_height))) {
+        *error_message = "dimensions do not align to a block boundary";
+        return false;
+      }
+      return true;
+    }
+    case GL_ATC_RGB_AMD:
+    case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
+    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: {
+      *error_message = "not supported for ATC textures";
+      return false;
+    }
+    case GL_ETC1_RGB8_OES: {
+      *error_message = "not supported for ECT1_RGB8_OES textures";
+      return false;
+    }
+    case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+    case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
+      if ((xoffset != 0) || (yoffset != 0)) {
+        *error_message = "xoffset and yoffset must be zero";
+        return false;
+      }
+      GLsizei tex_width = 0;
+      GLsizei tex_height = 0;
+      if (!texture->GetLevelSize(target, level, &tex_width, &tex_height,
+                                 nullptr) ||
+          width != tex_width || height != tex_height) {
+        *error_message =
+            "dimensions must match existing texture level dimensions";
+        return false;
+      }
+      return ValidateCompressedTexDimensions(target, level, width, height, 1,
+                                             format, restrict_for_webgl,
+                                             error_message);
+    }
+
+    // ES3 formats
+    case GL_COMPRESSED_R11_EAC:
+    case GL_COMPRESSED_SIGNED_R11_EAC:
+    case GL_COMPRESSED_RG11_EAC:
+    case GL_COMPRESSED_SIGNED_RG11_EAC:
+    case GL_COMPRESSED_RGB8_ETC2:
+    case GL_COMPRESSED_SRGB8_ETC2:
+    case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case GL_COMPRESSED_RGBA8_ETC2_EAC:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: {
+      const int kBlockSize = 4;
+      GLsizei tex_width, tex_height;
+      if (target == GL_TEXTURE_3D ||
+          !texture->GetLevelSize(target, level, &tex_width, &tex_height,
+                                 nullptr) ||
+          (xoffset % kBlockSize) || (yoffset % kBlockSize) ||
+          ((width % kBlockSize) && xoffset + width != tex_width) ||
+          ((height % kBlockSize) && yoffset + height != tex_height)) {
+        *error_message =
+            "dimensions must match existing texture level dimensions";
+        return false;
+      }
+      return true;
+    }
+    default:
+      *error_message = "unknown compressed texture format";
+      return false;
+  }
+}
+
+bool ValidateCompressedTexDimensions(GLenum target,
+                                     GLint level,
+                                     GLsizei width,
+                                     GLsizei height,
+                                     GLsizei depth,
+                                     GLenum format,
+                                     bool restrict_for_webgl,
+                                     const char** error_message) {
+  switch (format) {
+    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
+    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
+    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
+      DCHECK_EQ(1, depth);  // 2D formats.
+      if (restrict_for_webgl && (!IsValidS3TCSizeForWebGL(level, width) ||
+                                 !IsValidS3TCSizeForWebGL(level, height))) {
+        *error_message = "width or height invalid for level";
+        return false;
+      }
+      return true;
+    case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
+    case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+    case GL_ATC_RGB_AMD:
+    case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
+    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
+    case GL_ETC1_RGB8_OES:
+      DCHECK_EQ(1, depth);  // 2D formats.
+      if (width <= 0 || height <= 0) {
+        *error_message = "width or height invalid for level";
+        return false;
+      }
+      return true;
+    case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+    case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
+      DCHECK_EQ(1, depth);  // 2D formats.
+      if (!IsValidPVRTCSize(level, width) || !IsValidPVRTCSize(level, height)) {
+        *error_message = "width or height invalid for level";
+        return false;
+      }
+      return true;
+
+    // ES3 formats.
+    case GL_COMPRESSED_R11_EAC:
+    case GL_COMPRESSED_SIGNED_R11_EAC:
+    case GL_COMPRESSED_RG11_EAC:
+    case GL_COMPRESSED_SIGNED_RG11_EAC:
+    case GL_COMPRESSED_RGB8_ETC2:
+    case GL_COMPRESSED_SRGB8_ETC2:
+    case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    case GL_COMPRESSED_RGBA8_ETC2_EAC:
+    case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+      if (width < 0 || height < 0 || depth < 0) {
+        *error_message = "width, height, or depth invalid";
+        return false;
+      }
+      if (target == GL_TEXTURE_3D) {
+        *error_message = "target invalid for format";
+        return false;
+      }
+      return true;
+    default:
+      return false;
+  }
+}
+
 bool ValidateCopyTexFormatHelper(const FeatureInfo* feature_info,
                                  GLenum internal_format,
                                  GLenum read_format,
diff --git a/gpu/command_buffer/service/gl_utils.h b/gpu/command_buffer/service/gl_utils.h
index 350ae6e7..2b03458a 100644
--- a/gpu/command_buffer/service/gl_utils.h
+++ b/gpu/command_buffer/service/gl_utils.h
@@ -42,8 +42,16 @@
 class ErrorState;
 class FeatureInfo;
 class Logger;
+class Texture;
 enum class CopyTextureMethod;
 
+// clang-format off
+constexpr GLfloat kIdentityMatrix[16] = { 1.0f, 0.0f, 0.0f, 0.0f,
+                                          0.0f, 1.0f, 0.0f, 0.0f,
+                                          0.0f, 0.0f, 1.0f, 0.0f,
+                                          0.0f, 0.0f, 0.0f, 1.0f };
+// clang-format on
+
 struct CALayerSharedState {
   float opacity;
   bool is_clipped;
@@ -106,6 +114,28 @@
                                  GLsizei* size_in_bytes,
                                  ErrorState* error_state);
 
+bool ValidateCompressedTexSubDimensions(GLenum target,
+                                        GLint level,
+                                        GLint xoffset,
+                                        GLint yoffset,
+                                        GLint zoffset,
+                                        GLsizei width,
+                                        GLsizei height,
+                                        GLsizei depth,
+                                        GLenum format,
+                                        Texture* texture,
+                                        bool restrict_for_webgl,
+                                        const char** error_message);
+
+bool ValidateCompressedTexDimensions(GLenum target,
+                                     GLint level,
+                                     GLsizei width,
+                                     GLsizei height,
+                                     GLsizei depth,
+                                     GLenum format,
+                                     bool restrict_for_webgl,
+                                     const char** error_message);
+
 bool ValidateCopyTexFormatHelper(const FeatureInfo* feature_info,
                                  GLenum internal_format,
                                  GLenum read_format,
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index 57385fcd..a7e0c121 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -20,11 +20,6 @@
 
 namespace {
 
-const GLfloat kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
-                                     0.0f, 1.0f, 0.0f, 0.0f,
-                                     0.0f, 0.0f, 1.0f, 0.0f,
-                                     0.0f, 0.0f, 0.0f, 1.0f};
-
 enum {
   SAMPLER_2D,
   SAMPLER_RECTANGLE_ARB,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 1b98c564..43d0798 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -120,11 +120,6 @@
 const char kEXTDrawBuffersExtension[] = "GL_EXT_draw_buffers";
 const char kEXTShaderTextureLodExtension[] = "GL_EXT_shader_texture_lod";
 
-const GLfloat kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
-                                     0.0f, 1.0f, 0.0f, 0.0f,
-                                     0.0f, 0.0f, 1.0f, 0.0f,
-                                     0.0f, 0.0f, 0.0f, 1.0f};
-
 gfx::OverlayTransform GetGFXOverlayTransform(GLenum plane_transform) {
   switch (plane_transform) {
     case GL_OVERLAY_TRANSFORM_NONE_CHROMIUM:
@@ -222,9 +217,9 @@
 // Local versions of the SET_GL_ERROR macros
 #define LOCAL_SET_GL_ERROR(error, function_name, msg) \
     ERRORSTATE_SET_GL_ERROR(state_.GetErrorState(), error, function_name, msg)
-#define LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, value, label) \
-    ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(state_.GetErrorState(), \
-                                         function_name, value, label)
+#define LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, value, label)          \
+  ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(state_.GetErrorState(), function_name, \
+                                       static_cast<uint32_t>(value), label)
 #define LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(function_name) \
     ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(state_.GetErrorState(), \
                                               function_name)
@@ -13427,29 +13422,6 @@
 
 namespace {
 
-const int kS3TCBlockWidth = 4;
-
-typedef struct {
-  int blockWidth;
-  int blockHeight;
-} ASTCBlockArray;
-
-const ASTCBlockArray kASTCBlockArray[] = {
-    {4, 4},   /* GL_COMPRESSED_RGBA_ASTC_4x4_KHR */
-    {5, 4},   /* and GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR */
-    {5, 5},
-    {6, 5},
-    {6, 6},
-    {8, 5},
-    {8, 6},
-    {8, 8},
-    {10, 5},
-    {10, 6},
-    {10, 8},
-    {10, 10},
-    {12, 10},
-    {12, 12}};
-
 bool CheckETCFormatSupport(const FeatureInfo& feature_info) {
   const gl::GLVersionInfo& version_info = feature_info.gl_version_info();
   return version_info.IsAtLeastGL(4, 3) || version_info.IsAtLeastGLES(3, 0) ||
@@ -13591,18 +13563,6 @@
   return decompressed_data;
 }
 
-bool IsValidS3TCSizeForWebGL(GLint level, GLsizei size) {
-  // WebGL only allows multiple-of-4 sizes, except for levels > 0 where it also
-  // allows 1 or 2. See WEBGL_compressed_texture_s3tc.
-  return (level && size == 1) ||
-         (level && size == 2) ||
-         !(size % kS3TCBlockWidth);
-}
-
-bool IsValidPVRTCSize(GLint level, GLsizei size) {
-  return GLES2Util::IsPOT(size);
-}
-
 }  // anonymous namespace.
 
 bool GLES2DecoderImpl::ValidateCompressedTexFuncData(const char* function_name,
@@ -13639,106 +13599,14 @@
 bool GLES2DecoderImpl::ValidateCompressedTexDimensions(
     const char* function_name, GLenum target, GLint level,
     GLsizei width, GLsizei height, GLsizei depth, GLenum format) {
-  switch (format) {
-    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
-      DCHECK_EQ(1, depth);  // 2D formats.
-      if (feature_info_->IsWebGLContext() &&
-          (!IsValidS3TCSizeForWebGL(level, width) ||
-           !IsValidS3TCSizeForWebGL(level, height))) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "width or height invalid for level");
-        return false;
-      }
-      return true;
-    case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-    case GL_ATC_RGB_AMD:
-    case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
-    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
-    case GL_ETC1_RGB8_OES:
-      DCHECK_EQ(1, depth);  // 2D formats.
-      if (width <= 0 || height <= 0) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "width or height invalid for level");
-        return false;
-      }
-      return true;
-    case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
-    case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
-    case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
-    case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
-      DCHECK_EQ(1, depth);  // 2D formats.
-      if (!IsValidPVRTCSize(level, width) ||
-          !IsValidPVRTCSize(level, height)) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "width or height invalid for level");
-        return false;
-      }
-      return true;
-
-    // ES3 formats.
-    case GL_COMPRESSED_R11_EAC:
-    case GL_COMPRESSED_SIGNED_R11_EAC:
-    case GL_COMPRESSED_RG11_EAC:
-    case GL_COMPRESSED_SIGNED_RG11_EAC:
-    case GL_COMPRESSED_RGB8_ETC2:
-    case GL_COMPRESSED_SRGB8_ETC2:
-    case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-    case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-    case GL_COMPRESSED_RGBA8_ETC2_EAC:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-      if (width < 0 || height < 0 || depth < 0) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "width, height, or depth invalid");
-        return false;
-      }
-      if (target == GL_TEXTURE_3D) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "target invalid for format");
-        return false;
-      }
-      return true;
-    default:
-      return false;
+  const char* error_message = "";
+  if (!::gpu::gles2::ValidateCompressedTexDimensions(
+          target, level, width, height, depth, format,
+          feature_info_->IsWebGLContext(), &error_message)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, error_message);
+    return false;
   }
+  return true;
 }
 
 bool GLES2DecoderImpl::ValidateCompressedTexSubDimensions(
@@ -13746,179 +13614,14 @@
     GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
     GLsizei width, GLsizei height, GLsizei depth, GLenum format,
     Texture* texture) {
-  if (xoffset < 0 || yoffset < 0 || zoffset < 0) {
-    LOCAL_SET_GL_ERROR(
-        GL_INVALID_VALUE, function_name, "x/y/z offset < 0");
+  const char* error_message = "";
+  if (!::gpu::gles2::ValidateCompressedTexSubDimensions(
+          target, level, xoffset, yoffset, zoffset, width, height, depth,
+          format, texture, feature_info_->IsWebGLContext(), &error_message)) {
+    LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, error_message);
     return false;
   }
-
-  switch (format) {
-    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-    case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-    case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: {
-      const int kBlockWidth = 4;
-      const int kBlockHeight = 4;
-      if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "xoffset or yoffset not multiple of 4");
-        return false;
-      }
-      GLsizei tex_width = 0;
-      GLsizei tex_height = 0;
-      if (!texture->GetLevelSize(target, level,
-                                 &tex_width, &tex_height, nullptr) ||
-          width - xoffset > tex_width ||
-          height - yoffset > tex_height) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name, "dimensions out of range");
-        return false;
-      }
-      if ((((width % kBlockWidth) != 0) && (width + xoffset != tex_width)) ||
-          (((height % kBlockHeight) != 0) &&
-           (height + yoffset != tex_height))) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
-                           "dimensions do not align to a block boundary");
-        return false;
-      }
-      return true;
-    }
-    case GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
-    case GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: {
-      const int index =
-          (format < GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR)
-              ? static_cast<int>(format - GL_COMPRESSED_RGBA_ASTC_4x4_KHR)
-              : static_cast<int>(format -
-                                 GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR);
-
-      const int kBlockWidth = kASTCBlockArray[index].blockWidth;
-      const int kBlockHeight = kASTCBlockArray[index].blockHeight;
-
-      if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
-                           "xoffset or yoffset not multiple of 4");
-        return false;
-      }
-      GLsizei tex_width = 0;
-      GLsizei tex_height = 0;
-      if (!texture->GetLevelSize(target, level, &tex_width, &tex_height,
-                                 nullptr) ||
-          width - xoffset > tex_width || height - yoffset > tex_height) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
-                           "dimensions out of range");
-        return false;
-      }
-      if ((((width % kBlockWidth) != 0) && (width + xoffset != tex_width)) ||
-          (((height % kBlockHeight) != 0) &&
-           (height + yoffset != tex_height))) {
-        LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
-                           "dimensions do not align to a block boundary");
-        return false;
-      }
-      return true;
-    }
-    case GL_ATC_RGB_AMD:
-    case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD:
-    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: {
-      LOCAL_SET_GL_ERROR(
-          GL_INVALID_OPERATION, function_name,
-          "not supported for ATC textures");
-      return false;
-    }
-    case GL_ETC1_RGB8_OES: {
-      LOCAL_SET_GL_ERROR(
-          GL_INVALID_OPERATION, function_name,
-          "not supported for ECT1_RGB8_OES textures");
-      return false;
-    }
-    case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
-    case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
-    case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
-    case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: {
-      if ((xoffset != 0) || (yoffset != 0)) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "xoffset and yoffset must be zero");
-        return false;
-      }
-      GLsizei tex_width = 0;
-      GLsizei tex_height = 0;
-      if (!texture->GetLevelSize(target, level,
-                                 &tex_width, &tex_height, nullptr) ||
-          width != tex_width ||
-          height != tex_height) {
-        LOCAL_SET_GL_ERROR(
-            GL_INVALID_OPERATION, function_name,
-            "dimensions must match existing texture level dimensions");
-        return false;
-      }
-      return ValidateCompressedTexDimensions(
-          function_name, target, level, width, height, 1, format);
-    }
-
-    // ES3 formats
-    case GL_COMPRESSED_R11_EAC:
-    case GL_COMPRESSED_SIGNED_R11_EAC:
-    case GL_COMPRESSED_RG11_EAC:
-    case GL_COMPRESSED_SIGNED_RG11_EAC:
-    case GL_COMPRESSED_RGB8_ETC2:
-    case GL_COMPRESSED_SRGB8_ETC2:
-    case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-    case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-    case GL_COMPRESSED_RGBA8_ETC2_EAC:
-    case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-      {
-        const int kBlockSize = 4;
-        GLsizei tex_width, tex_height;
-        if (target == GL_TEXTURE_3D ||
-            !texture->GetLevelSize(target, level,
-                                   &tex_width, &tex_height, nullptr) ||
-            (xoffset % kBlockSize) || (yoffset % kBlockSize) ||
-            ((width % kBlockSize) && xoffset + width != tex_width) ||
-            ((height % kBlockSize) && yoffset + height != tex_height)) {
-          LOCAL_SET_GL_ERROR(
-              GL_INVALID_OPERATION, function_name,
-              "dimensions must match existing texture level dimensions");
-          return false;
-        }
-        return true;
-      }
-    default:
-      LOCAL_SET_GL_ERROR(GL_INVALID_ENUM, function_name,
-                         "unknown compressed texture format");
-      return false;
-  }
+  return true;
 }
 
 error::Error GLES2DecoderImpl::HandleCompressedTexImage2DBucket(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
index ffe583d..1a9f266 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -79,13 +79,13 @@
   }
 }
 
-void APIENTRY GLDebugMessageCallback(GLenum source,
-                                     GLenum type,
-                                     GLuint id,
-                                     GLenum severity,
-                                     GLsizei length,
-                                     const GLchar* message,
-                                     const GLvoid* user_param) {
+void APIENTRY PassthroughGLDebugMessageCallback(GLenum source,
+                                                GLenum type,
+                                                GLuint id,
+                                                GLenum severity,
+                                                GLsizei length,
+                                                const GLchar* message,
+                                                const GLvoid* user_param) {
   DCHECK(user_param != nullptr);
   GLES2DecoderPassthroughImpl* command_decoder =
       static_cast<GLES2DecoderPassthroughImpl*>(const_cast<void*>(user_param));
@@ -782,7 +782,8 @@
   // only enable debug logging if requested.
   bool log_non_errors =
       group_->gpu_preferences().enable_gpu_driver_debug_logging;
-  InitializeGLDebugLogging(log_non_errors, GLDebugMessageCallback, this);
+  InitializeGLDebugLogging(log_non_errors, PassthroughGLDebugMessageCallback,
+                           this);
 
   if (feature_info_->feature_flags().chromium_texture_filtering_hint &&
       feature_info_->feature_flags().is_swiftshader) {
diff --git a/gpu/command_buffer/service/service_discardable_manager.cc b/gpu/command_buffer/service/service_discardable_manager.cc
index 43df3de2..690c47c6 100644
--- a/gpu/command_buffer/service/service_discardable_manager.cc
+++ b/gpu/command_buffer/service/service_discardable_manager.cc
@@ -11,7 +11,7 @@
 
 namespace gpu {
 namespace {
-size_t CacheSizeLimit() {
+size_t DiscardableCacheSizeLimit() {
 // Cache size values are designed to roughly correspond to existing image cache
 // sizes for 1-1.5 renderers. These will be updated as more types of data are
 // moved to this cache.
@@ -58,7 +58,7 @@
 
 ServiceDiscardableManager::ServiceDiscardableManager()
     : entries_(EntryCache::NO_AUTO_EVICT),
-      cache_size_limit_(CacheSizeLimit()) {}
+      cache_size_limit_(DiscardableCacheSizeLimit()) {}
 
 ServiceDiscardableManager::~ServiceDiscardableManager() {
 #if DCHECK_IS_ON()
diff --git a/gpu/command_buffer/service/service_transfer_cache.cc b/gpu/command_buffer/service/service_transfer_cache.cc
index d0cbab77..755a220 100644
--- a/gpu/command_buffer/service/service_transfer_cache.cc
+++ b/gpu/command_buffer/service/service_transfer_cache.cc
@@ -22,7 +22,7 @@
 // unbounded handle growth with tiny entries.
 static size_t kMaxCacheEntries = 2000;
 
-size_t CacheSizeLimit() {
+size_t ServiceTransferCacheSizeLimit() {
   size_t memory_usage = 128 * 1024 * 1024;
   if (base::SysInfo::IsLowEndDevice()) {
     // Based on the 512KB limit used for discardable images in non-OOP-R, but
@@ -78,7 +78,7 @@
 
 ServiceTransferCache::ServiceTransferCache()
     : entries_(EntryCache::NO_AUTO_EVICT),
-      cache_size_limit_(CacheSizeLimit()),
+      cache_size_limit_(ServiceTransferCacheSizeLimit()),
       max_cache_entries_(kMaxCacheEntries) {
   // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
   // Don't register a dump provider in these cases.
@@ -193,7 +193,7 @@
   }
 
   EnforceLimits();
-  cache_size_limit_ = CacheSizeLimit();
+  cache_size_limit_ = ServiceTransferCacheSizeLimit();
 }
 
 bool ServiceTransferCache::OnMemoryDump(
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 9862f0f..565a640 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -213,6 +213,10 @@
   return path_;
 }
 
+base::FilePath HeadlessBrowserContextImpl::GetCachePath() const {
+  return path_;
+}
+
 bool HeadlessBrowserContextImpl::IsOffTheRecord() const {
   return context_options_->incognito_mode();
 }
diff --git a/headless/lib/browser/headless_browser_context_impl.h b/headless/lib/browser/headless_browser_context_impl.h
index 3eb7684..b4b2f1a5 100644
--- a/headless/lib/browser/headless_browser_context_impl.h
+++ b/headless/lib/browser/headless_browser_context_impl.h
@@ -65,6 +65,7 @@
   std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
   bool IsOffTheRecord() const override;
   content::ResourceContext* GetResourceContext() override;
   content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;
diff --git a/infra/config/global/luci-milo-dev.cfg b/infra/config/global/luci-milo-dev.cfg
index 067d97b..c1c9892 100644
--- a/infra/config/global/luci-milo-dev.cfg
+++ b/infra/config/global/luci-milo-dev.cfg
@@ -1107,6 +1107,12 @@
     category: "perf|android"
     short_name: "N5X"
   }
+  builders {
+    name: "buildbot/chromium.perf/android-go-perf"
+    name: "buildbucket/luci.chromium.ci/android-go-perf"
+    category: "perf|android"
+    short_name: "go"
+  }
   builders: {
     name: "buildbot/chromium.perf/Android One Perf"
     category: "perf|android"
@@ -2757,10 +2763,6 @@
     name: "buildbot/chromium.perf.fyi/One Buildbot Step Test Builder"
     category: "linux"
   }
-  builders: {
-    name: "buildbot/chromium.perf.fyi/Android Go"
-    category: "android"
-  }
 }
 
 consoles: {
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 65158e3..2e45e22 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -1250,6 +1250,12 @@
     short_name: "N5X"
   }
   builders {
+    name: "buildbot/chromium.perf/android-go-perf"
+    name: "buildbucket/luci.chromium.ci/android-go-perf"
+    category: "perf|android"
+    short_name: "go"
+  }
+  builders {
     name: "buildbot/chromium.perf/Android One Perf"
     name: "buildbucket/luci.chromium.ci/Android One Perf"
     category: "perf|android"
@@ -3372,11 +3378,6 @@
     category: "mac"
   }
   builders {
-    name: "buildbot/chromium.perf.fyi/Android Go"
-    name: "buildbucket/luci.chromium.ci/Android Go"
-    category: "android"
-  }
-  builders {
     name: "buildbot/chromium.perf.fyi/Win Builder Perf FYI"
     name: "buildbucket/luci.chromium.ci/Win Builder Perf FYI"
   }
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index d534ef2..b06ef5a 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -364,15 +364,10 @@
           ->change_processor()
           ->GetControllerDelegateOnUIThread();
     }
-    case syncer::TYPED_URLS: {
-      history::HistoryService* history =
-          ios::HistoryServiceFactory::GetForBrowserState(
-              browser_state_, ServiceAccessType::EXPLICIT_ACCESS);
-      return history ? history->GetTypedURLSyncBridge()
-                           ->change_processor()
-                           ->GetControllerDelegateOnUIThread()
-                     : base::WeakPtr<syncer::ModelTypeControllerDelegate>();
-    }
+    case syncer::TYPED_URLS:
+      // TypedURLModelTypeController doesn't exercise this function.
+      NOTREACHED();
+      return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
     case syncer::USER_CONSENTS:
       return ConsentAuditorFactory::GetForBrowserState(browser_state_)
           ->GetControllerDelegateOnUIThread();
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
index ee27162..1233ffc 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_synchronizer.mm
@@ -130,10 +130,6 @@
                                  animated:NO];
   }
 
-  CGFloat pinnedOffsetY = [self.headerController pinnedOffsetY];
-  self.collectionShiftingOffset =
-      MAX(0, pinnedOffsetY - self.collectionView.contentOffset.y);
-
   if (self.collectionController.scrolledToTop) {
     self.shouldAnimateHeader = NO;
     if (completion)
@@ -141,6 +137,10 @@
     return;
   }
 
+  CGFloat pinnedOffsetY = [self.headerController pinnedOffsetY];
+  self.collectionShiftingOffset =
+      MAX(0, pinnedOffsetY - self.collectionView.contentOffset.y);
+
   self.collectionController.scrolledToTop = YES;
   self.shouldAnimateHeader = YES;
   self.shiftUpCompletionBlock = completion;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index 22d1856..e2e224d1 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -508,8 +508,7 @@
 
   self.omniboxFocused = YES;
 
-  if (!IsUIRefreshPhase1Enabled() || ![self.delegate isScrolledToTop])
-    [self shiftTilesUp];
+  [self shiftTilesUp];
 }
 
 - (void)locationBarResignsFirstResponder {
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index da22060..a7954eb 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -574,6 +574,25 @@
       @"The collection is not scrolled back to its previous position");
 }
 
+// Tests tapping the search button when the fake omnibox is scrolled.
+- (void)testTapSearchButtonFakeOmniboxScrolled {
+  if (!IsUIRefreshPhase1Enabled() ||
+      content_suggestions::IsRegularXRegularSizeClass()) {
+    // This only happens on iPhone, since on iPad there's no secondary toolbar.
+    return;
+  }
+
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::
+                                          ContentSuggestionCollectionView()]
+      performAction:grey_swipeFastInDirection(kGREYDirectionUp)];
+  // Tap the search button.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kToolbarOmniboxButtonIdentifier)]
+      performAction:grey_tap()];
+  [ChromeEarlGrey
+      waitForElementWithMatcherSufficientlyVisible:chrome_test_util::Omnibox()];
+}
+
 #pragma mark - Helpers
 
 - (void)addMostVisitedTile {
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index 56abdee..8886fd6e 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -715,15 +715,18 @@
   self.doneButton.titleLabel.adjustsFontForContentSizeCategory = YES;
   self.closeAllButton.titleLabel.adjustsFontForContentSizeCategory = YES;
   self.doneButton.accessibilityIdentifier = kTabGridDoneButtonIdentifier;
+  self.doneButton.exclusiveTouch = YES;
   [self.doneButton addTarget:self
                       action:@selector(doneButtonTapped:)
             forControlEvents:UIControlEventTouchUpInside];
   [self.closeAllButton addTarget:self
                           action:@selector(closeAllButtonTapped:)
                 forControlEvents:UIControlEventTouchUpInside];
+  self.closeAllButton.exclusiveTouch = YES;
   [self.newTabButton addTarget:self
                         action:@selector(newTabButtonTapped:)
               forControlEvents:UIControlEventTouchUpInside];
+  self.newTabButton.exclusiveTouch = YES;
   [self configureButtonsForActiveAndCurrentPage];
 }
 
diff --git a/media/base/decrypt_config.h b/media/base/decrypt_config.h
index 25265a2..111a803 100644
--- a/media/base/decrypt_config.h
+++ b/media/base/decrypt_config.h
@@ -102,11 +102,11 @@
   DISALLOW_ASSIGN(DecryptConfig);
 };
 
-}  // namespace media
-
 inline std::ostream& operator<<(std::ostream& os,
                                 const media::DecryptConfig& obj) {
   return obj.Print(os);
 }
 
+}  // namespace media
+
 #endif  // MEDIA_BASE_DECRYPT_CONFIG_H_
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc
index 54a5924..2404fe8d 100644
--- a/media/base/video_frame.cc
+++ b/media/base/video_frame.cc
@@ -6,6 +6,8 @@
 
 #include <algorithm>
 #include <climits>
+#include <numeric>
+#include <utility>
 
 #include "base/atomic_sequence_num.h"
 #include "base/bind.h"
@@ -225,9 +227,12 @@
     return nullptr;
   }
 
-  return new VideoFrame(format, storage, coded_size, visible_rect, natural_size,
-                        mailbox_holders, std::move(mailbox_holder_release_cb),
-                        timestamp);
+  scoped_refptr<VideoFrame> frame = new VideoFrame(
+      format, storage, coded_size, visible_rect, natural_size, timestamp);
+  memcpy(&frame->mailbox_holders_, mailbox_holders,
+         sizeof(frame->mailbox_holders_));
+  frame->mailbox_holders_release_cb_ = std::move(mailbox_holder_release_cb);
+  return frame;
 }
 
 // static
@@ -314,11 +319,13 @@
     return nullptr;
   }
 
+  const size_t height = coded_size.height();
   scoped_refptr<VideoFrame> frame(new VideoFrame(
-      format, storage, coded_size, visible_rect, natural_size, timestamp));
-  frame->strides_[kYPlane] = y_stride;
-  frame->strides_[kUPlane] = u_stride;
-  frame->strides_[kVPlane] = v_stride;
+      VideoFrameLayout(
+          format, coded_size, {y_stride, u_stride, v_stride},
+          {std::abs(y_stride) * height, std::abs(u_stride) * height,
+           std::abs(v_stride) * height}),
+      storage, visible_rect, natural_size, timestamp));
   frame->data_[kYPlane] = y_data;
   frame->data_[kUPlane] = u_data;
   frame->data_[kVPlane] = v_data;
@@ -354,12 +361,13 @@
     return nullptr;
   }
 
+  const size_t height = coded_size.height();
   scoped_refptr<VideoFrame> frame(new VideoFrame(
-      format, storage, coded_size, visible_rect, natural_size, timestamp));
-  frame->strides_[kYPlane] = y_stride;
-  frame->strides_[kUPlane] = u_stride;
-  frame->strides_[kVPlane] = v_stride;
-  frame->strides_[kAPlane] = a_stride;
+      VideoFrameLayout(format, coded_size,
+                       {y_stride, u_stride, v_stride, a_stride},
+                       {abs(y_stride) * height, abs(u_stride) * height,
+                        abs(v_stride) * height, abs(a_stride) * height}),
+      storage, visible_rect, natural_size, timestamp));
   frame->data_[kYPlane] = y_data;
   frame->data_[kUPlane] = u_data;
   frame->data_[kVPlane] = v_data;
@@ -391,14 +399,15 @@
   }
 
   gpu::MailboxHolder mailbox_holders[kMaxPlanes];
-  scoped_refptr<VideoFrame> frame =
-      new VideoFrame(format, storage, coded_size, visible_rect, natural_size,
-                     mailbox_holders, ReleaseMailboxCB(), timestamp);
+  scoped_refptr<VideoFrame> frame = new VideoFrame(
+      format, storage, coded_size, visible_rect, natural_size, timestamp);
   if (!frame) {
     LOG(DFATAL) << __func__ << " Couldn't create VideoFrame instance.";
     return nullptr;
   }
-
+  memcpy(&frame->mailbox_holders_, mailbox_holders,
+         sizeof(frame->mailbox_holders_));
+  frame->mailbox_holders_release_cb_ = ReleaseMailboxCB();
   frame->dmabuf_fds_ = std::move(dmabuf_fds);
 
   return frame;
@@ -477,14 +486,13 @@
   }
 
   scoped_refptr<VideoFrame> wrapping_frame(
-      new VideoFrame(format, frame->storage_type(), frame->coded_size(),
+      new VideoFrame(frame->layout().Clone(), frame->storage_type(),
                      visible_rect, natural_size, frame->timestamp()));
 
   // Copy all metadata to the wrapped frame.
   wrapping_frame->metadata()->MergeMetadataFrom(frame->metadata());
 
   for (size_t i = 0; i < NumPlanes(format); ++i) {
-    wrapping_frame->strides_[i] = frame->stride(i);
     wrapping_frame->data_[i] = frame->data(i);
   }
 
@@ -593,7 +601,9 @@
     case PIXEL_FORMAT_I420A:
       return 4;
     case PIXEL_FORMAT_UNKNOWN:
-      break;
+      // Note: PIXEL_FORMAT_UNKNOWN is used for end-of-stream frame.
+      // Set its NumPlanes() to zero to avoid NOTREACHED().
+      return 0;
   }
   NOTREACHED() << "Unsupported video frame format: " << format;
   return 0;
@@ -741,7 +751,7 @@
     return 0;
 
   size_t i = 0;
-  for (; i < NumPlanes(format_); ++i) {
+  for (; i < NumPlanes(format()); ++i) {
     if (mailbox_holders_[i].mailbox.IsZero()) {
       return i;
     }
@@ -769,50 +779,29 @@
   return color_space_;
 }
 
-void VideoFrame::set_color_space(const gfx::ColorSpace& color_space) {
-  color_space_ = color_space;
-}
-
-int VideoFrame::stride(size_t plane) const {
-  DCHECK(IsValidPlane(plane, format_));
-  return strides_[plane];
-}
-
 int VideoFrame::row_bytes(size_t plane) const {
-  return RowBytes(plane, format_, coded_size_.width());
+  return RowBytes(plane, format(), coded_size().width());
 }
 
 int VideoFrame::rows(size_t plane) const {
-  return Rows(plane, format_, coded_size_.height());
-}
-
-const uint8_t* VideoFrame::data(size_t plane) const {
-  DCHECK(IsValidPlane(plane, format_));
-  DCHECK(IsMappable());
-  return data_[plane];
-}
-
-uint8_t* VideoFrame::data(size_t plane) {
-  DCHECK(IsValidPlane(plane, format_));
-  DCHECK(IsMappable());
-  return data_[plane];
+  return Rows(plane, format(), coded_size().height());
 }
 
 const uint8_t* VideoFrame::visible_data(size_t plane) const {
-  DCHECK(IsValidPlane(plane, format_));
+  DCHECK(IsValidPlane(plane, format()));
   DCHECK(IsMappable());
 
   // Calculate an offset that is properly aligned for all planes.
-  const gfx::Size alignment = CommonAlignment(format_);
+  const gfx::Size alignment = CommonAlignment(format());
   const gfx::Point offset(RoundDown(visible_rect_.x(), alignment.width()),
                           RoundDown(visible_rect_.y(), alignment.height()));
 
-  const gfx::Size subsample = SampleSize(format_, plane);
+  const gfx::Size subsample = SampleSize(format(), plane);
   DCHECK(offset.x() % subsample.width() == 0);
   DCHECK(offset.y() % subsample.height() == 0);
   return data(plane) +
          stride(plane) * (offset.y() / subsample.height()) +  // Row offset.
-         BytesPerElement(format_, plane) *                    // Column offset.
+         BytesPerElement(format(), plane) *                   // Column offset.
              (offset.x() / subsample.width());
 }
 
@@ -824,7 +813,7 @@
 const gpu::MailboxHolder&
 VideoFrame::mailbox_holder(size_t texture_index) const {
   DCHECK(HasTextures());
-  DCHECK(IsValidPlane(texture_index, format_));
+  DCHECK(IsValidPlane(texture_index, format()));
   return mailbox_holders_[texture_index];
 }
 
@@ -932,14 +921,14 @@
     return "end of stream";
 
   std::ostringstream s;
-  s << ConfigToString(format_, storage_type_, coded_size_, visible_rect_,
+  s << ConfigToString(format(), storage_type_, coded_size(), visible_rect_,
                       natural_size_)
     << " timestamp:" << timestamp_.InMicroseconds();
   return s.str();
 }
 
 size_t VideoFrame::BitDepth() const {
-  switch (format_) {
+  switch (format()) {
     case media::PIXEL_FORMAT_UNKNOWN:
       NOTREACHED();
       FALLTHROUGH;
@@ -1012,25 +1001,34 @@
     return nullptr;
   }
 
-  scoped_refptr<VideoFrame> frame;
+  scoped_refptr<VideoFrame> frame = new VideoFrame(
+      format, storage_type, coded_size, visible_rect, natural_size, timestamp);
+
   if (storage_type == STORAGE_SHMEM) {
     if (read_only_region || unsafe_region) {
       DCHECK(!handle.IsValid());
-      frame = new VideoFrame(format, storage_type, coded_size, visible_rect,
-                             natural_size, timestamp, read_only_region,
-                             unsafe_region, data_offset);
+      DCHECK_NE(!!read_only_region, !!unsafe_region)
+          << "Expected exactly one read-only or unsafe region for "
+          << "STORAGE_SHMEM VideoFrame";
+      if (read_only_region) {
+        frame->read_only_shared_memory_region_ = read_only_region;
+        DCHECK(frame->read_only_shared_memory_region_->IsValid());
+      } else if (unsafe_region) {
+        frame->unsafe_shared_memory_region_ = unsafe_region;
+        DCHECK(frame->unsafe_shared_memory_region_->IsValid());
+      }
+      frame->shared_memory_offset_ = data_offset;
     } else {
-      frame = new VideoFrame(format, storage_type, coded_size, visible_rect,
-                             natural_size, timestamp, handle, data_offset);
+      frame->AddSharedMemoryHandle(handle);
+      frame->shared_memory_offset_ = data_offset;
     }
-  } else {
-    frame = new VideoFrame(format, storage_type, coded_size, visible_rect,
-                           natural_size, timestamp);
   }
+
   switch (NumPlanes(format)) {
     case 1:
-      frame->strides_[kYPlane] = RowBytes(kYPlane, format, coded_size.width());
       frame->data_[kYPlane] = data;
+      frame->layout_.set_strides(
+          {RowBytes(kYPlane, format, coded_size.width())});
       return frame;
     case 3:
       DCHECK_EQ(format, PIXEL_FORMAT_I420);
@@ -1039,12 +1037,12 @@
       // resolved.  Perhaps a CommonAlignment() check should be made in
       // IsValidConfig()?
       // http://crbug.com/555909
-      frame->strides_[kYPlane] = RowBytes(kYPlane, format, coded_size.width());
       frame->data_[kYPlane] = data;
-      frame->strides_[kVPlane] = coded_size.width() / 2;
       frame->data_[kVPlane] = data + (coded_size.GetArea() * 5 / 4);
-      frame->strides_[kUPlane] = coded_size.width() / 2;
       frame->data_[kUPlane] = data + coded_size.GetArea();
+      frame->layout_.set_strides({RowBytes(kYPlane, format, coded_size.width()),
+                                  coded_size.width() / 2,
+                                  coded_size.width() / 2});
       return frame;
     default:
       LOG(DFATAL) << "Invalid number of planes: " << NumPlanes(format)
@@ -1053,29 +1051,38 @@
   }
 }
 
+VideoFrame::VideoFrame(VideoFrameLayout layout,
+                       StorageType storage_type,
+                       const gfx::Rect& visible_rect,
+                       const gfx::Size& natural_size,
+                       base::TimeDelta timestamp)
+    : layout_(std::move(layout)),
+      storage_type_(storage_type),
+      visible_rect_(Intersection(visible_rect, gfx::Rect(layout.coded_size()))),
+      natural_size_(natural_size),
+      shared_memory_offset_(0),
+      timestamp_(timestamp),
+      unique_id_(g_unique_id_generator.GetNext()) {
+  DCHECK(IsValidConfig(format(), storage_type, coded_size(), visible_rect_,
+                       natural_size_));
+  DCHECK(visible_rect_ == visible_rect)
+      << "visible_rect " << visible_rect.ToString() << " exceeds coded_size "
+      << coded_size().ToString();
+  memset(&mailbox_holders_, 0, sizeof(mailbox_holders_));
+  memset(&data_, 0, sizeof(data_));
+}
+
 VideoFrame::VideoFrame(VideoPixelFormat format,
                        StorageType storage_type,
                        const gfx::Size& coded_size,
                        const gfx::Rect& visible_rect,
                        const gfx::Size& natural_size,
                        base::TimeDelta timestamp)
-    : format_(format),
-      storage_type_(storage_type),
-      coded_size_(coded_size),
-      visible_rect_(Intersection(visible_rect, gfx::Rect(coded_size))),
-      natural_size_(natural_size),
-      shared_memory_offset_(0),
-      timestamp_(timestamp),
-      unique_id_(g_unique_id_generator.GetNext()) {
-  DCHECK(IsValidConfig(format_, storage_type, coded_size_, visible_rect_,
-                       natural_size_));
-  DCHECK(visible_rect_ == visible_rect)
-      << "visible_rect " << visible_rect.ToString() << " exceeds coded_size "
-      << coded_size.ToString();
-  memset(&mailbox_holders_, 0, sizeof(mailbox_holders_));
-  memset(&strides_, 0, sizeof(strides_));
-  memset(&data_, 0, sizeof(data_));
-}
+    : VideoFrame(VideoFrameLayout(format, coded_size),
+                 storage_type,
+                 visible_rect,
+                 natural_size,
+                 timestamp) {}
 
 VideoFrame::~VideoFrame() {
   if (!mailbox_holders_release_cb_.is_null()) {
@@ -1124,84 +1131,6 @@
   return adjusted;
 }
 
-void VideoFrame::set_data(size_t plane, uint8_t* ptr) {
-  DCHECK(IsValidPlane(plane, format_));
-  DCHECK(ptr);
-  data_[plane] = ptr;
-}
-
-void VideoFrame::set_stride(size_t plane, int stride) {
-  DCHECK(IsValidPlane(plane, format_));
-  DCHECK_GT(stride, 0);
-  strides_[plane] = stride;
-}
-
-VideoFrame::VideoFrame(VideoPixelFormat format,
-                       StorageType storage_type,
-                       const gfx::Size& coded_size,
-                       const gfx::Rect& visible_rect,
-                       const gfx::Size& natural_size,
-                       base::TimeDelta timestamp,
-                       base::ReadOnlySharedMemoryRegion* read_only_region,
-                       base::UnsafeSharedMemoryRegion* unsafe_region,
-                       size_t shared_memory_offset)
-    : VideoFrame(format,
-                 storage_type,
-                 coded_size,
-                 visible_rect,
-                 natural_size,
-                 timestamp) {
-  DCHECK_EQ(storage_type, STORAGE_SHMEM);
-  DCHECK_EQ(bool(read_only_region) ^ bool(unsafe_region), 1)
-      << "Expected exactly one read-only or unsafe region for STORAGE_SHMEM "
-         "VideoFrame";
-  if (read_only_region) {
-    read_only_shared_memory_region_ = read_only_region;
-    DCHECK(read_only_shared_memory_region_->IsValid());
-  } else if (unsafe_region) {
-    unsafe_shared_memory_region_ = unsafe_region;
-    DCHECK(unsafe_shared_memory_region_->IsValid());
-  }
-  shared_memory_offset_ = shared_memory_offset;
-}
-
-VideoFrame::VideoFrame(VideoPixelFormat format,
-                       StorageType storage_type,
-                       const gfx::Size& coded_size,
-                       const gfx::Rect& visible_rect,
-                       const gfx::Size& natural_size,
-                       base::TimeDelta timestamp,
-                       base::SharedMemoryHandle handle,
-                       size_t shared_memory_offset)
-    : VideoFrame(format,
-                 storage_type,
-                 coded_size,
-                 visible_rect,
-                 natural_size,
-                 timestamp) {
-  DCHECK_EQ(storage_type, STORAGE_SHMEM);
-  AddSharedMemoryHandle(handle);
-  shared_memory_offset_ = shared_memory_offset;
-}
-
-VideoFrame::VideoFrame(VideoPixelFormat format,
-                       StorageType storage_type,
-                       const gfx::Size& coded_size,
-                       const gfx::Rect& visible_rect,
-                       const gfx::Size& natural_size,
-                       const gpu::MailboxHolder (&mailbox_holders)[kMaxPlanes],
-                       ReleaseMailboxCB mailbox_holder_release_cb,
-                       base::TimeDelta timestamp)
-    : VideoFrame(format,
-                 storage_type,
-                 coded_size,
-                 visible_rect,
-                 natural_size,
-                 timestamp) {
-  memcpy(&mailbox_holders_, mailbox_holders, sizeof(mailbox_holders_));
-  mailbox_holders_release_cb_ = std::move(mailbox_holder_release_cb);
-}
-
 // static
 scoped_refptr<VideoFrame> VideoFrame::CreateFrameInternal(
     VideoPixelFormat format,
@@ -1214,17 +1143,28 @@
   // we can pad the requested |coded_size| if necessary if the request does not
   // line up on sample boundaries. See discussion at http://crrev.com/1240833003
   const gfx::Size new_coded_size = DetermineAlignedSize(format, coded_size);
+  return CreateFrameWithLayout(VideoFrameLayout(format, new_coded_size),
+                               visible_rect, natural_size, timestamp,
+                               zero_initialize_memory);
+}
+
+scoped_refptr<VideoFrame> VideoFrame::CreateFrameWithLayout(
+    VideoFrameLayout layout,
+    const gfx::Rect& visible_rect,
+    const gfx::Size& natural_size,
+    base::TimeDelta timestamp,
+    bool zero_initialize_memory) {
   const StorageType storage = STORAGE_OWNED_MEMORY;
-  if (!IsValidConfig(format, storage, new_coded_size, visible_rect,
-                     natural_size)) {
+  if (!IsValidConfig(layout.format(), storage, layout.coded_size(),
+                     visible_rect, natural_size)) {
     LOG(DFATAL) << __func__ << " Invalid config."
-                << ConfigToString(format, storage, coded_size, visible_rect,
-                                  natural_size);
+                << ConfigToString(layout.format(), storage, layout.coded_size(),
+                                  visible_rect, natural_size);
     return nullptr;
   }
 
   scoped_refptr<VideoFrame> frame(new VideoFrame(
-      format, storage, new_coded_size, visible_rect, natural_size, timestamp));
+      std::move(layout), storage, visible_rect, natural_size, timestamp));
   frame->AllocateMemory(zero_initialize_memory);
   return frame;
 }
@@ -1301,42 +1241,96 @@
   DCHECK_EQ(storage_type_, STORAGE_OWNED_MEMORY);
   static_assert(0 == kYPlane, "y plane data must be index 0");
 
-  size_t data_size = 0;
-  size_t offset[kMaxPlanes];
+  CalculateUnassignedStrides();
+  std::vector<size_t> plane_size = CalculatePlaneSize();
+  size_t total_buffer_size = layout_.GetTotalBufferSize();
+  // If caller does not provide buffer layout, it uses sum of calculated color
+  // planes' size as buffer size VideoFrame needs to allocate.
+  if (total_buffer_size == 0) {
+    total_buffer_size =
+        std::accumulate(plane_size.begin(), plane_size.end(), 0u);
+  }
 
-  // Tightly pack if it is single planar.
-  if (NumPlanes(format_) == 1) {
-    data_size = AllocationSize(format_, coded_size_);
-    offset[0] = 0;
-    strides_[0] = row_bytes(0);
+  uint8_t* data = reinterpret_cast<uint8_t*>(
+      base::AlignedAlloc(total_buffer_size, kFrameAddressAlignment));
+  if (zero_initialize_memory) {
+    memset(data, 0, total_buffer_size);
+  }
+  AddDestructionObserver(base::BindOnce(&base::AlignedFree, data));
+
+  // Note that if layout.buffer_sizes is specified, color planes' layout is the
+  // same as buffers'. See CalculatePlaneSize() for detail.
+  for (size_t plane = 0, offset = 0; plane < NumPlanes(format()); ++plane) {
+    data_[plane] = data + offset;
+    offset += plane_size[plane];
+  }
+}
+
+void VideoFrame::CalculateUnassignedStrides() {
+  // Note: strides() could be {0,0,0,0}, which is uninitialized.
+  if (!layout_.strides().empty() && stride(0) != 0)
+    return;
+
+  std::vector<int32_t> strides;
+  const size_t num_planes = NumPlanes(format());
+  if (num_planes == 1) {
+    strides.push_back(row_bytes(0));
   } else {
-    for (size_t plane = 0; plane < NumPlanes(format_); ++plane) {
+    for (size_t plane = 0; plane < num_planes; ++plane) {
+      strides.push_back(RoundUp(row_bytes(plane), kFrameAddressAlignment));
+    }
+  }
+  layout_.set_strides(std::move(strides));
+}
+
+std::vector<size_t> VideoFrame::CalculatePlaneSize() const {
+  const size_t num_planes = NumPlanes(format());
+  const size_t num_buffers = layout_.num_buffers();
+  const bool buffer_equals_plane = num_buffers == num_planes;
+  const bool buffer_assigned = layout_.GetTotalBufferSize() > 0;
+
+  // We have three cases for plane size mapping:
+  // 1) buffer size assigned, and #buffers == #planes: use buffers' size as
+  //    color planes' size.
+  // 2) buffer size unassigned: use legacy calculation formula.
+  // 3) buffer size assigned, and #buffers < #planes: map first B-1 buffers'
+  //    size to first B-1 color planes. And for the rest color planes' size,
+  //    fallback to use legacy calculation formula.
+  // The reason to use buffer size (if available) as color plane size is that
+  // color plane size is used to calculate each plane's starting address.
+  // For caller who already specify a buffer for each plane, use buffer size
+  // to calculate buffer/plane head address is the trivial choice.
+  if (buffer_equals_plane && buffer_assigned) {
+    return layout_.buffer_sizes();
+  }
+
+  size_t mappable_buffers = 0;
+  if (buffer_assigned)
+    mappable_buffers = num_buffers - (buffer_equals_plane ? 0 : 1);
+
+  std::vector<size_t> plane_size;
+  for (size_t plane = 0; plane < num_planes; ++plane) {
+    if (plane < mappable_buffers) {
+      DCHECK_LT(plane, num_buffers);
+      plane_size.push_back(layout_.buffer_sizes()[plane]);
+    } else {
       // These values were chosen to mirror ffmpeg's get_video_buffer().
       // TODO(dalecurtis): This should be configurable; eventually ffmpeg wants
       // us to use av_cpu_max_align(), but... for now, they just hard-code 32.
       const size_t height = RoundUp(rows(plane), kFrameAddressAlignment);
-      strides_[plane] = RoundUp(row_bytes(plane), kFrameAddressAlignment);
-      offset[plane] = data_size;
-      data_size += height * strides_[plane];
+      const size_t width = std::abs(stride(plane));
+      plane_size.push_back(width * height);
     }
-
+  }
+  if (num_planes > 1 && mappable_buffers < num_planes) {
     // The extra line of UV being allocated is because h264 chroma MC
     // overreads by one line in some cases, see libavcodec/utils.c:
     // avcodec_align_dimensions2() and libavcodec/x86/h264_chromamc.asm:
     // put_h264_chroma_mc4_ssse3().
-    DCHECK(IsValidPlane(kUPlane, format_));
-    data_size += strides_[kUPlane] + kFrameSizePadding;
+    DCHECK(IsValidPlane(kUPlane, format()));
+    plane_size.back() += std::abs(stride(kUPlane)) + kFrameSizePadding;
   }
-
-  uint8_t* data = reinterpret_cast<uint8_t*>(
-      base::AlignedAlloc(data_size, kFrameAddressAlignment));
-  if (zero_initialize_memory)
-    memset(data, 0, data_size);
-
-  for (size_t plane = 0; plane < NumPlanes(format_); ++plane)
-    data_[plane] = data + offset[plane];
-
-  AddDestructionObserver(base::Bind(&base::AlignedFree, data));
+  return plane_size;
 }
 
 }  // namespace media
diff --git a/media/base/video_frame.h b/media/base/video_frame.h
index d70e19c..b180e7e 100644
--- a/media/base/video_frame.h
+++ b/media/base/video_frame.h
@@ -10,9 +10,11 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/callback.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/md5.h"
 #include "base/memory/aligned_memory.h"
@@ -23,6 +25,7 @@
 #include "base/synchronization/lock.h"
 #include "build/build_config.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
+#include "media/base/video_frame_layout.h"
 #include "media/base/video_frame_metadata.h"
 #include "media/base/video_types.h"
 #include "ui/gfx/color_space.h"
@@ -107,7 +110,7 @@
                             const gfx::Size& natural_size);
 
   // Creates a new frame in system memory with given parameters. Buffers for the
-  // frame are allocated but not initialized. The caller most not make
+  // frame are allocated but not initialized. The caller must not make
   // assumptions about the actual underlying size(s), but check the returned
   // VideoFrame instead.
   static scoped_refptr<VideoFrame> CreateFrame(VideoPixelFormat format,
@@ -125,6 +128,16 @@
       const gfx::Size& natural_size,
       base::TimeDelta timestamp);
 
+  // Creates a new frame in system memory with given parameters. Buffers for the
+  // frame are allocated but not initialized. The caller should specify the
+  // physical buffer size in |layout| parameter.
+  static scoped_refptr<VideoFrame> CreateFrameWithLayout(
+      VideoFrameLayout layout,
+      const gfx::Rect& visible_rect,
+      const gfx::Size& natural_size,
+      base::TimeDelta timestamp,
+      bool zero_initialize_memory);
+
   // Wraps a set of native textures with a VideoFrame.
   // |mailbox_holders_release_cb| will be called with a sync token as the
   // argument when the VideoFrame is to be destroyed.
@@ -339,16 +352,24 @@
 
   // Returns the color space of this frame's content.
   gfx::ColorSpace ColorSpace() const;
-  void set_color_space(const gfx::ColorSpace& color_space);
+  void set_color_space(const gfx::ColorSpace& color_space) {
+    color_space_ = color_space;
+  }
 
-  VideoPixelFormat format() const { return format_; }
+  const VideoFrameLayout& layout() const { return layout_; }
+
+  VideoPixelFormat format() const { return layout_.format(); }
   StorageType storage_type() const { return storage_type_; }
 
-  const gfx::Size& coded_size() const { return coded_size_; }
+  const gfx::Size& coded_size() const { return layout_.coded_size(); }
   const gfx::Rect& visible_rect() const { return visible_rect_; }
   const gfx::Size& natural_size() const { return natural_size_; }
 
-  int stride(size_t plane) const;
+  int stride(size_t plane) const {
+    DCHECK(IsValidPlane(plane, format()));
+    DCHECK_LT(plane, layout_.num_strides());
+    return layout_.strides()[plane];
+  }
 
   // Returns the number of bytes per row and number of rows for a given plane.
   //
@@ -360,8 +381,16 @@
   // Returns pointer to the buffer for a given plane, if this is an
   // IsMappable() frame type. The memory is owned by VideoFrame object and must
   // not be freed by the caller.
-  const uint8_t* data(size_t plane) const;
-  uint8_t* data(size_t plane);
+  const uint8_t* data(size_t plane) const {
+    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(IsMappable());
+    return data_[plane];
+  }
+  uint8_t* data(size_t plane) {
+    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(IsMappable());
+    return data_[plane];
+  }
 
   // Returns pointer to the data in the visible region of the frame, for
   // IsMappable() storage types. The returned pointer is offsetted into the
@@ -475,6 +504,13 @@
              const gfx::Size& natural_size,
              base::TimeDelta timestamp);
 
+  // VideoFrameLayout is initialized at caller side.
+  VideoFrame(VideoFrameLayout layout,
+             StorageType storage_type,
+             const gfx::Rect& visible_rect,
+             const gfx::Size& natural_size,
+             base::TimeDelta timestamp);
+
   virtual ~VideoFrame();
 
   // Creates a summary of the configuration settings provided as parameters.
@@ -491,37 +527,17 @@
   static gfx::Size DetermineAlignedSize(VideoPixelFormat format,
                                         const gfx::Size& dimensions);
 
-  void set_data(size_t plane, uint8_t* ptr);
-  void set_stride(size_t plane, int stride);
+  void set_data(size_t plane, uint8_t* ptr) {
+    DCHECK(IsValidPlane(plane, format()));
+    DCHECK(ptr);
+    data_[plane] = ptr;
+  }
+
+  void set_strides(std::vector<int32_t> strides) {
+    layout_.set_strides(std::move(strides));
+  }
 
  private:
-  // Clients must use the static factory/wrapping methods to create a new frame.
-  VideoFrame(VideoPixelFormat format,
-             StorageType storage_type,
-             const gfx::Size& coded_size,
-             const gfx::Rect& visible_rect,
-             const gfx::Size& natural_size,
-             base::TimeDelta timestamp,
-             base::ReadOnlySharedMemoryRegion* read_only_region,
-             base::UnsafeSharedMemoryRegion* unsafe_region,
-             size_t shared_memory_offset);
-  VideoFrame(VideoPixelFormat format,
-             StorageType storage_type,
-             const gfx::Size& coded_size,
-             const gfx::Rect& visible_rect,
-             const gfx::Size& natural_size,
-             base::TimeDelta timestamp,
-             base::SharedMemoryHandle handle,
-             size_t shared_memory_offset);
-  VideoFrame(VideoPixelFormat format,
-             StorageType storage_type,
-             const gfx::Size& coded_size,
-             const gfx::Rect& visible_rect,
-             const gfx::Size& natural_size,
-             const gpu::MailboxHolder (&mailbox_holders)[kMaxPlanes],
-             ReleaseMailboxCB mailbox_holder_release_cb,
-             base::TimeDelta timestamp);
-
   static scoped_refptr<VideoFrame> WrapExternalStorage(
       VideoPixelFormat format,
       StorageType storage_type,
@@ -556,19 +572,27 @@
 
   void AllocateMemory(bool zero_initialize_memory);
 
-  // Frame format.
-  const VideoPixelFormat format_;
+  // Calculates strides if unassigned.
+  // For the case that plane stride is not assigned, i.e. 0, in the layout_
+  // object, it calculates strides for each plane based on frame format and
+  // coded size then writes them back.
+  void CalculateUnassignedStrides();
+
+  // Calculates plane size.
+  // It first considers buffer size layout_ object provides. If layout's
+  // number of buffers equals to number of planes, and buffer size is assigned
+  // (non-zero), it returns buffers' size.
+  // Otherwise, it uses the first (num_buffers - 1) assigned buffers' size as
+  // plane size. Then for the rest unassigned planes, calculates their size
+  // based on format, coded size and stride for the plane.
+  std::vector<size_t> CalculatePlaneSize() const;
+
+  // VideFrameLayout (includes format, coded_size, and strides).
+  VideoFrameLayout layout_;
 
   // Storage type for the different planes.
   StorageType storage_type_;  // TODO(mcasas): make const
 
-  // Width and height of the video frame, in pixels. This must include pixel
-  // data for the whole image; i.e. for YUV formats with subsampled chroma
-  // planes, in the case that the visible portion of the image does not line up
-  // on a sample boundary, |coded_size_| must be rounded up appropriately and
-  // the pixel data provided for the odd pixels.
-  const gfx::Size coded_size_;
-
   // Width, height, and offsets of the visible portion of the video frame. Must
   // be a subrect of |coded_size_|. Can be odd with respect to the sample
   // boundaries, e.g. for formats with subsampled chroma.
@@ -578,11 +602,6 @@
   // (|visible_rect_.size()|) with aspect ratio taken into account.
   const gfx::Size natural_size_;
 
-  // Array of strides for each plane, typically greater or equal to the width
-  // of the surface divided by the horizontal sampling period.  Note that
-  // strides can be negative.
-  int32_t strides_[kMaxPlanes];
-
   // Array of data pointers to each plane.
   // TODO(mcasas): we don't know on ctor if we own |data_| or not. Change
   // to std::unique_ptr<uint8_t, AlignedFreeDeleter> after refactoring
diff --git a/media/base/video_frame_layout.h b/media/base/video_frame_layout.h
index b2342ec..52e1a84c 100644
--- a/media/base/video_frame_layout.h
+++ b/media/base/video_frame_layout.h
@@ -27,10 +27,12 @@
 class MEDIA_EXPORT VideoFrameLayout {
  public:
   // Constructor with strides and buffers' size.
+  // If strides and buffer_sizes are not assigned, their default value are
+  // {0, 0, 0, 0} for compatibility with video_frame.cc's original behavior.
   VideoFrameLayout(VideoPixelFormat format,
                    const gfx::Size& coded_size,
-                   std::vector<int32_t> strides = std::vector<int32_t>(),
-                   std::vector<size_t> buffer_sizes = std::vector<size_t>());
+                   std::vector<int32_t> strides = {0, 0, 0, 0},
+                   std::vector<size_t> buffer_sizes = {0, 0, 0, 0});
 
   // Move constructor.
   VideoFrameLayout(VideoFrameLayout&&);
diff --git a/media/base/video_frame_layout_unittest.cc b/media/base/video_frame_layout_unittest.cc
index 98fbfec..ee9f9d22 100644
--- a/media/base/video_frame_layout_unittest.cc
+++ b/media/base/video_frame_layout_unittest.cc
@@ -40,8 +40,12 @@
   EXPECT_EQ(layout.format(), PIXEL_FORMAT_I420);
   EXPECT_EQ(layout.coded_size(), coded_size);
   EXPECT_EQ(layout.GetTotalBufferSize(), 0u);
-  EXPECT_EQ(layout.num_strides(), 0u);
-  EXPECT_EQ(layout.num_buffers(), 0u);
+  EXPECT_EQ(layout.num_strides(), 4u);
+  EXPECT_EQ(layout.num_buffers(), 4u);
+  for (size_t i = 0; i < 4u; ++i) {
+    EXPECT_EQ(layout.strides()[i], 0);
+    EXPECT_EQ(layout.buffer_sizes()[i], 0u);
+  }
 }
 
 TEST(VideoFrameLayout, Clone) {
@@ -129,7 +133,8 @@
 
   EXPECT_EQ(layout.ToString(),
             "VideoFrameLayout format:PIXEL_FORMAT_NV12 coded_size:320x180 "
-            "num_buffers:0 buffer_sizes:[] num_strides:0 strides:[]");
+            "num_buffers:4 buffer_sizes:[0, 0, 0, 0] num_strides:4 "
+            "strides:[0, 0, 0, 0]");
 }
 
 TEST(VideoFrameLayout, SetStrideBufferSize) {
diff --git a/media/cast/sender/video_encoder_unittest.cc b/media/cast/sender/video_encoder_unittest.cc
index c64f5b0..8fea266 100644
--- a/media/cast/sender/video_encoder_unittest.cc
+++ b/media/cast/sender/video_encoder_unittest.cc
@@ -151,9 +151,12 @@
     const base::TimeDelta timestamp =
         testing_clock_.NowTicks() - first_frame_time_;
     scoped_refptr<media::VideoFrame> frame;
-    if (video_frame_factory_)
+    if (video_frame_factory_) {
+      DVLOG(1) << "MaybeCreateFrame";
       frame = video_frame_factory_->MaybeCreateFrame(size, timestamp);
+    }
     if (!frame) {
+      DVLOG(1) << "No VideoFrame, create using VideoFrame::CreateFrame";
       frame = media::VideoFrame::CreateFrame(PIXEL_FORMAT_I420, size,
                                              gfx::Rect(size), size, timestamp);
     }
diff --git a/media/cast/test/utility/video_utility.cc b/media/cast/test/utility/video_utility.cc
index e957c684..ec656f2 100644
--- a/media/cast/test/utility/video_utility.cc
+++ b/media/cast/test/utility/video_utility.cc
@@ -69,6 +69,7 @@
 
   // Set Y.
   const int height = frame_size.height();
+  VLOG(1) << "frame num_strides: " << frame->layout().num_strides();
   const int stride_y = frame->stride(VideoFrame::kYPlane);
   uint8_t* y_plane = frame->data(VideoFrame::kYPlane);
   for (int j = 0; j < height; ++j) {
diff --git a/media/mojo/clients/BUILD.gn b/media/mojo/clients/BUILD.gn
index 90b391ac..92ab540 100644
--- a/media/mojo/clients/BUILD.gn
+++ b/media/mojo/clients/BUILD.gn
@@ -2,8 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/jumbo.gni")
+
 # Implementations of media C++ interfaces using corresponding mojo services.
-source_set("clients") {
+jumbo_source_set("clients") {
   visibility = [
     "//chromecast/*",
     "//content/renderer:*",
diff --git a/media/mojo/common/BUILD.gn b/media/mojo/common/BUILD.gn
index 32d2931..969a974 100644
--- a/media/mojo/common/BUILD.gn
+++ b/media/mojo/common/BUILD.gn
@@ -2,7 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("common") {
+import("//build/config/jumbo.gni")
+
+jumbo_source_set("common") {
   sources = [
     "media_type_converters.cc",
     "media_type_converters.h",
diff --git a/media/mojo/common/mojo_shared_buffer_video_frame.cc b/media/mojo/common/mojo_shared_buffer_video_frame.cc
index e53c65e..bd7df5f8 100644
--- a/media/mojo/common/mojo_shared_buffer_video_frame.cc
+++ b/media/mojo/common/mojo_shared_buffer_video_frame.cc
@@ -4,6 +4,9 @@
 
 #include "media/mojo/common/mojo_shared_buffer_video_frame.h"
 
+#include <utility>
+#include <vector>
+
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/compiler_specific.h"
@@ -176,9 +179,7 @@
   if (!shared_buffer_mapping_)
     return false;
 
-  set_stride(kYPlane, y_stride);
-  set_stride(kUPlane, u_stride);
-  set_stride(kVPlane, v_stride);
+  set_strides({y_stride, u_stride, v_stride});
   offsets_[kYPlane] = y_offset;
   offsets_[kUPlane] = u_offset;
   offsets_[kVPlane] = v_offset;
diff --git a/media/mojo/services/BUILD.gn b/media/mojo/services/BUILD.gn
index d1fec92..3f4caa5 100644
--- a/media/mojo/services/BUILD.gn
+++ b/media/mojo/services/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/jumbo.gni")
 import("//media/media_options.gni")
 import("//services/catalog/public/tools/catalog.gni")
 import("//services/service_manager/public/cpp/service.gni")
@@ -9,7 +10,7 @@
 import("//services/service_manager/public/tools/test/service_test.gni")
 import("//testing/test.gni")
 
-component("services") {
+jumbo_component("services") {
   output_name = "media_mojo_services"
   sources = [
     "deferred_destroy_strong_binding_set.h",
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 1d4e113..aa90b645 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1561,14 +1561,20 @@
       "third_party/quic/platform/impl/quic_url_impl.h",
       "third_party/quic/platform/impl/quic_url_utils_impl.cc",
       "third_party/quic/platform/impl/quic_url_utils_impl.h",
+      "third_party/quic/quartc/quartc_clock_interface.h",
       "third_party/quic/quartc/quartc_factory.cc",
       "third_party/quic/quartc/quartc_factory.h",
+      "third_party/quic/quartc/quartc_factory_interface.cc",
+      "third_party/quic/quartc/quartc_factory_interface.h",
       "third_party/quic/quartc/quartc_packet_writer.cc",
       "third_party/quic/quartc/quartc_packet_writer.h",
       "third_party/quic/quartc/quartc_session.cc",
       "third_party/quic/quartc/quartc_session.h",
+      "third_party/quic/quartc/quartc_session_interface.h",
       "third_party/quic/quartc/quartc_stream.cc",
       "third_party/quic/quartc/quartc_stream.h",
+      "third_party/quic/quartc/quartc_stream_interface.h",
+      "third_party/quic/quartc/quartc_task_runner_interface.h",
       "third_party/spdy/core/fuzzing/hpack_fuzz_util.cc",
       "third_party/spdy/core/fuzzing/hpack_fuzz_util.h",
       "third_party/spdy/core/hpack/hpack_constants.cc",
diff --git a/net/third_party/quic/quartc/quartc_clock_interface.h b/net/third_party/quic/quartc/quartc_clock_interface.h
new file mode 100644
index 0000000..53366d70
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_clock_interface.h
@@ -0,0 +1,21 @@
+// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_CLOCK_INTERFACE_H_
+#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_CLOCK_INTERFACE_H_
+
+#include <stdint.h>
+
+namespace quic {
+
+// Implemented by the Quartc API user to provide a timebase.
+class QuartcClockInterface {
+ public:
+  virtual ~QuartcClockInterface() {}
+  virtual int64_t NowMicroseconds() = 0;
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_CLOCK_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_factory.cc b/net/third_party/quic/quartc/quartc_factory.cc
index e5e0287e..099808c 100644
--- a/net/third_party/quic/quartc/quartc_factory.cc
+++ b/net/third_party/quic/quartc/quartc_factory.cc
@@ -11,17 +11,106 @@
 
 namespace quic {
 
+namespace {
+
+// Implements the QuicAlarm with QuartcTaskRunnerInterface for the Quartc
+//  users other than Chromium. For example, WebRTC will create QuartcAlarm with
+// a QuartcTaskRunner implemented by WebRTC.
+class QuartcAlarm : public QuicAlarm, public QuartcTaskRunnerInterface::Task {
+ public:
+  QuartcAlarm(const QuicClock* clock,
+              QuartcTaskRunnerInterface* task_runner,
+              QuicArenaScopedPtr<QuicAlarm::Delegate> delegate)
+      : QuicAlarm(std::move(delegate)),
+        clock_(clock),
+        task_runner_(task_runner) {}
+
+  ~QuartcAlarm() override {
+    // Cancel the scheduled task before getting deleted.
+    CancelImpl();
+  }
+
+  // QuicAlarm overrides.
+  void SetImpl() override {
+    DCHECK(deadline().IsInitialized());
+    // Cancel it if already set.
+    CancelImpl();
+
+    int64_t delay_ms = (deadline() - (clock_->Now())).ToMilliseconds();
+    if (delay_ms < 0) {
+      delay_ms = 0;
+    }
+
+    DCHECK(task_runner_);
+    DCHECK(!scheduled_task_);
+    scheduled_task_ = task_runner_->Schedule(this, delay_ms);
+  }
+
+  void CancelImpl() override {
+    if (scheduled_task_) {
+      scheduled_task_->Cancel();
+      scheduled_task_.reset();
+    }
+  }
+
+  // QuartcTaskRunner::Task overrides.
+  void Run() override {
+    // The alarm may have been cancelled.
+    if (!deadline().IsInitialized()) {
+      return;
+    }
+
+    // The alarm may have been re-set to a later time.
+    if (clock_->Now() < deadline()) {
+      SetImpl();
+      return;
+    }
+
+    Fire();
+  }
+
+ private:
+  // Not owned by QuartcAlarm. Owned by the QuartcFactory.
+  const QuicClock* clock_;
+  // Not owned by QuartcAlarm. Owned by the QuartcFactory.
+  QuartcTaskRunnerInterface* task_runner_;
+  // Owned by QuartcAlarm.
+  std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask> scheduled_task_;
+};
+
+// Adapts QuartcClockInterface (provided by the user) to QuicClock
+// (expected by QUIC).
+class QuartcClock : public QuicClock {
+ public:
+  explicit QuartcClock(QuartcClockInterface* clock) : clock_(clock) {}
+  QuicTime ApproximateNow() const override { return Now(); }
+  QuicTime Now() const override {
+    return QuicTime::Zero() +
+           QuicTime::Delta::FromMicroseconds(clock_->NowMicroseconds());
+  }
+  QuicWallTime WallNow() const override {
+    return QuicWallTime::FromUNIXMicroseconds(clock_->NowMicroseconds());
+  }
+
+ private:
+  QuartcClockInterface* clock_;
+};
+
+}  // namespace
+
 QuartcFactory::QuartcFactory(const QuartcFactoryConfig& factory_config)
-    : alarm_factory_(factory_config.alarm_factory),
-      clock_(factory_config.clock) {}
+    : task_runner_(factory_config.task_runner),
+      clock_(new QuartcClock(factory_config.clock)) {}
 
 QuartcFactory::~QuartcFactory() {}
 
-std::unique_ptr<QuartcSession> QuartcFactory::CreateQuartcSession(
+std::unique_ptr<QuartcSessionInterface> QuartcFactory::CreateQuartcSession(
     const QuartcSessionConfig& quartc_session_config) {
   DCHECK(quartc_session_config.packet_transport);
 
-  Perspective perspective = quartc_session_config.perspective;
+  Perspective perspective = quartc_session_config.is_server
+                                ? Perspective::IS_SERVER
+                                : Perspective::IS_CLIENT;
 
   // QuartcSession will eventually own both |writer| and |quic_connection|.
   auto writer =
@@ -46,50 +135,53 @@
   // Enable time-based loss detection.
   copt.push_back(kTIME);
 
-  copt.push_back(kTBBR);
+  if (quartc_session_config.congestion_control ==
+      QuartcCongestionControl::kBBR) {
+    copt.push_back(kTBBR);
 
-  // Note: These settings have no effect for Exoblaze builds since
-  // SetQuicReloadableFlag() gets stubbed out.
-  SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true);
-  SetQuicReloadableFlag(quic_unified_iw_options, true);
-  for (const auto option : quartc_session_config.bbr_options) {
-    switch (option) {
-      case (QuartcBbrOptions::kSlowerStartup):
-        copt.push_back(kBBRS);
-        break;
-      case (QuartcBbrOptions::kFullyDrainQueue):
-        copt.push_back(kBBR3);
-        break;
-      case (QuartcBbrOptions::kReduceProbeRtt):
-        copt.push_back(kBBR6);
-        break;
-      case (QuartcBbrOptions::kSkipProbeRtt):
-        copt.push_back(kBBR7);
-        break;
-      case (QuartcBbrOptions::kSkipProbeRttAggressively):
-        copt.push_back(kBBR8);
-        break;
-      case (QuartcBbrOptions::kFillUpLinkDuringProbing):
-        quic_connection->set_fill_up_link_during_probing(true);
-        break;
-      case (QuartcBbrOptions::kInitialWindow3):
-        copt.push_back(kIW03);
-        break;
-      case (QuartcBbrOptions::kInitialWindow10):
-        copt.push_back(kIW10);
-        break;
-      case (QuartcBbrOptions::kInitialWindow20):
-        copt.push_back(kIW20);
-        break;
-      case (QuartcBbrOptions::kInitialWindow50):
-        copt.push_back(kIW50);
-        break;
-      case (QuartcBbrOptions::kStartup1RTT):
-        copt.push_back(k1RTT);
-        break;
-      case (QuartcBbrOptions::kStartup2RTT):
-        copt.push_back(k2RTT);
-        break;
+    // Note: These settings have no effect for Exoblaze builds since
+    // SetQuicReloadableFlag() gets stubbed out.
+    SetQuicReloadableFlag(quic_bbr_less_probe_rtt, true);
+    SetQuicReloadableFlag(quic_unified_iw_options, true);
+    for (const auto option : quartc_session_config.bbr_options) {
+      switch (option) {
+        case (QuartcBbrOptions::kSlowerStartup):
+          copt.push_back(kBBRS);
+          break;
+        case (QuartcBbrOptions::kFullyDrainQueue):
+          copt.push_back(kBBR3);
+          break;
+        case (QuartcBbrOptions::kReduceProbeRtt):
+          copt.push_back(kBBR6);
+          break;
+        case (QuartcBbrOptions::kSkipProbeRtt):
+          copt.push_back(kBBR7);
+          break;
+        case (QuartcBbrOptions::kSkipProbeRttAggressively):
+          copt.push_back(kBBR8);
+          break;
+        case (QuartcBbrOptions::kFillUpLinkDuringProbing):
+          quic_connection->set_fill_up_link_during_probing(true);
+          break;
+        case (QuartcBbrOptions::kInitialWindow3):
+          copt.push_back(kIW03);
+          break;
+        case (QuartcBbrOptions::kInitialWindow10):
+          copt.push_back(kIW10);
+          break;
+        case (QuartcBbrOptions::kInitialWindow20):
+          copt.push_back(kIW20);
+          break;
+        case (QuartcBbrOptions::kInitialWindow50):
+          copt.push_back(kIW50);
+          break;
+        case (QuartcBbrOptions::kStartup1RTT):
+          copt.push_back(k1RTT);
+          break;
+        case (QuartcBbrOptions::kStartup2RTT):
+          copt.push_back(k2RTT);
+          break;
+      }
     }
   }
   QuicConfig quic_config;
@@ -110,15 +202,15 @@
       kStreamReceiveWindowLimit);
   quic_config.SetConnectionOptionsToSend(copt);
   quic_config.SetClientConnectionOptions(copt);
-  if (quartc_session_config.max_time_before_crypto_handshake >
-      QuicTime::Delta::Zero()) {
+  if (quartc_session_config.max_time_before_crypto_handshake_secs > 0) {
     quic_config.set_max_time_before_crypto_handshake(
-        quartc_session_config.max_time_before_crypto_handshake);
+        QuicTime::Delta::FromSeconds(
+            quartc_session_config.max_time_before_crypto_handshake_secs));
   }
-  if (quartc_session_config.max_idle_time_before_crypto_handshake >
-      QuicTime::Delta::Zero()) {
+  if (quartc_session_config.max_idle_time_before_crypto_handshake_secs > 0) {
     quic_config.set_max_idle_time_before_crypto_handshake(
-        quartc_session_config.max_idle_time_before_crypto_handshake);
+        QuicTime::Delta::FromSeconds(
+            quartc_session_config.max_idle_time_before_crypto_handshake_secs));
   }
   if (quartc_session_config.idle_network_timeout > QuicTime::Delta::Zero()) {
     quic_config.SetIdleNetworkTimeout(
@@ -132,7 +224,7 @@
   return QuicMakeUnique<QuartcSession>(
       std::move(quic_connection), quic_config,
       quartc_session_config.unique_remote_server_id, perspective,
-      this /*QuicConnectionHelperInterface*/, clock_, std::move(writer));
+      this /*QuicConnectionHelperInterface*/, clock_.get(), std::move(writer));
 }
 
 std::unique_ptr<QuicConnection> QuartcFactory::CreateQuicConnection(
@@ -144,12 +236,28 @@
   QuicSocketAddress dummy_address(QuicIpAddress::Any4(), 0 /*Port*/);
   return QuicMakeUnique<QuicConnection>(
       dummy_id, dummy_address, this, /*QuicConnectionHelperInterface*/
-      alarm_factory_ /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false,
+      this /*QuicAlarmFactory*/, packet_writer, /*owns_writer=*/false,
       perspective, CurrentSupportedVersions());
 }
 
+QuicAlarm* QuartcFactory::CreateAlarm(QuicAlarm::Delegate* delegate) {
+  return new QuartcAlarm(GetClock(), task_runner_,
+                         QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate));
+}
+
+QuicArenaScopedPtr<QuicAlarm> QuartcFactory::CreateAlarm(
+    QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+    QuicConnectionArena* arena) {
+  if (arena != nullptr) {
+    return arena->New<QuartcAlarm>(GetClock(), task_runner_,
+                                   std::move(delegate));
+  }
+  return QuicArenaScopedPtr<QuicAlarm>(
+      new QuartcAlarm(GetClock(), task_runner_, std::move(delegate)));
+}
+
 const QuicClock* QuartcFactory::GetClock() const {
-  return clock_;
+  return clock_.get();
 }
 
 QuicRandom* QuartcFactory::GetRandomGenerator() {
@@ -160,9 +268,10 @@
   return &buffer_allocator_;
 }
 
-std::unique_ptr<QuartcFactory> CreateQuartcFactory(
+std::unique_ptr<QuartcFactoryInterface> CreateQuartcFactory(
     const QuartcFactoryConfig& factory_config) {
-  return std::unique_ptr<QuartcFactory>(new QuartcFactory(factory_config));
+  return std::unique_ptr<QuartcFactoryInterface>(
+      new QuartcFactory(factory_config));
 }
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_factory.h b/net/third_party/quic/quartc/quartc_factory.h
index 8db0340..f56c2499 100644
--- a/net/third_party/quic/quartc/quartc_factory.h
+++ b/net/third_party/quic/quartc/quartc_factory.h
@@ -8,83 +8,34 @@
 #include "net/third_party/quic/core/quic_alarm_factory.h"
 #include "net/third_party/quic/core/quic_connection.h"
 #include "net/third_party/quic/core/quic_simple_buffer_allocator.h"
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/quartc/quartc_factory_interface.h"
 #include "net/third_party/quic/quartc/quartc_packet_writer.h"
-#include "net/third_party/quic/quartc/quartc_session.h"
+#include "net/third_party/quic/quartc/quartc_task_runner_interface.h"
 
 namespace quic {
 
-// Options that control the BBR algorithm.
-enum class QuartcBbrOptions {
-  kSlowerStartup,    // Once a loss is encountered in STARTUP,
-                     // switches startup to a 1.5x pacing gain.
-  kFullyDrainQueue,  // Fully drains the queue once per cycle.
-  kReduceProbeRtt,   // Probe RTT reduces CWND to 0.75 * BDP instead of 4
-                     // packets.
-  kSkipProbeRtt,     // Skip Probe RTT and extend the existing min_rtt if a
-                     // recent min_rtt is within 12.5% of the current min_rtt.
-  kSkipProbeRttAggressively,  //  Skip ProbeRTT and extend the existing min_rtt
-                              //  as long as you've been app limited at least
-                              //  once.
-  kFillUpLinkDuringProbing,   // Sends probing retransmissions whenever we
-                              // become application limited.
-  kInitialWindow3,            // Use a 3-packet initial congestion window.
-  kInitialWindow10,           // Use a 10-packet initial congestion window.
-  kInitialWindow20,           // Use a 20-packet initial congestion window.
-  kInitialWindow50,           // Use a 50-packet initial congestion window.
-  kStartup1RTT,               // Stay in STARTUP for 1 RTT.
-  kStartup2RTT,               // Stay in STARTUP for 2 RTTs.
-};
-
-// The configuration for creating a QuartcFactory.
-struct QuartcFactoryConfig {
-  // Factory for |QuicAlarm|s. Implemented by the Quartc user with different
-  // mechanisms. For example in WebRTC, it is implemented with rtc::Thread.
-  // Owned by the user, and needs to stay alive for as long as the QuartcFactory
-  // exists.
-  QuicAlarmFactory* alarm_factory = nullptr;
-  // The clock used by |QuicAlarm|s. Implemented by the Quartc user. Owned by
-  // the user, and needs to stay alive for as long as the QuartcFactory exists.
-  QuicClock* clock = nullptr;
-};
-
-struct QuartcSessionConfig {
-  // When using Quartc, there are two endpoints. The QuartcSession on one
-  // endpoint must act as a server and the one on the other side must act as a
-  // client.
-  Perspective perspective = Perspective::IS_CLIENT;
-  // This is only needed when is_server = false.  It must be unique
-  // for each endpoint the local endpoint may communicate with. For example,
-  // a WebRTC client could use the remote endpoint's crypto fingerprint
-  QuicString unique_remote_server_id;
-  // The way the QuicConnection will send and receive packets, like a virtual
-  // UDP socket. For WebRTC, this will typically be an IceTransport.
-  QuartcPacketTransport* packet_transport = nullptr;
-  // The maximum size of the packet can be written with the packet writer.
-  // 1200 bytes by default.
-  QuicPacketLength max_packet_size = 1200;
-  // Options to control the BBR algorithm. In case the congestion control is
-  // set to anything but BBR, these options are ignored.
-  std::vector<QuartcBbrOptions> bbr_options;
-  // Timeouts for the crypto handshake. Set them to higher values to
-  // prevent closing the session before it started on a slow network.
-  // Zero entries are ignored and QUIC defaults are used in that case.
-  QuicTime::Delta max_idle_time_before_crypto_handshake =
-      QuicTime::Delta::Zero();
-  QuicTime::Delta max_time_before_crypto_handshake = QuicTime::Delta::Zero();
-  QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
-};
-
-// Factory that creates instances of QuartcSession.  Implements the
-// QuicConnectionHelperInterface used by the QuicConnections. Only one
-// QuartcFactory is expected to be created.
-class QUIC_EXPORT_PRIVATE QuartcFactory : public QuicConnectionHelperInterface {
+// Implements the QuartcFactoryInterface to create the instances of
+// QuartcSessionInterface. Implements the QuicAlarmFactory to create alarms
+// using the QuartcTaskRunner. Implements the QuicConnectionHelperInterface used
+// by the QuicConnections. Only one QuartcFactory is expected to be created.
+class QUIC_EXPORT_PRIVATE QuartcFactory : public QuartcFactoryInterface,
+                                          public QuicAlarmFactory,
+                                          public QuicConnectionHelperInterface {
  public:
   explicit QuartcFactory(const QuartcFactoryConfig& factory_config);
   ~QuartcFactory() override;
 
-  // Creates a new QuartcSession using the given configuration.
-  std::unique_ptr<QuartcSession> CreateQuartcSession(
-      const QuartcSessionConfig& quartc_session_config);
+  // QuartcFactoryInterface overrides.
+  std::unique_ptr<QuartcSessionInterface> CreateQuartcSession(
+      const QuartcSessionConfig& quartc_session_config) override;
+
+  // QuicAlarmFactory overrides.
+  QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override;
+
+  QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
+      QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
+      QuicConnectionArena* arena) override;
 
   // QuicConnectionHelperInterface overrides.
   const QuicClock* GetClock() const override;
@@ -98,19 +49,15 @@
       Perspective perspective,
       QuartcPacketWriter* packet_writer);
 
-  // Used to implement QuicAlarmFactory.  Owned by the user and must outlive
-  // QuartcFactory.
-  QuicAlarmFactory* alarm_factory_;
-  // Used to implement the QuicConnectionHelperInterface.  Owned by the user and
-  // must outlive QuartcFactory.
-  QuicClock* clock_;
+  // Used to implement QuicAlarmFactory..
+  QuartcTaskRunnerInterface* task_runner_;
+  // Used to implement the QuicConnectionHelperInterface.
+  // The QuicClock wrapper held in this variable is owned by QuartcFactory,
+  // but the QuartcClockInterface inside of it belongs to the user!
+  std::unique_ptr<QuicClock> clock_;
   SimpleBufferAllocator buffer_allocator_;
 };
 
-// Creates a new instance of QuartcFactory.
-std::unique_ptr<QuartcFactory> CreateQuartcFactory(
-    const QuartcFactoryConfig& factory_config);
-
 }  // namespace quic
 
 #endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_H_
diff --git a/net/third_party/quic/quartc/quartc_factory_interface.cc b/net/third_party/quic/quartc/quartc_factory_interface.cc
new file mode 100644
index 0000000..12897fa
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_factory_interface.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 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 "net/third_party/quic/quartc/quartc_factory_interface.h"
+
+namespace quic {
+
+QuartcFactoryInterface::QuartcSessionConfig::QuartcSessionConfig() = default;
+QuartcFactoryInterface::QuartcSessionConfig::~QuartcSessionConfig() = default;
+
+}  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_factory_interface.h b/net/third_party/quic/quartc/quartc_factory_interface.h
new file mode 100644
index 0000000..8013bc9
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_factory_interface.h
@@ -0,0 +1,108 @@
+// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_INTERFACE_H_
+#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_INTERFACE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/quartc/quartc_clock_interface.h"
+#include "net/third_party/quic/quartc/quartc_session_interface.h"
+#include "net/third_party/quic/quartc/quartc_task_runner_interface.h"
+
+namespace quic {
+
+// Algorithm to use for congestion control.
+enum class QuartcCongestionControl {
+  kDefault,  // Use an arbitrary algorithm chosen by QUIC.
+  kBBR,      // Use BBR.
+};
+
+// Options that control the BBR algorithm.
+enum class QuartcBbrOptions {
+  kSlowerStartup,    // Once a loss is encountered in STARTUP,
+                     // switches startup to a 1.5x pacing gain.
+  kFullyDrainQueue,  // Fully drains the queue once per cycle.
+  kReduceProbeRtt,   // Probe RTT reduces CWND to 0.75 * BDP instead of 4
+                     // packets.
+  kSkipProbeRtt,     // Skip Probe RTT and extend the existing min_rtt if a
+                     // recent min_rtt is within 12.5% of the current min_rtt.
+  kSkipProbeRttAggressively,  //  Skip ProbeRTT and extend the existing min_rtt
+                              //  as long as you've been app limited at least
+                              //  once.
+  kFillUpLinkDuringProbing,   // Sends probing retransmissions whenever we
+                              // become application limited.
+  kInitialWindow3,            // Use a 3-packet initial congestion window.
+  kInitialWindow10,           // Use a 10-packet initial congestion window.
+  kInitialWindow20,           // Use a 20-packet initial congestion window.
+  kInitialWindow50,           // Use a 50-packet initial congestion window.
+  kStartup1RTT,               // Stay in STARTUP for 1 RTT.
+  kStartup2RTT,               // Stay in STARTUP for 2 RTTs.
+};
+
+// Used to create instances for Quartc objects such as QuartcSession.
+class QUIC_EXPORT_PRIVATE QuartcFactoryInterface {
+ public:
+  virtual ~QuartcFactoryInterface() {}
+
+  struct QuartcSessionConfig {
+    QuartcSessionConfig();
+    ~QuartcSessionConfig();
+
+    // When using Quartc, there are two endpoints. The QuartcSession on one
+    // endpoint must act as a server and the one on the other side must act as a
+    // client.
+    bool is_server = false;
+    // This is only needed when is_server = false.  It must be unique
+    // for each endpoint the local endpoint may communicate with. For example,
+    // a WebRTC client could use the remote endpoint's crypto fingerprint
+    std::string unique_remote_server_id;
+    // The way the QuicConnection will send and receive packets, like a virtual
+    // UDP socket. For WebRTC, this will typically be an IceTransport.
+    QuartcPacketTransport* packet_transport = nullptr;
+    // The maximum size of the packet can be written with the packet writer.
+    // 1200 bytes by default.
+    uint64_t max_packet_size = 1200;
+    // Algorithm to use for congestion control.  By default, uses an arbitrary
+    // congestion control algorithm chosen by QUIC.
+    QuartcCongestionControl congestion_control =
+        QuartcCongestionControl::kDefault;
+    // Options to control the BBR algorithm. In case the congestion control is
+    // set to anything but BBR, these options are ignored.
+    std::vector<QuartcBbrOptions> bbr_options;
+    // Timeouts for the crypto handshake. Set them to higher values to
+    // prevent closing the session before it started on a slow network.
+    // Zero entries are ignored and QUIC defaults are used in that case.
+    uint32_t max_idle_time_before_crypto_handshake_secs = 0;
+    uint32_t max_time_before_crypto_handshake_secs = 0;
+    QuicTime::Delta idle_network_timeout = QuicTime::Delta::Zero();
+  };
+
+  virtual std::unique_ptr<QuartcSessionInterface> CreateQuartcSession(
+      const QuartcSessionConfig& quartc_config) = 0;
+};
+
+// The configuration for creating a QuartcFactory.
+struct QuartcFactoryConfig {
+  // The task runner used by the QuartcAlarm. Implemented by the Quartc user
+  // with different mechanism. For example in WebRTC, it is implemented with
+  // rtc::Thread. Owned by the user, and needs to stay alive for as long
+  // as the QuartcFactory exists.
+  QuartcTaskRunnerInterface* task_runner = nullptr;
+  // The clock used by QuartcAlarms. Implemented by the Quartc user. Owned by
+  // the user, and needs to stay alive for as long as the QuartcFactory exists.
+  QuartcClockInterface* clock = nullptr;
+};
+
+// Creates a new instance of QuartcFactoryInterface.
+std::unique_ptr<QuartcFactoryInterface> CreateQuartcFactory(
+    const QuartcFactoryConfig& factory_config);
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_FACTORY_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_packet_writer.h b/net/third_party/quic/quartc/quartc_packet_writer.h
index a4dca96..a1cabb7 100644
--- a/net/third_party/quic/quartc/quartc_packet_writer.h
+++ b/net/third_party/quic/quartc/quartc_packet_writer.h
@@ -5,31 +5,12 @@
 #ifndef NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
 #define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_PACKET_WRITER_H_
 
-#include "net/third_party/quic/core/quic_connection.h"
 #include "net/third_party/quic/core/quic_packet_writer.h"
-#include "net/third_party/quic/core/quic_types.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/quartc/quartc_session_interface.h"
 
 namespace quic {
 
-// Send and receive packets, like a virtual UDP socket. For example, this
-// could be implemented by WebRTC's IceTransport.
-class QUIC_EXPORT_PRIVATE QuartcPacketTransport {
- public:
-  // Additional metadata provided for each packet written.
-  struct PacketInfo {
-    QuicPacketNumber packet_number;
-  };
-
-  virtual ~QuartcPacketTransport() {}
-
-  // Called by the QuartcPacketWriter when writing packets to the network.
-  // Return the number of written bytes. Return 0 if the write is blocked.
-  virtual int Write(const char* buffer,
-                    size_t buf_len,
-                    const PacketInfo& info) = 0;
-};
-
 // Implements a QuicPacketWriter using a QuartcPacketTransport, which allows a
 // QuicConnection to use (for example), a WebRTC IceTransport.
 class QUIC_EXPORT_PRIVATE QuartcPacketWriter : public QuicPacketWriter {
@@ -39,7 +20,7 @@
   ~QuartcPacketWriter() override {}
 
   // The QuicConnection calls WritePacket and the QuicPacketWriter writes them
-  // to the QuartcSession::PacketTransport.
+  // to the QuartcSessionInterface::PacketTransport.
   WriteResult WritePacket(const char* buffer,
                           size_t buf_len,
                           const QuicIpAddress& self_address,
diff --git a/net/third_party/quic/quartc/quartc_session.cc b/net/third_party/quic/quartc/quartc_session.cc
index f61da4e..c8d48c2 100644
--- a/net/third_party/quic/quartc/quartc_session.cc
+++ b/net/third_party/quic/quartc/quartc_session.cc
@@ -8,6 +8,8 @@
 #include "net/third_party/quic/core/tls_server_handshaker.h"
 #include "net/third_party/quic/platform/api/quic_ptr_util.h"
 
+using std::string;
+
 namespace quic {
 
 namespace {
@@ -29,14 +31,14 @@
 
   // ProofSource override.
   void GetProof(const QuicSocketAddress& server_addr,
-                const QuicString& hostname,
-                const QuicString& server_config,
+                const string& hostname,
+                const string& server_config,
                 QuicTransportVersion transport_version,
                 QuicStringPiece chlo_hash,
                 std::unique_ptr<Callback> callback) override {
     QuicReferenceCountedPointer<ProofSource::Chain> chain;
     QuicCryptoProof proof;
-    std::vector<QuicString> certs;
+    std::vector<string> certs;
     certs.push_back("Dummy cert");
     chain = new ProofSource::Chain(certs);
     proof.signature = "Dummy signature";
@@ -46,13 +48,13 @@
 
   QuicReferenceCountedPointer<Chain> GetCertChain(
       const QuicSocketAddress& server_address,
-      const QuicString& hostname) override {
+      const string& hostname) override {
     return QuicReferenceCountedPointer<Chain>();
   }
 
   void ComputeTlsSignature(
       const QuicSocketAddress& server_address,
-      const QuicString& hostname,
+      const string& hostname,
       uint16_t signature_algorithm,
       QuicStringPiece in,
       std::unique_ptr<SignatureCallback> callback) override {
@@ -70,26 +72,26 @@
 
   // ProofVerifier override.
   QuicAsyncStatus VerifyProof(
-      const QuicString& hostname,
+      const string& hostname,
       const uint16_t port,
-      const QuicString& server_config,
+      const string& server_config,
       QuicTransportVersion transport_version,
       QuicStringPiece chlo_hash,
-      const std::vector<QuicString>& certs,
-      const QuicString& cert_sct,
-      const QuicString& signature,
+      const std::vector<string>& certs,
+      const string& cert_sct,
+      const string& signature,
       const ProofVerifyContext* context,
-      QuicString* error_details,
+      string* error_details,
       std::unique_ptr<ProofVerifyDetails>* verify_details,
       std::unique_ptr<ProofVerifierCallback> callback) override {
     return QUIC_SUCCESS;
   }
 
   QuicAsyncStatus VerifyCertChain(
-      const QuicString& hostname,
-      const std::vector<QuicString>& certs,
+      const string& hostname,
+      const std::vector<string>& certs,
       const ProofVerifyContext* context,
-      QuicString* error_details,
+      string* error_details,
       std::unique_ptr<ProofVerifyDetails>* details,
       std::unique_ptr<ProofVerifierCallback> callback) override {
     return QUIC_SUCCESS;
@@ -112,13 +114,65 @@
     const QuicSocketAddress& client_address,
     const QuicSocketAddress& peer_address,
     const QuicSocketAddress& self_address,
-    QuicString* error_details) const {
+    string* error_details) const {
   return true;
 }
 
+QuartcSessionVisitorAdapter::~QuartcSessionVisitorAdapter() {}
+
+QuartcSessionVisitorAdapter::QuartcSessionVisitorAdapter() {}
+
+void QuartcSessionVisitorAdapter::OnPacketSent(
+    const SerializedPacket& serialized_packet,
+    QuicPacketNumber original_packet_number,
+    TransmissionType transmission_type,
+    QuicTime sent_time) {
+  for (QuartcSessionVisitor* visitor : visitors_) {
+    visitor->OnPacketSent(serialized_packet, original_packet_number,
+                          transmission_type, sent_time);
+  }
+}
+
+void QuartcSessionVisitorAdapter::OnIncomingAck(
+    const QuicAckFrame& ack_frame,
+    QuicTime ack_receive_time,
+    QuicPacketNumber largest_observed,
+    bool rtt_updated,
+    QuicPacketNumber least_unacked_sent_packet) {
+  for (QuartcSessionVisitor* visitor : visitors_) {
+    visitor->OnIncomingAck(ack_frame, ack_receive_time, largest_observed,
+                           rtt_updated, least_unacked_sent_packet);
+  }
+}
+
+void QuartcSessionVisitorAdapter::OnPacketLoss(
+    QuicPacketNumber lost_packet_number,
+    TransmissionType transmission_type,
+    QuicTime detection_time) {
+  for (QuartcSessionVisitor* visitor : visitors_) {
+    visitor->OnPacketLoss(lost_packet_number, transmission_type,
+                          detection_time);
+  }
+}
+
+void QuartcSessionVisitorAdapter::OnWindowUpdateFrame(
+    const QuicWindowUpdateFrame& frame,
+    const QuicTime& receive_time) {
+  for (QuartcSessionVisitor* visitor : visitors_) {
+    visitor->OnWindowUpdateFrame(frame, receive_time);
+  }
+}
+
+void QuartcSessionVisitorAdapter::OnSuccessfulVersionNegotiation(
+    const ParsedQuicVersion& version) {
+  for (QuartcSessionVisitor* visitor : visitors_) {
+    visitor->OnSuccessfulVersionNegotiation(version);
+  }
+}
+
 QuartcSession::QuartcSession(std::unique_ptr<QuicConnection> connection,
                              const QuicConfig& config,
-                             const QuicString& unique_remote_server_id,
+                             const string& unique_remote_server_id,
                              Perspective perspective,
                              QuicConnectionHelperInterface* helper,
                              QuicClock* clock,
@@ -146,7 +200,7 @@
     helper_->GetRandomGenerator()->RandBytes(source_address_token_secret,
                                              kInputKeyingMaterialLength);
     quic_crypto_server_config_ = QuicMakeUnique<QuicCryptoServerConfig>(
-        QuicString(source_address_token_secret, kInputKeyingMaterialLength),
+        string(source_address_token_secret, kInputKeyingMaterialLength),
         helper_->GetRandomGenerator(), std::move(proof_source),
         TlsServerHandshaker::CreateSslCtx());
     // Provide server with serialized config string to prove ownership.
@@ -187,6 +241,15 @@
   }
 }
 
+void QuartcSession::CloseStream(QuicStreamId stream_id) {
+  if (IsClosedStream(stream_id)) {
+    // When CloseStream has been called recursively (via
+    // QuicStream::OnClose), the stream is already closed so return.
+    return;
+  }
+  QuicSession::CloseStream(stream_id);
+}
+
 void QuartcSession::CancelStream(QuicStreamId stream_id) {
   ResetStream(stream_id, QuicRstStreamErrorCode::QUIC_STREAM_CANCELLED);
 }
@@ -202,12 +265,21 @@
   }
 }
 
+bool QuartcSession::IsOpenStream(QuicStreamId stream_id) {
+  return QuicSession::IsOpenStream(stream_id);
+}
+
+QuicConnectionStats QuartcSession::GetStats() {
+  return connection_->GetStats();
+}
+
 void QuartcSession::OnConnectionClosed(QuicErrorCode error,
-                                       const QuicString& error_details,
+                                       const string& error_details,
                                        ConnectionCloseSource source) {
   QuicSession::OnConnectionClosed(error, error_details, source);
   DCHECK(session_delegate_);
-  session_delegate_->OnConnectionClosed(error, error_details, source);
+  session_delegate_->OnConnectionClosed(
+      error, source == ConnectionCloseSource::FROM_PEER);
 }
 
 void QuartcSession::SetPreSharedKey(QuicStringPiece key) {
@@ -241,13 +313,35 @@
   }
 }
 
-void QuartcSession::CloseConnection(const QuicString& details) {
+bool QuartcSession::ExportKeyingMaterial(const string& label,
+                                         const uint8_t* context,
+                                         size_t context_len,
+                                         bool used_context,
+                                         uint8_t* result,
+                                         size_t result_len) {
+  string quic_context(reinterpret_cast<const char*>(context), context_len);
+  string quic_result;
+  bool success = crypto_stream_->ExportKeyingMaterial(label, quic_context,
+                                                      result_len, &quic_result);
+  quic_result.copy(reinterpret_cast<char*>(result), result_len);
+  DCHECK(quic_result.length() == result_len);
+  return success;
+}
+
+void QuartcSession::CloseConnection(const string& details) {
   connection_->CloseConnection(
       QuicErrorCode::QUIC_CONNECTION_CANCELLED, details,
       ConnectionCloseBehavior::SEND_CONNECTION_CLOSE_PACKET_WITH_NO_ACK);
 }
 
-void QuartcSession::SetDelegate(Delegate* session_delegate) {
+QuartcStreamInterface* QuartcSession::CreateOutgoingStream(
+    const OutgoingStreamParameters& param) {
+  // The |param| is for forward-compatibility. Not used for now.
+  return CreateOutgoingDynamicStream();
+}
+
+void QuartcSession::SetDelegate(
+    QuartcSessionInterface::Delegate* session_delegate) {
   if (session_delegate_) {
     LOG(WARNING) << "The delegate for the session has already been set.";
   }
@@ -255,6 +349,25 @@
   DCHECK(session_delegate_);
 }
 
+void QuartcSession::AddSessionVisitor(QuartcSessionVisitor* visitor) {
+  // If there aren't any visitors yet, install the adapter as a connection debug
+  // visitor to delegate any future calls.
+  if (session_visitor_adapter_.visitors().empty()) {
+    connection_->set_debug_visitor(&session_visitor_adapter_);
+  }
+  session_visitor_adapter_.mutable_visitors().insert(visitor);
+  visitor->OnQuicConnection(connection_.get());
+}
+
+void QuartcSession::RemoveSessionVisitor(QuartcSessionVisitor* visitor) {
+  session_visitor_adapter_.mutable_visitors().erase(visitor);
+  // If the last visitor is removed, uninstall the connection debug visitor to
+  // avoid delegating debug calls unnecessarily.
+  if (session_visitor_adapter_.visitors().empty()) {
+    connection_->set_debug_visitor(nullptr);
+  }
+}
+
 void QuartcSession::OnTransportCanWrite() {
   connection()->writer()->SetWritable();
   if (HasDataToWrite()) {
@@ -263,12 +376,29 @@
 }
 
 bool QuartcSession::OnTransportReceived(const char* data, size_t data_len) {
+  // If the session is currently bundling packets, it must stop and flush writes
+  // before processing incoming data.  QUIC expects pending packets to be
+  // written before receiving data, because received data may change the
+  // contents of ACK frames in pending packets.
+  FlushWrites();
+
   QuicReceivedPacket packet(data, data_len, clock_->Now());
   ProcessUdpPacket(connection()->self_address(), connection()->peer_address(),
                    packet);
   return true;
 }
 
+void QuartcSession::BundleWrites() {
+  if (!packet_flusher_) {
+    packet_flusher_ = QuicMakeUnique<QuicConnection::ScopedPacketFlusher>(
+        connection_.get(), QuicConnection::SEND_ACK_IF_QUEUED);
+  }
+}
+
+void QuartcSession::FlushWrites() {
+  packet_flusher_ = nullptr;
+}
+
 void QuartcSession::OnProofValid(
     const QuicCryptoClientConfig::CachedState& cached) {
   // TODO(zhihuang): Handle the proof verification.
@@ -279,6 +409,16 @@
   // TODO(zhihuang): Handle the proof verification.
 }
 
+void QuartcSession::SetClientCryptoConfig(
+    QuicCryptoClientConfig* client_config) {
+  quic_crypto_client_config_.reset(client_config);
+}
+
+void QuartcSession::SetServerCryptoConfig(
+    QuicCryptoServerConfig* server_config) {
+  quic_crypto_server_config_.reset(server_config);
+}
+
 QuicStream* QuartcSession::CreateIncomingDynamicStream(QuicStreamId id) {
   return ActivateDataStream(CreateDataStream(id, QuicStream::kDefaultPriority));
 }
diff --git a/net/third_party/quic/quartc/quartc_session.h b/net/third_party/quic/quartc/quartc_session.h
index 82a43338..ac1eb24c 100644
--- a/net/third_party/quic/quartc/quartc_session.h
+++ b/net/third_party/quic/quartc/quartc_session.h
@@ -11,7 +11,9 @@
 #include "net/third_party/quic/core/quic_error_codes.h"
 #include "net/third_party/quic/core/quic_session.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/quartc/quartc_clock_interface.h"
 #include "net/third_party/quic/quartc/quartc_packet_writer.h"
+#include "net/third_party/quic/quartc/quartc_session_interface.h"
 #include "net/third_party/quic/quartc/quartc_stream.h"
 
 namespace quic {
@@ -26,23 +28,58 @@
                             const QuicSocketAddress& client_address,
                             const QuicSocketAddress& peer_address,
                             const QuicSocketAddress& self_address,
-                            QuicString* error_details) const override;
+                            std::string* error_details) const override;
 };
 
-// QuartcSession owns and manages a QUIC connection.
+// Adapts |QuartcSessionVisitor|s to the |QuicConnectionDebugVisitor| interface.
+// Keeps a set of |QuartcSessionVisitor|s and forwards QUIC debug callbacks to
+// each visitor in the set.
+class QuartcSessionVisitorAdapter : public QuicConnectionDebugVisitor {
+ public:
+  QuartcSessionVisitorAdapter();
+  ~QuartcSessionVisitorAdapter() override;
+
+  void OnPacketSent(const SerializedPacket& serialized_packet,
+                    QuicPacketNumber original_packet_number,
+                    TransmissionType transmission_type,
+                    QuicTime sent_time) override;
+  void OnIncomingAck(const QuicAckFrame& ack_frame,
+                     QuicTime ack_receive_time,
+                     QuicPacketNumber largest_observed,
+                     bool rtt_updated,
+                     QuicPacketNumber least_unacked_sent_packet) override;
+  void OnPacketLoss(QuicPacketNumber lost_packet_number,
+                    TransmissionType transmission_type,
+                    QuicTime detection_time) override;
+  void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
+                           const QuicTime& receive_time) override;
+  void OnSuccessfulVersionNegotiation(
+      const ParsedQuicVersion& version) override;
+
+  const std::set<QuartcSessionVisitor*>& visitors() const { return visitors_; }
+  std::set<QuartcSessionVisitor*>& mutable_visitors() { return visitors_; }
+
+  // Disallow copy and assign.
+  QuartcSessionVisitorAdapter(const QuartcSessionVisitorAdapter&) = delete;
+  QuartcSessionVisitorAdapter operator=(const QuartcSessionVisitorAdapter&) =
+      delete;
+
+ private:
+  std::set<QuartcSessionVisitor*> visitors_;
+};
+
 class QUIC_EXPORT_PRIVATE QuartcSession
     : public QuicSession,
+      public QuartcSessionInterface,
       public QuicCryptoClientStream::ProofHandler {
  public:
   QuartcSession(std::unique_ptr<QuicConnection> connection,
                 const QuicConfig& config,
-                const QuicString& unique_remote_server_id,
+                const std::string& unique_remote_server_id,
                 Perspective perspective,
                 QuicConnectionHelperInterface* helper,
                 QuicClock* clock,
                 std::unique_ptr<QuartcPacketWriter> packet_writer);
-  QuartcSession(const QuartcSession&) = delete;
-  QuartcSession& operator=(const QuartcSession&) = delete;
   ~QuartcSession() override;
 
   // QuicSession overrides.
@@ -54,67 +91,48 @@
 
   void OnCryptoHandshakeEvent(CryptoHandshakeEvent event) override;
 
+  void CloseStream(QuicStreamId stream_id) override;
+
   // QuicConnectionVisitorInterface overrides.
   void OnConnectionClosed(QuicErrorCode error,
-                          const QuicString& error_details,
+                          const std::string& error_details,
                           ConnectionCloseSource source) override;
 
-  // QuartcSession methods.
+  // QuartcSessionInterface overrides
+  void SetPreSharedKey(QuicStringPiece key) override;
 
-  // Sets a pre-shared key for use during the crypto handshake.  Must be set
-  // before StartCryptoHandshake() is called.
-  void SetPreSharedKey(QuicStringPiece key);
+  void StartCryptoHandshake() override;
 
-  void StartCryptoHandshake();
+  bool ExportKeyingMaterial(const std::string& label,
+                            const uint8_t* context,
+                            size_t context_len,
+                            bool used_context,
+                            uint8_t* result,
+                            size_t result_len) override;
 
-  // Closes the connection with the given human-readable error details.
-  // The connection closes with the QUIC_CONNECTION_CANCELLED error code to
-  // indicate the application closed it.
-  //
-  // Informs the peer that the connection has been closed.  This prevents the
-  // peer from waiting until the connection times out.
-  //
-  // Cleans up the underlying QuicConnection's state.  Closing the connection
-  // makes it safe to delete the QuartcSession.
-  void CloseConnection(const QuicString& details);
+  void CloseConnection(const std::string& details) override;
 
-  // If the given stream is still open, sends a reset frame to cancel it.
-  // Note:  This method cancels a stream by QuicStreamId rather than by pointer
-  // (or by a method on QuartcStream) because QuartcSession (and not
-  // the caller) owns the streams.  Streams may finish and be deleted before the
-  // caller tries to cancel them, rendering the caller's pointers invalid.
-  void CancelStream(QuicStreamId stream_id);
+  QuartcStreamInterface* CreateOutgoingStream(
+      const OutgoingStreamParameters& param) override;
 
-  // Callbacks called by the QuartcSession to notify the user of the
-  // QuartcSession of certain events.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
+  void CancelStream(QuicStreamId stream_id) override;
 
-    // Called when the crypto handshake is complete.
-    virtual void OnCryptoHandshakeComplete() = 0;
+  bool IsOpenStream(QuicStreamId stream_id) override;
 
-    // Called when a new stream is received from the remote endpoint.
-    virtual void OnIncomingStream(QuartcStream* stream) = 0;
+  QuicConnectionStats GetStats() override;
 
-    // Called when the connection is closed. This means all of the streams will
-    // be closed and no new streams can be created.
-    virtual void OnConnectionClosed(QuicErrorCode error_code,
-                                    const QuicString& error_details,
-                                    ConnectionCloseSource source) = 0;
+  void SetDelegate(QuartcSessionInterface::Delegate* session_delegate) override;
 
-    // TODO(zhihuang): Add proof verification.
-  };
+  void AddSessionVisitor(QuartcSessionVisitor* visitor) override;
+  void RemoveSessionVisitor(QuartcSessionVisitor* visitor) override;
 
-  // The |delegate| is not owned by QuartcSession.
-  void SetDelegate(Delegate* session_delegate);
+  void OnTransportCanWrite() override;
 
-  // Called when CanWrite() changes from false to true.
-  void OnTransportCanWrite();
+  // Decrypts an incoming QUIC packet to a data stream.
+  bool OnTransportReceived(const char* data, size_t data_len) override;
 
-  // Called when a packet has been received and should be handled by the
-  // QuicConnection.
-  bool OnTransportReceived(const char* data, size_t data_len);
+  void BundleWrites() override;
+  void FlushWrites() override;
 
   // ProofHandler overrides.
   void OnProofValid(const QuicCryptoClientConfig::CachedState& cached) override;
@@ -125,6 +143,12 @@
   void OnProofVerifyDetailsAvailable(
       const ProofVerifyDetails& verify_details) override;
 
+  // Override the default crypto configuration.
+  // The session will take the ownership of the configurations.
+  void SetClientCryptoConfig(QuicCryptoClientConfig* client_config);
+
+  void SetServerCryptoConfig(QuicCryptoServerConfig* server_config);
+
  protected:
   // QuicSession override.
   QuicStream* CreateIncomingDynamicStream(QuicStreamId id) override;
@@ -140,7 +164,7 @@
  private:
   // For crypto handshake.
   std::unique_ptr<QuicCryptoStream> crypto_stream_;
-  const QuicString unique_remote_server_id_;
+  const std::string unique_remote_server_id_;
   Perspective perspective_;
 
   // Packet writer used by |connection_|.
@@ -155,7 +179,7 @@
   // For recording packet receipt time
   QuicClock* clock_;
   // Not owned by QuartcSession.
-  Delegate* session_delegate_ = nullptr;
+  QuartcSessionInterface::Delegate* session_delegate_ = nullptr;
   // Used by QUIC crypto server stream to track most recently compressed certs.
   std::unique_ptr<QuicCompressedCertsCache> quic_compressed_certs_cache_;
   // This helper is needed when create QuicCryptoServerStream.
@@ -164,6 +188,14 @@
   std::unique_ptr<QuicCryptoClientConfig> quic_crypto_client_config_;
   // Config for QUIC crypto server stream, used by the server.
   std::unique_ptr<QuicCryptoServerConfig> quic_crypto_server_config_;
+
+  // Holds pointers to QuartcSessionVisitors and adapts them to the
+  // QuicConnectionDebugVisitor interface.
+  QuartcSessionVisitorAdapter session_visitor_adapter_;
+
+  std::unique_ptr<QuicConnection::ScopedPacketFlusher> packet_flusher_;
+
+  DISALLOW_COPY_AND_ASSIGN(QuartcSession);
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_session_interface.h b/net/third_party/quic/quartc/quartc_session_interface.h
new file mode 100644
index 0000000..2db5f35
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_session_interface.h
@@ -0,0 +1,155 @@
+// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_INTERFACE_H_
+#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_INTERFACE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string>
+
+#include "net/third_party/quic/core/quic_bandwidth.h"
+#include "net/third_party/quic/core/quic_error_codes.h"
+#include "net/third_party/quic/core/quic_time.h"
+#include "net/third_party/quic/core/quic_types.h"
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/quartc/quartc_session_visitor_interface.h"
+#include "net/third_party/quic/quartc/quartc_stream_interface.h"
+
+namespace quic {
+
+// Send and receive packets, like a virtual UDP socket. For example, this
+// could be implemented by WebRTC's IceTransport.
+class QUIC_EXPORT_PRIVATE QuartcPacketTransport {
+ public:
+  // Additional metadata provided for each packet written.
+  struct PacketInfo {
+    QuicPacketNumber packet_number;
+  };
+
+  virtual ~QuartcPacketTransport() {}
+
+  // Called by the QuartcPacketWriter when writing packets to the network.
+  // Return the number of written bytes. Return 0 if the write is blocked.
+  virtual int Write(const char* buffer,
+                    size_t buf_len,
+                    const PacketInfo& info) = 0;
+};
+
+// Given a PacketTransport, provides a way to send and receive separate streams
+// of reliable, in-order, encrypted data. For example, this can build on top of
+// a WebRTC IceTransport for sending and receiving data over QUIC.
+class QUIC_EXPORT_PRIVATE QuartcSessionInterface {
+ public:
+  virtual ~QuartcSessionInterface() {}
+
+  // Sets a pre-shared key for use during the crypto handshake.  Must be set
+  // before StartCryptoHandshake() is called.
+  virtual void SetPreSharedKey(QuicStringPiece key) = 0;
+
+  virtual void StartCryptoHandshake() = 0;
+
+  // Only needed when using SRTP with QuicTransport
+  // Key Exporter interface from RFC 5705
+  // Arguments are:
+  // label               -- the exporter label.
+  //                        part of the RFC defining each exporter usage (IN)
+  // context/context_len -- a context to bind to for this connection;
+  //                        optional, can be NULL, 0 (IN)
+  // use_context         -- whether to use the context value
+  //                        (needed to distinguish no context from
+  //                        zero-length ones).
+  // result              -- where to put the computed value
+  // result_len          -- the length of the computed value
+  virtual bool ExportKeyingMaterial(const std::string& label,
+                                    const uint8_t* context,
+                                    size_t context_len,
+                                    bool used_context,
+                                    uint8_t* result,
+                                    size_t result_len) = 0;
+
+  // Closes the connection with the given human-readable error details.
+  // The connection closes with the QUIC_CONNECTION_CANCELLED error code to
+  // indicate the application closed it.
+  //
+  // Informs the peer that the connection has been closed.  This prevents the
+  // peer from waiting until the connection times out.
+  //
+  // Cleans up the underlying QuicConnection's state.  Closing the connection
+  // makes it safe to delete the QuartcSession.
+  virtual void CloseConnection(const std::string& error_details) = 0;
+
+  // For forward-compatibility. More parameters could be added through the
+  // struct without changing the API.
+  struct OutgoingStreamParameters {};
+
+  virtual QuartcStreamInterface* CreateOutgoingStream(
+      const OutgoingStreamParameters& params) = 0;
+
+  // If the given stream is still open, sends a reset frame to cancel it.
+  // Note:  This method cancels a stream by QuicStreamId rather than by pointer
+  // (or by a method on QuartcStreamInterface) because QuartcSession (and not
+  // the caller) owns the streams.  Streams may finish and be deleted before the
+  // caller tries to cancel them, rendering the caller's pointers invalid.
+  virtual void CancelStream(QuicStreamId stream_id) = 0;
+
+  // This method verifies if a stream is still open and stream pointer can be
+  // used. When true is returned, the interface pointer is good for making a
+  // call immediately on the same thread, but may be rendered invalid by ANY
+  // other QUIC activity.
+  virtual bool IsOpenStream(QuicStreamId stream_id) = 0;
+
+  // Gets stats associated with the current QUIC connection.
+  virtual QuicConnectionStats GetStats() = 0;
+
+  // Called when CanWrite() changes from false to true.
+  virtual void OnTransportCanWrite() = 0;
+
+  // Called when a packet has been received and should be handled by the
+  // QuicConnection.
+  virtual bool OnTransportReceived(const char* data, size_t data_len) = 0;
+
+  // Bundles subsequent writes on a best-effort basis.
+  // Data is sent whenever enough data is accumulated to fill a packet.
+  // The session stops bundling writes and sends data immediately as soon as
+  // FlushWrites() is called or a packet is received.
+  virtual void BundleWrites() = 0;
+
+  // Stop bundling writes and flush any pending writes immediately.
+  virtual void FlushWrites() = 0;
+
+  // Callbacks called by the QuartcSession to notify the user of the
+  // QuartcSession of certain events.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Called when the crypto handshake is complete.
+    virtual void OnCryptoHandshakeComplete() = 0;
+
+    // Called when a new stream is received from the remote endpoint.
+    virtual void OnIncomingStream(QuartcStreamInterface* stream) = 0;
+
+    // Called when the connection is closed. This means all of the streams will
+    // be closed and no new streams can be created.
+    // TODO(zhihuang): Create mapping from integer error code to WebRTC error
+    // code.
+    virtual void OnConnectionClosed(int error_code, bool from_remote) = 0;
+
+    // TODO(zhihuang): Add proof verification.
+  };
+
+  // The |delegate| is not owned by QuartcSession.
+  virtual void SetDelegate(Delegate* delegate) = 0;
+
+  // Add or remove session visitors.  Session visitors observe internals of the
+  // Quartc/QUIC session for the purpose of gathering metrics or debug
+  // information.
+  virtual void AddSessionVisitor(QuartcSessionVisitor* visitor) = 0;
+  virtual void RemoveSessionVisitor(QuartcSessionVisitor* visitor) = 0;
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_session_test.cc b/net/third_party/quic/quartc/quartc_session_test.cc
index 3aa46a5..aedd3675 100644
--- a/net/third_party/quic/quartc/quartc_session_test.cc
+++ b/net/third_party/quic/quartc/quartc_session_test.cc
@@ -13,97 +13,229 @@
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/platform/api/quic_test_mem_slice_vector.h"
 #include "net/third_party/quic/quartc/quartc_factory.h"
+#include "net/third_party/quic/quartc/quartc_factory_interface.h"
 #include "net/third_party/quic/quartc/quartc_packet_writer.h"
+#include "net/third_party/quic/quartc/quartc_stream_interface.h"
 #include "net/third_party/quic/test_tools/mock_clock.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using std::string;
+
 namespace quic {
 
 namespace {
 
+static const char kExporterLabel[] = "label";
+static const uint8_t kExporterContext[] = "context";
+static const size_t kExporterContextLen = sizeof(kExporterContext);
+static const size_t kOutputKeyLength = 20;
+static QuartcStreamInterface::WriteParameters kDefaultWriteParam;
+static QuartcSessionInterface::OutgoingStreamParameters kDefaultStreamParam;
 static QuicByteCount kDefaultMaxPacketSize = 1200;
 
-// Single-threaded alarm implementation based on a MockClock.
+// Single-threaded scheduled task runner based on a MockClock.
 //
-// Simulates asynchronous execution on a single thread by holding alarms
-// until Run() is called. Performs no synchronization, assumes that
-// CreateAlarm(), Set(), Cancel(), and Run() are called on the same thread.
-class FakeAlarmFactory : public QuicAlarmFactory {
+// Simulates asynchronous execution on a single thread by holding scheduled
+// tasks until Run() is called. Performs no synchronization, assumes that
+// Schedule() and Run() are called on the same thread.
+class FakeTaskRunner : public QuartcTaskRunnerInterface {
  public:
-  class FakeAlarm : public QuicAlarm {
-   public:
-    FakeAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
-              FakeAlarmFactory* parent)
-        : QuicAlarm(std::move(delegate)), parent_(parent) {}
+  explicit FakeTaskRunner(MockClock* clock)
+      : tasks_([this](const TaskType& l, const TaskType& r) {
+          // Items at a later time should run after items at an earlier time.
+          // Priority queue comparisons should return true if l appears after r.
+          return l->time() > r->time();
+        }),
+        clock_(clock) {}
 
-    ~FakeAlarm() override { parent_->RemoveAlarm(this); }
+  ~FakeTaskRunner() override {}
 
-    void SetImpl() override { parent_->AddAlarm(this); }
-
-    void CancelImpl() override { parent_->RemoveAlarm(this); }
-
-    void Run() { Fire(); }
-
-   private:
-    FakeAlarmFactory* parent_;
-  };
-
-  explicit FakeAlarmFactory(MockClock* clock) : clock_(clock) {}
-  FakeAlarmFactory(const FakeAlarmFactory&) = delete;
-  FakeAlarmFactory& operator=(const FakeAlarmFactory&) = delete;
-
-  QuicAlarm* CreateAlarm(QuicAlarm::Delegate* delegate) override {
-    return new FakeAlarm(QuicArenaScopedPtr<QuicAlarm::Delegate>(delegate),
-                         this);
-  }
-
-  QuicArenaScopedPtr<QuicAlarm> CreateAlarm(
-      QuicArenaScopedPtr<QuicAlarm::Delegate> delegate,
-      QuicConnectionArena* arena) override {
-    return arena->New<FakeAlarm>(std::move(delegate), this);
-  }
-
-  // Runs all alarms scheduled in the next total_ms milliseconds.  Advances the
+  // Runs all tasks scheduled in the next total_ms milliseconds.  Advances the
   // clock by total_ms.  Runs tasks in time order.  Executes tasks scheduled at
   // the same in an arbitrary order.
   void Run(uint32_t total_ms) {
     for (uint32_t i = 0; i < total_ms; ++i) {
-      while (!alarms_.empty() && alarms_.top()->deadline() <= clock_->Now()) {
-        alarms_.top()->Run();
-        alarms_.pop();
+      while (!tasks_.empty() && tasks_.top()->time() <= clock_->Now()) {
+        tasks_.top()->Run();
+        tasks_.pop();
       }
       clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(1));
     }
   }
 
  private:
-  void RemoveAlarm(FakeAlarm* alarm) {
-    std::vector<FakeAlarm*> leftovers;
-    while (!alarms_.empty()) {
-      FakeAlarm* top = alarms_.top();
-      alarms_.pop();
-      if (top == alarm) {
-        break;
+  class InnerTask {
+   public:
+    InnerTask(std::function<void()> task, QuicTime time)
+        : task_(std::move(task)), time_(time) {}
+
+    void Cancel() { cancelled_ = true; }
+
+    void Run() {
+      if (!cancelled_) {
+        task_();
       }
-      leftovers.push_back(top);
     }
-    for (FakeAlarm* leftover : leftovers) {
-      alarms_.push(leftover);
-    }
+
+    QuicTime time() const { return time_; }
+
+   private:
+    bool cancelled_ = false;
+    std::function<void()> task_;
+    QuicTime time_;
+  };
+
+ public:
+  // Hook for cancelling a scheduled task.
+  class ScheduledTask : public QuartcTaskRunnerInterface::ScheduledTask {
+   public:
+    explicit ScheduledTask(std::shared_ptr<InnerTask> inner)
+        : inner_(std::move(inner)) {}
+
+    // Cancel if the caller deletes the ScheduledTask.  This behavior is
+    // consistent with the actual task runner Quartc uses.
+    ~ScheduledTask() override { Cancel(); }
+
+    // ScheduledTask implementation.
+    void Cancel() override { inner_->Cancel(); }
+
+   private:
+    std::shared_ptr<InnerTask> inner_;
+  };
+
+  // See QuartcTaskRunnerInterface.
+  std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask> Schedule(
+      Task* task,
+      uint64_t delay_ms) override {
+    auto inner = std::shared_ptr<InnerTask>(new InnerTask(
+        [task] { task->Run(); },
+        clock_->Now() + QuicTime::Delta::FromMilliseconds(delay_ms)));
+    tasks_.push(inner);
+    return std::unique_ptr<QuartcTaskRunnerInterface::ScheduledTask>(
+        new ScheduledTask(inner));
   }
 
-  void AddAlarm(FakeAlarm* alarm) { alarms_.push(alarm); }
+  // Schedules a function to run immediately.
+  void Schedule(std::function<void()> task) {
+    tasks_.push(std::shared_ptr<InnerTask>(
+        new InnerTask(std::move(task), clock_->Now())));
+  }
 
+ private:
+  // InnerTasks are shared by the queue and ScheduledTask (which hooks into it
+  // to implement Cancel()).
+  using TaskType = std::shared_ptr<InnerTask>;
+  std::priority_queue<TaskType,
+                      std::vector<TaskType>,
+                      std::function<bool(const TaskType&, const TaskType&)>>
+      tasks_;
   MockClock* clock_;
+};
 
-  using AlarmCompare = std::function<bool(const FakeAlarm*, const FakeAlarm*)>;
-  const AlarmCompare alarm_later_ = [](const FakeAlarm* l, const FakeAlarm* r) {
-    // Sort alarms so that the earliest deadline appears first.
-    return l->deadline() > r->deadline();
-  };
-  std::priority_queue<FakeAlarm*, std::vector<FakeAlarm*>, AlarmCompare>
-      alarms_{alarm_later_};
+// QuartcClock that wraps a MockClock.
+//
+// This is silly because Quartc wraps it as a QuicClock, and MockClock is
+// already a QuicClock.  But we don't have much choice.  We need to pass a
+// QuartcClockInterface into the Quartc wrappers.
+class MockQuartcClock : public QuartcClockInterface {
+ public:
+  explicit MockQuartcClock(MockClock* clock) : clock_(clock) {}
+
+  int64_t NowMicroseconds() override {
+    return clock_->WallNow().ToUNIXMicroseconds();
+  }
+
+ private:
+  MockClock* clock_;
+};
+
+// Used by QuicCryptoServerConfig to provide server credentials, returning a
+// canned response equal to |success|.
+class FakeProofSource : public ProofSource {
+ public:
+  explicit FakeProofSource(bool success) : success_(success) {}
+
+  // ProofSource override.
+  void GetProof(const QuicSocketAddress& server_ip,
+                const string& hostname,
+                const string& server_config,
+                QuicTransportVersion transport_version,
+                QuicStringPiece chlo_hash,
+                std::unique_ptr<Callback> callback) override {
+    QuicReferenceCountedPointer<ProofSource::Chain> chain;
+    QuicCryptoProof proof;
+    if (success_) {
+      std::vector<string> certs;
+      certs.push_back("Required to establish handshake");
+      chain = new ProofSource::Chain(certs);
+      proof.signature = "Signature";
+      proof.leaf_cert_scts = "Time";
+    }
+    callback->Run(success_, chain, proof, nullptr /* details */);
+  }
+
+  QuicReferenceCountedPointer<Chain> GetCertChain(
+      const QuicSocketAddress& server_address,
+      const string& hostname) override {
+    return QuicReferenceCountedPointer<Chain>();
+  }
+
+  void ComputeTlsSignature(
+      const QuicSocketAddress& server_address,
+      const string& hostname,
+      uint16_t signature_algorithm,
+      QuicStringPiece in,
+      std::unique_ptr<SignatureCallback> callback) override {
+    callback->Run(true, "Signature");
+  }
+
+ private:
+  // Whether or not obtaining proof source succeeds.
+  bool success_;
+};
+
+// Used by QuicCryptoClientConfig to verify server credentials, returning a
+// canned response of QUIC_SUCCESS if |success| is true.
+class FakeProofVerifier : public ProofVerifier {
+ public:
+  explicit FakeProofVerifier(bool success) : success_(success) {}
+
+  // ProofVerifier override
+  QuicAsyncStatus VerifyProof(
+      const string& hostname,
+      const uint16_t port,
+      const string& server_config,
+      QuicTransportVersion transport_version,
+      QuicStringPiece chlo_hash,
+      const std::vector<string>& certs,
+      const string& cert_sct,
+      const string& signature,
+      const ProofVerifyContext* context,
+      string* error_details,
+      std::unique_ptr<ProofVerifyDetails>* verify_details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    return success_ ? QUIC_SUCCESS : QUIC_FAILURE;
+  }
+
+  QuicAsyncStatus VerifyCertChain(
+      const string& hostname,
+      const std::vector<string>& certs,
+      const ProofVerifyContext* context,
+      string* error_details,
+      std::unique_ptr<ProofVerifyDetails>* details,
+      std::unique_ptr<ProofVerifierCallback> callback) override {
+    LOG(INFO) << "VerifyProof() ignoring credentials and returning success";
+    return success_ ? QUIC_SUCCESS : QUIC_FAILURE;
+  }
+
+  std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override {
+    return nullptr;
+  }
+
+ private:
+  // Whether or not proof verification succeeds.
+  bool success_;
 };
 
 // Used by the FakeTransportChannel.
@@ -112,17 +244,15 @@
   virtual ~FakeTransportChannelObserver() {}
 
   // Called when the other peer is trying to send message.
-  virtual void OnTransportChannelReadPacket(const QuicString& data) = 0;
+  virtual void OnTransportChannelReadPacket(const string& data) = 0;
 };
 
 // Simulate the P2P communication transport. Used by the
-// QuartcSession::Transport.
-class FakeTransportChannel : QuicAlarm::Delegate {
+// QuartcSessionInterface::Transport.
+class FakeTransportChannel {
  public:
-  explicit FakeTransportChannel(QuicAlarmFactory* alarm_factory,
-                                MockClock* clock)
-      : alarm_(alarm_factory->CreateAlarm(new AlarmDelegate(this))),
-        clock_(clock) {}
+  explicit FakeTransportChannel(FakeTaskRunner* task_runner, MockClock* clock)
+      : task_runner_(task_runner), clock_(clock) {}
 
   void SetDestination(FakeTransportChannel* dest) {
     if (!dest_) {
@@ -138,16 +268,21 @@
     }
     // Advance the time 10us to ensure the RTT is never 0ms.
     clock_->AdvanceTime(QuicTime::Delta::FromMicroseconds(10));
-    if (async_) {
-      packet_queue_.emplace_back(data, len);
-      alarm_->Cancel();
-      alarm_->Set(clock_->Now());
+    if (async_ && task_runner_) {
+      string packet(data, len);
+      task_runner_->Schedule([this, packet] { send(packet); });
     } else {
-      Send(QuicString(data, len));
+      send(string(data, len));
     }
     return static_cast<int>(len);
   }
 
+  void send(const string& data) {
+    DCHECK(dest_);
+    DCHECK(dest_->observer());
+    dest_->observer()->OnTransportChannelReadPacket(data);
+  }
+
   FakeTransportChannelObserver* observer() { return observer_; }
 
   void SetObserver(FakeTransportChannelObserver* observer) {
@@ -157,43 +292,14 @@
   void SetAsync(bool async) { async_ = async; }
 
  private:
-  class AlarmDelegate : public QuicAlarm::Delegate {
-   public:
-    explicit AlarmDelegate(FakeTransportChannel* channel) : channel_(channel) {}
-
-    void OnAlarm() override { channel_->OnAlarm(); }
-
-   private:
-    FakeTransportChannel* channel_;
-  };
-
-  void Send(const QuicString& data) {
-    DCHECK(dest_);
-    DCHECK(dest_->observer());
-    dest_->observer()->OnTransportChannelReadPacket(data);
-  }
-
-  void OnAlarm() override {
-    QUIC_LOG(WARNING) << "Sending packet: " << packet_queue_.front();
-    Send(packet_queue_.front());
-    packet_queue_.pop_front();
-
-    if (!packet_queue_.empty()) {
-      alarm_->Cancel();
-      alarm_->Set(clock_->Now());
-    }
-  }
-
   // The writing destination of this channel.
   FakeTransportChannel* dest_ = nullptr;
   // The observer of this channel. Called when the received the data.
   FakeTransportChannelObserver* observer_ = nullptr;
   // If async, will send packets by running asynchronous tasks.
   bool async_ = false;
-  // If async, packets are queued here to send.
-  QuicDeque<QuicString> packet_queue_;
-  // Alarm used to send data asynchronously.
-  QuicArenaScopedPtr<QuicAlarm> alarm_;
+  // Used to send data asynchronously.
+  FakeTaskRunner* task_runner_;
   // The test clock.  Used to ensure the RTT is not 0.
   MockClock* clock_;
 };
@@ -225,52 +331,51 @@
   QuicPacketCount packets_to_lose_ = 0;
 };
 
-class FakeQuartcSessionDelegate : public QuartcSession::Delegate {
+class FakeQuartcSessionDelegate : public QuartcSessionInterface::Delegate {
  public:
-  explicit FakeQuartcSessionDelegate(QuartcStream::Delegate* stream_delegate)
+  explicit FakeQuartcSessionDelegate(
+      QuartcStreamInterface::Delegate* stream_delegate)
       : stream_delegate_(stream_delegate) {}
   // Called when peers have established forward-secure encryption
   void OnCryptoHandshakeComplete() override {
     LOG(INFO) << "Crypto handshake complete!";
   }
   // Called when connection closes locally, or remotely by peer.
-  void OnConnectionClosed(QuicErrorCode error_code,
-                          const QuicString& error_details,
-                          ConnectionCloseSource source) override {
+  void OnConnectionClosed(int error_code, bool from_remote) override {
     connected_ = false;
   }
   // Called when an incoming QUIC stream is created.
-  void OnIncomingStream(QuartcStream* quartc_stream) override {
+  void OnIncomingStream(QuartcStreamInterface* quartc_stream) override {
     last_incoming_stream_ = quartc_stream;
     last_incoming_stream_->SetDelegate(stream_delegate_);
   }
 
-  QuartcStream* incoming_stream() { return last_incoming_stream_; }
+  QuartcStreamInterface* incoming_stream() { return last_incoming_stream_; }
 
   bool connected() { return connected_; }
 
  private:
-  QuartcStream* last_incoming_stream_;
+  QuartcStreamInterface* last_incoming_stream_;
   bool connected_ = true;
   QuartcStream::Delegate* stream_delegate_;
 };
 
-class FakeQuartcStreamDelegate : public QuartcStream::Delegate {
+class FakeQuartcStreamDelegate : public QuartcStreamInterface::Delegate {
  public:
-  void OnReceived(QuartcStream* stream,
+  void OnReceived(QuartcStreamInterface* stream,
                   const char* data,
                   size_t size) override {
-    received_data_[stream->id()] += QuicString(data, size);
+    received_data_[stream->stream_id()] += string(data, size);
   }
 
-  void OnClose(QuartcStream* stream) override {}
+  void OnClose(QuartcStreamInterface* stream) override {}
 
-  void OnBufferChanged(QuartcStream* stream) override {}
+  void OnBufferChanged(QuartcStreamInterface* stream) override {}
 
-  std::map<QuicStreamId, QuicString> data() { return received_data_; }
+  std::map<QuicStreamId, string> data() { return received_data_; }
 
  private:
-  std::map<QuicStreamId, QuicString> received_data_;
+  std::map<QuicStreamId, string> received_data_;
 };
 
 class QuartcSessionForTest : public QuartcSession,
@@ -278,7 +383,7 @@
  public:
   QuartcSessionForTest(std::unique_ptr<QuicConnection> connection,
                        const QuicConfig& config,
-                       const QuicString& remote_fingerprint_value,
+                       const string& remote_fingerprint_value,
                        Perspective perspective,
                        QuicConnectionHelperInterface* helper,
                        QuicClock* clock,
@@ -298,11 +403,11 @@
   }
 
   // QuartcPacketWriter override.
-  void OnTransportChannelReadPacket(const QuicString& data) override {
+  void OnTransportChannelReadPacket(const string& data) override {
     OnTransportReceived(data.c_str(), data.length());
   }
 
-  std::map<QuicStreamId, QuicString> data() { return stream_delegate_->data(); }
+  std::map<QuicStreamId, string> data() { return stream_delegate_->data(); }
 
   bool has_data() { return !data().empty(); }
 
@@ -326,9 +431,9 @@
     // Quic crashes if packets are sent at time 0, and the clock defaults to 0.
     clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1000));
     client_channel_ =
-        QuicMakeUnique<FakeTransportChannel>(&alarm_factory_, &clock_);
+        QuicMakeUnique<FakeTransportChannel>(&task_runner_, &clock_);
     server_channel_ =
-        QuicMakeUnique<FakeTransportChannel>(&alarm_factory_, &clock_);
+        QuicMakeUnique<FakeTransportChannel>(&task_runner_, &clock_);
     // Make the channel asynchronous so that two peer will not keep calling each
     // other when they exchange information.
     client_channel_->SetAsync(true);
@@ -348,7 +453,8 @@
 
   // The parameters are used to control whether the handshake will success or
   // not.
-  void CreateClientAndServerSessions() {
+  void CreateClientAndServerSessions(bool client_handshake_success = true,
+                                     bool server_handshake_success = true) {
     Init();
     client_peer_ =
         CreateSession(Perspective::IS_CLIENT, std::move(client_writer_));
@@ -357,6 +463,26 @@
 
     client_channel_->SetObserver(client_peer_.get());
     server_channel_->SetObserver(server_peer_.get());
+
+    client_peer_->SetClientCryptoConfig(new QuicCryptoClientConfig(
+        std::unique_ptr<ProofVerifier>(
+            new FakeProofVerifier(client_handshake_success)),
+        TlsClientHandshaker::CreateSslCtx()));
+
+    QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig(
+        "TESTING", QuicRandom::GetInstance(),
+        std::unique_ptr<FakeProofSource>(
+            new FakeProofSource(server_handshake_success)),
+        TlsServerHandshaker::CreateSslCtx());
+    // Provide server with serialized config string to prove ownership.
+    QuicCryptoServerConfig::ConfigOptions options;
+    std::unique_ptr<QuicServerConfigProtobuf> primary_config(
+        server_config->GenerateConfig(QuicRandom::GetInstance(), &clock_,
+                                      options));
+    std::unique_ptr<CryptoHandshakeMessage> message(
+        server_config->AddConfig(std::move(primary_config), clock_.WallNow()));
+
+    server_peer_->SetServerCryptoConfig(server_config);
   }
 
   std::unique_ptr<QuartcSessionForTest> CreateSession(
@@ -364,7 +490,7 @@
       std::unique_ptr<QuartcPacketWriter> writer) {
     std::unique_ptr<QuicConnection> quic_connection =
         CreateConnection(perspective, writer.get());
-    QuicString remote_fingerprint_value = "value";
+    string remote_fingerprint_value = "value";
     QuicConfig config;
     return QuicMakeUnique<QuartcSessionForTest>(
         std::move(quic_connection), config, remote_fingerprint_value,
@@ -375,14 +501,22 @@
                                                    QuartcPacketWriter* writer) {
     QuicIpAddress ip;
     ip.FromString("0.0.0.0");
+    if (!alarm_factory_) {
+      // QuartcFactory is only used as an alarm factory.
+      QuartcFactoryConfig config;
+      config.clock = &quartc_clock_;
+      config.task_runner = &task_runner_;
+      alarm_factory_ = QuicMakeUnique<QuartcFactory>(config);
+    }
+
     return QuicMakeUnique<QuicConnection>(
         0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
-        &alarm_factory_, writer, /*owns_writer=*/false, perspective,
+        alarm_factory_.get(), writer, /*owns_writer=*/false, perspective,
         CurrentSupportedVersions());
   }
 
   // Runs all tasks scheduled in the next 200 ms.
-  void RunTasks() { alarm_factory_.Run(200); }
+  void RunTasks() { task_runner_.Run(200); }
 
   void StartHandshake() {
     server_peer_->StartCryptoHandshake();
@@ -398,9 +532,23 @@
     ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
     ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
 
+    uint8_t server_key[kOutputKeyLength];
+    uint8_t client_key[kOutputKeyLength];
+    bool use_context = true;
+    bool server_success = server_peer_->ExportKeyingMaterial(
+        kExporterLabel, kExporterContext, kExporterContextLen, use_context,
+        server_key, kOutputKeyLength);
+    ASSERT_TRUE(server_success);
+    bool client_success = client_peer_->ExportKeyingMaterial(
+        kExporterLabel, kExporterContext, kExporterContextLen, use_context,
+        client_key, kOutputKeyLength);
+    ASSERT_TRUE(client_success);
+    EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key)));
+
     // Now we can establish encrypted outgoing stream.
-    QuartcStream* outgoing_stream = server_peer_->CreateOutgoingDynamicStream();
-    QuicStreamId stream_id = outgoing_stream->id();
+    QuartcStreamInterface* outgoing_stream =
+        server_peer_->CreateOutgoingStream(kDefaultStreamParam);
+    QuicStreamId stream_id = outgoing_stream->stream_id();
     ASSERT_NE(nullptr, outgoing_stream);
     EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
 
@@ -410,16 +558,16 @@
     char kTestMessage[] = "Hello";
     test::QuicTestMemSliceVector data(
         {std::make_pair(kTestMessage, strlen(kTestMessage))});
-    outgoing_stream->WriteMemSlices(data.span(), /*fin=*/false);
+    outgoing_stream->Write(data.span(), kDefaultWriteParam);
     RunTasks();
 
     // Wait for peer 2 to receive messages.
     ASSERT_TRUE(client_peer_->has_data());
 
-    QuartcStream* incoming =
+    QuartcStreamInterface* incoming =
         client_peer_->session_delegate()->incoming_stream();
     ASSERT_TRUE(incoming);
-    EXPECT_EQ(incoming->id(), stream_id);
+    EXPECT_EQ(incoming->stream_id(), stream_id);
     EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
 
     EXPECT_EQ(client_peer_->data()[stream_id], kTestMessage);
@@ -427,7 +575,7 @@
     char kTestResponse[] = "Response";
     test::QuicTestMemSliceVector response(
         {std::make_pair(kTestResponse, strlen(kTestResponse))});
-    incoming->WriteMemSlices(response.span(), /*fin=*/false);
+    incoming->Write(response.span(), kDefaultWriteParam);
     RunTasks();
     // Wait for peer 1 to receive messages.
     ASSERT_TRUE(server_peer_->has_data());
@@ -458,9 +606,10 @@
   }
 
  protected:
-  MockClock clock_;
-  FakeAlarmFactory alarm_factory_{&clock_};
+  std::unique_ptr<QuicAlarmFactory> alarm_factory_;
   SimpleBufferAllocator buffer_allocator_;
+  MockClock clock_;
+  MockQuartcClock quartc_clock_{&clock_};
 
   std::unique_ptr<FakeTransportChannel> client_channel_;
   std::unique_ptr<FakeTransportChannel> server_channel_;
@@ -470,6 +619,8 @@
   std::unique_ptr<QuartcPacketWriter> server_writer_;
   std::unique_ptr<QuartcSessionForTest> client_peer_;
   std::unique_ptr<QuartcSessionForTest> server_peer_;
+
+  FakeTaskRunner task_runner_{&clock_};
 };
 
 TEST_F(QuartcSessionTest, StreamConnection) {
@@ -478,19 +629,42 @@
   TestStreamConnection();
 }
 
-TEST_F(QuartcSessionTest, PreSharedKeyHandshake) {
-  CreateClientAndServerSessions();
-  client_peer_->SetPreSharedKey("foo");
-  server_peer_->SetPreSharedKey("foo");
+TEST_F(QuartcSessionTest, ClientRejection) {
+  CreateClientAndServerSessions(false /*client_handshake_success*/,
+                                true /*server_handshake_success*/);
   StartHandshake();
-  TestStreamConnection();
+  TestDisconnectAfterFailedHandshake();
+}
+
+TEST_F(QuartcSessionTest, ServerRejection) {
+  CreateClientAndServerSessions(true /*client_handshake_success*/,
+                                false /*server_handshake_success*/);
+  StartHandshake();
+  TestDisconnectAfterFailedHandshake();
 }
 
 // Test that data streams are not created before handshake.
 TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
   CreateClientAndServerSessions();
-  EXPECT_EQ(nullptr, server_peer_->CreateOutgoingDynamicStream());
-  EXPECT_EQ(nullptr, client_peer_->CreateOutgoingDynamicStream());
+  EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam));
+  EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam));
+}
+
+TEST_F(QuartcSessionTest, CloseQuartcStream) {
+  CreateClientAndServerSessions();
+  StartHandshake();
+  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
+  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+  QuartcStreamInterface* stream =
+      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  ASSERT_NE(nullptr, stream);
+
+  uint32_t id = stream->stream_id();
+  EXPECT_FALSE(client_peer_->IsClosedStream(id));
+  stream->SetDelegate(client_peer_->stream_delegate());
+  stream->Close();
+  RunTasks();
+  EXPECT_TRUE(client_peer_->IsClosedStream(id));
 }
 
 TEST_F(QuartcSessionTest, CancelQuartcStream) {
@@ -499,10 +673,11 @@
   ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
   ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
 
-  QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
+  QuartcStreamInterface* stream =
+      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
   ASSERT_NE(nullptr, stream);
 
-  uint32_t id = stream->id();
+  uint32_t id = stream->stream_id();
   EXPECT_FALSE(client_peer_->IsClosedStream(id));
   stream->SetDelegate(client_peer_->stream_delegate());
   client_peer_->CancelStream(id);
@@ -511,19 +686,103 @@
   EXPECT_TRUE(client_peer_->IsClosedStream(id));
 }
 
+TEST_F(QuartcSessionTest, BundleWrites) {
+  CreateClientAndServerSessions();
+  StartHandshake();
+  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
+  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+
+  client_peer_->BundleWrites();
+  QuartcStreamInterface* first =
+      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  QuicStreamId first_id = first->stream_id();
+  first->SetDelegate(client_peer_->stream_delegate());
+
+  char kFirstMessage[] = "Hello";
+  test::QuicTestMemSliceVector first_data(
+      {std::make_pair(kFirstMessage, strlen(kFirstMessage))});
+  first->Write(first_data.span(), kDefaultWriteParam);
+  RunTasks();
+
+  // Server should not receive any data until the client flushes writes.
+  EXPECT_FALSE(server_peer_->has_data());
+
+  QuartcStreamInterface* second =
+      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  QuicStreamId second_id = second->stream_id();
+  second->SetDelegate(client_peer_->stream_delegate());
+
+  char kSecondMessage[] = "World";
+  test::QuicTestMemSliceVector second_data(
+      {std::make_pair(kSecondMessage, strlen(kSecondMessage))});
+  second->Write(second_data.span(), kDefaultWriteParam);
+  RunTasks();
+
+  EXPECT_FALSE(server_peer_->has_data());
+
+  client_peer_->FlushWrites();
+  RunTasks();
+
+  ASSERT_TRUE(server_peer_->has_data());
+  EXPECT_EQ(server_peer_->data()[first_id], kFirstMessage);
+  EXPECT_EQ(server_peer_->data()[second_id], kSecondMessage);
+}
+
+TEST_F(QuartcSessionTest, StopBundlingOnIncomingData) {
+  CreateClientAndServerSessions();
+  StartHandshake();
+  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
+  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+
+  client_peer_->BundleWrites();
+  QuartcStreamInterface* first =
+      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  QuicStreamId first_id = first->stream_id();
+  first->SetDelegate(client_peer_->stream_delegate());
+
+  char kFirstMessage[] = "Hello";
+  test::QuicTestMemSliceVector first_data(
+      {std::make_pair(kFirstMessage, strlen(kFirstMessage))});
+  first->Write(first_data.span(), kDefaultWriteParam);
+  RunTasks();
+
+  // Server should not receive any data until the client flushes writes.
+  EXPECT_FALSE(server_peer_->has_data());
+
+  QuartcStreamInterface* second =
+      server_peer_->CreateOutgoingStream(kDefaultStreamParam);
+  QuicStreamId second_id = second->stream_id();
+  second->SetDelegate(server_peer_->stream_delegate());
+
+  char kSecondMessage[] = "World";
+  test::QuicTestMemSliceVector second_data(
+      {std::make_pair(kSecondMessage, strlen(kSecondMessage))});
+  second->Write(second_data.span(), kDefaultWriteParam);
+  RunTasks();
+
+  ASSERT_TRUE(client_peer_->has_data());
+  EXPECT_EQ(client_peer_->data()[second_id], kSecondMessage);
+
+  // Server should receive data as well, since the client stops bundling to
+  // process incoming packets.
+  ASSERT_TRUE(server_peer_->has_data());
+  EXPECT_EQ(server_peer_->data()[first_id], kFirstMessage);
+}
+
 TEST_F(QuartcSessionTest, WriterGivesPacketNumberToTransport) {
   CreateClientAndServerSessions();
   StartHandshake();
   ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
   ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
 
-  QuartcStream* stream = client_peer_->CreateOutgoingDynamicStream();
+  QuartcStreamInterface* stream =
+      client_peer_->CreateOutgoingStream(kDefaultStreamParam);
   stream->SetDelegate(client_peer_->stream_delegate());
 
   char kClientMessage[] = "Hello";
   test::QuicTestMemSliceVector stream_data(
       {std::make_pair(kClientMessage, strlen(kClientMessage))});
-  stream->WriteMemSlices(stream_data.span(), /*fin=*/false);
+  stream->Write(stream_data.span(), kDefaultWriteParam);
   RunTasks();
 
   // The transport should see the latest packet number sent by QUIC.
@@ -532,6 +791,33 @@
       client_peer_->connection()->sent_packet_manager().GetLargestSentPacket());
 }
 
+TEST_F(QuartcSessionTest, GetStats) {
+  CreateClientAndServerSessions();
+  StartHandshake();
+  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
+  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+
+  QuicConnectionStats stats = server_peer_->GetStats();
+  EXPECT_GT(stats.estimated_bandwidth, QuicBandwidth::Zero());
+  EXPECT_GT(stats.srtt_us, 0);
+  EXPECT_GT(stats.packets_sent, 0u);
+  EXPECT_EQ(stats.packets_lost, 0u);
+}
+
+TEST_F(QuartcSessionTest, DISABLED_PacketLossStats) {
+  CreateClientAndServerSessions();
+  StartHandshake();
+  ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed());
+  ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed());
+
+  // Packet loss doesn't count until the handshake is done.
+  server_transport_->set_packets_to_lose(1);
+  TestStreamConnection();
+
+  QuicConnectionStats stats = server_peer_->GetStats();
+  EXPECT_EQ(stats.packets_lost, 1u);
+}
+
 TEST_F(QuartcSessionTest, CloseConnection) {
   CreateClientAndServerSessions();
   StartHandshake();
diff --git a/net/third_party/quic/quartc/quartc_session_visitor_interface.h b/net/third_party/quic/quartc/quartc_session_visitor_interface.h
new file mode 100644
index 0000000..7cd75c6
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_session_visitor_interface.h
@@ -0,0 +1,53 @@
+// 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_
+#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_
+
+#include "net/third_party/quic/core/quic_connection.h"
+#include "net/third_party/quic/platform/api/quic_export.h"
+
+namespace quic {
+
+// QuartcSessionVisitor observes internals of a Quartc/QUIC session for the
+// purpose of gathering metrics or debug information.
+class QUIC_EXPORT_PRIVATE QuartcSessionVisitor {
+ public:
+  virtual ~QuartcSessionVisitor() {}
+
+  // Informs this visitor of a |QuicConnection| for the session.
+  // Called once when the visitor is attached to a QuartcSession, or when a new
+  // |QuicConnection| starts.
+  virtual void OnQuicConnection(QuicConnection* connection) {}
+
+  // Called when a packet has been sent.
+  virtual void OnPacketSent(const SerializedPacket& serialized_packet,
+                            QuicPacketNumber original_packet_number,
+                            TransmissionType transmission_type,
+                            QuicTime sent_time) {}
+
+  // Called when an ack is received.
+  virtual void OnIncomingAck(const QuicAckFrame& ack_frame,
+                             QuicTime ack_receive_time,
+                             QuicPacketNumber largest_observed,
+                             bool rtt_updated,
+                             QuicPacketNumber least_unacked_sent_packet) {}
+
+  // Called when a packet is lost.
+  virtual void OnPacketLoss(QuicPacketNumber lost_packet_number,
+                            TransmissionType transmission_type,
+                            QuicTime detection_time) {}
+
+  // Called when a WindowUpdateFrame is received.
+  virtual void OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame,
+                                   const QuicTime& receive_time) {}
+
+  // Called when version negotiation succeeds.
+  virtual void OnSuccessfulVersionNegotiation(
+      const ParsedQuicVersion& version) {}
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_SESSION_VISITOR_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_stream.cc b/net/third_party/quic/quartc/quartc_stream.cc
index 6cbce4a..8c628cf 100644
--- a/net/third_party/quic/quartc/quartc_stream.cc
+++ b/net/third_party/quic/quartc/quartc_stream.cc
@@ -50,11 +50,39 @@
   delegate_->OnBufferChanged(this);
 }
 
+uint32_t QuartcStream::stream_id() {
+  return id();
+}
+
+uint64_t QuartcStream::bytes_buffered() {
+  return BufferedDataBytes();
+}
+
+bool QuartcStream::fin_sent() {
+  return QuicStream::fin_sent();
+}
+
+int QuartcStream::stream_error() {
+  return QuicStream::stream_error();
+}
+
+void QuartcStream::Write(QuicMemSliceSpan data, const WriteParameters& param) {
+  WriteMemSlices(data, param.fin);
+}
+
 void QuartcStream::FinishWriting() {
   WriteOrBufferData(QuicStringPiece(nullptr, 0), true, nullptr);
 }
 
-void QuartcStream::SetDelegate(Delegate* delegate) {
+void QuartcStream::FinishReading() {
+  QuicStream::StopReading();
+}
+
+void QuartcStream::Close() {
+  QuicStream::session()->CloseStream(id());
+}
+
+void QuartcStream::SetDelegate(QuartcStreamInterface::Delegate* delegate) {
   if (delegate_) {
     LOG(WARNING) << "The delegate for Stream " << id()
                  << " has already been set.";
diff --git a/net/third_party/quic/quartc/quartc_stream.h b/net/third_party/quic/quartc/quartc_stream.h
index 830d45f..7a7173e 100644
--- a/net/third_party/quic/quartc/quartc_stream.h
+++ b/net/third_party/quic/quartc/quartc_stream.h
@@ -8,15 +8,13 @@
 #include "net/third_party/quic/core/quic_session.h"
 #include "net/third_party/quic/core/quic_stream.h"
 #include "net/third_party/quic/platform/api/quic_export.h"
-#include "net/third_party/quic/platform/api/quic_mem_slice_span.h"
+#include "net/third_party/quic/quartc/quartc_stream_interface.h"
 
 namespace quic {
 
-// Sends and receives data with a particular QUIC stream ID, reliably and
-// in-order. To send/receive data out of order, use separate streams. To
-// send/receive unreliably, close a stream after reliability is no longer
-// needed.
-class QUIC_EXPORT_PRIVATE QuartcStream : public QuicStream {
+// Implements a QuartcStreamInterface using a QuicStream.
+class QUIC_EXPORT_PRIVATE QuartcStream : public QuicStream,
+                                         public QuartcStreamInterface {
  public:
   QuartcStream(QuicStreamId id, QuicSession* session);
 
@@ -35,43 +33,27 @@
       const QuicReferenceCountedPointer<QuicAckListenerInterface>& ack_listener)
       override;
 
-  // QuartcStream interface methods.
+  // QuartcStreamInterface overrides.
+  uint32_t stream_id() override;
 
-  // Marks this stream as finished writing.  Asynchronously sends a FIN and
-  // closes the write-side.  It is not necessary to call FinishWriting() if the
-  // last call to Write() sends a FIN.
-  void FinishWriting();
+  uint64_t bytes_buffered() override;
 
-  // Implemented by the user of the QuartcStream to receive incoming
-  // data and be notified of state changes.
-  class Delegate {
-   public:
-    virtual ~Delegate() {}
+  bool fin_sent() override;
 
-    // Called when the stream receives data.  Called with |size| == 0 after all
-    // stream data has been delivered (once the stream receives a FIN bit).
-    // Note that the same packet may include both data and a FIN bit, causing
-    // this method to be called twice.
-    virtual void OnReceived(QuartcStream* stream,
-                            const char* data,
-                            size_t size) = 0;
+  int stream_error() override;
 
-    // Called when the stream is closed, either locally or by the remote
-    // endpoint.  Streams close when (a) fin bits are both sent and received,
-    // (b) Close() is called, or (c) the stream is reset.
-    // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native
-    // error code.
-    virtual void OnClose(QuartcStream* stream) = 0;
+  void Write(QuicMemSliceSpan data, const WriteParameters& param) override;
 
-    // Called when the contents of the stream's buffer changes.
-    virtual void OnBufferChanged(QuartcStream* stream) = 0;
-  };
+  void FinishWriting() override;
 
-  // The |delegate| is not owned by QuartcStream.
-  void SetDelegate(Delegate* delegate);
+  void FinishReading() override;
+
+  void Close() override;
+
+  void SetDelegate(QuartcStreamInterface::Delegate* delegate) override;
 
  private:
-  Delegate* delegate_ = nullptr;
+  QuartcStreamInterface::Delegate* delegate_ = nullptr;
 };
 
 }  // namespace quic
diff --git a/net/third_party/quic/quartc/quartc_stream_interface.h b/net/third_party/quic/quartc/quartc_stream_interface.h
new file mode 100644
index 0000000..9f3f600
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_stream_interface.h
@@ -0,0 +1,92 @@
+// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_STREAM_INTERFACE_H_
+#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_STREAM_INTERFACE_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "net/third_party/quic/platform/api/quic_export.h"
+#include "net/third_party/quic/platform/api/quic_mem_slice_span.h"
+
+namespace quic {
+
+// Sends and receives data with a particular QUIC stream ID, reliably and
+// in-order. To send/receive data out of order, use separate streams. To
+// send/receive unreliably, close a stream after reliability is no longer
+// needed.
+class QUIC_EXPORT_PRIVATE QuartcStreamInterface {
+ public:
+  virtual ~QuartcStreamInterface() {}
+
+  // The QUIC stream ID.
+  virtual uint32_t stream_id() = 0;
+
+  // The amount of data buffered on this stream.
+  virtual uint64_t bytes_buffered() = 0;
+
+  // Return true if the FIN has been sent. Used by the outgoing streams to
+  // determine if all the data has been sent
+  virtual bool fin_sent() = 0;
+
+  virtual int stream_error() = 0;
+
+  struct WriteParameters {
+    // |fin| is set to be true when there is no more data need to be send
+    // through a particular stream. The receiving side will used it to determine
+    // if the sender finish sending data.
+    bool fin = false;
+  };
+
+  // Sends data reliably and in-order.  Returns the amount sent.
+  // Does not buffer data.
+  virtual void Write(QuicMemSliceSpan data, const WriteParameters& param) = 0;
+
+  // Marks this stream as finished writing.  Asynchronously sends a FIN and
+  // closes the write-side.  The stream will no longer call OnCanWrite().
+  // It is not necessary to call FinishWriting() if the last call to Write()
+  // sends a FIN.
+  virtual void FinishWriting() = 0;
+
+  // Marks this stream as finished reading.  Further incoming data is discarded.
+  // The stream will no longer call OnReceived().
+  // It is never necessary to call FinishReading().  The read-side closes when a
+  // FIN is received, regardless of whether FinishReading() has been called.
+  virtual void FinishReading() = 0;
+
+  // Once Close is called, no more data can be sent, all buffered data will be
+  // dropped and no data will be retransmitted.
+  virtual void Close() = 0;
+
+  // Implemented by the user of the QuartcStreamInterface to receive incoming
+  // data and be notified of state changes.
+  class Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Called when the stream receives the data.  Called with |size| == 0 after
+    // all stream data has been delivered.
+    virtual void OnReceived(QuartcStreamInterface* stream,
+                            const char* data,
+                            size_t size) = 0;
+
+    // Called when the stream is closed, either locally or by the remote
+    // endpoint.  Streams close when (a) fin bits are both sent and received,
+    // (b) Close() is called, or (c) the stream is reset.
+    // TODO(zhihuang) Creates a map from the integer error_code to WebRTC native
+    // error code.
+    virtual void OnClose(QuartcStreamInterface* stream) = 0;
+
+    // Called when the contents of the stream's buffer changes.
+    virtual void OnBufferChanged(QuartcStreamInterface* stream) = 0;
+  };
+
+  // The |delegate| is not owned by QuartcStream.
+  virtual void SetDelegate(Delegate* delegate) = 0;
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_STREAM_INTERFACE_H_
diff --git a/net/third_party/quic/quartc/quartc_stream_test.cc b/net/third_party/quic/quartc/quartc_stream_test.cc
index 353990e..66e3673 100644
--- a/net/third_party/quic/quartc/quartc_stream_test.cc
+++ b/net/third_party/quic/quartc/quartc_stream_test.cc
@@ -11,9 +11,9 @@
 #include "net/third_party/quic/platform/api/quic_ptr_util.h"
 #include "net/third_party/quic/platform/api/quic_test.h"
 #include "net/third_party/quic/platform/api/quic_test_mem_slice_vector.h"
+#include "net/third_party/quic/quartc/quartc_clock_interface.h"
 #include "net/third_party/quic/quartc/quartc_factory.h"
 #include "net/third_party/quic/test_tools/mock_clock.h"
-#include "net/third_party/quic/test_tools/quic_test_utils.h"
 #include "net/third_party/spdy/core/spdy_protocol.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +23,7 @@
 namespace {
 
 static const QuicStreamId kStreamId = 5;
+static const QuartcStreamInterface::WriteParameters kDefaultParam;
 
 // MockQuicSession that does not create streams and writes data from
 // QuicStream to a string.
@@ -30,7 +31,7 @@
  public:
   MockQuicSession(QuicConnection* connection,
                   const QuicConfig& config,
-                  QuicString* write_buffer)
+                  std::string* write_buffer)
       : QuicSession(connection, nullptr /*visitor*/, config),
         write_buffer_(write_buffer) {}
 
@@ -91,7 +92,7 @@
 
  private:
   // Stores written data from ReliableQuicStreamAdapter.
-  QuicString* write_buffer_;
+  std::string* write_buffer_;
   // Whether data is written to write_buffer_.
   bool writable_ = true;
 };
@@ -131,23 +132,23 @@
   WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
 };
 
-class MockQuartcStreamDelegate : public QuartcStream::Delegate {
+class MockQuartcStreamDelegate : public QuartcStreamInterface::Delegate {
  public:
-  MockQuartcStreamDelegate(int id, QuicString* read_buffer)
+  MockQuartcStreamDelegate(int id, std::string* read_buffer)
       : id_(id), read_buffer_(read_buffer) {}
 
-  void OnBufferChanged(QuartcStream* stream) override {
-    last_bytes_buffered_ = stream->BufferedDataBytes();
+  void OnBufferChanged(QuartcStreamInterface* stream) override {
+    last_bytes_buffered_ = stream->bytes_buffered();
   }
 
-  void OnReceived(QuartcStream* stream,
+  void OnReceived(QuartcStreamInterface* stream,
                   const char* data,
                   size_t size) override {
-    EXPECT_EQ(id_, stream->id());
+    EXPECT_EQ(id_, stream->stream_id());
     read_buffer_->append(data, size);
   }
 
-  void OnClose(QuartcStream* stream) override { closed_ = true; }
+  void OnClose(QuartcStreamInterface* stream) override { closed_ = true; }
 
   bool closed() { return closed_; }
 
@@ -156,7 +157,7 @@
  protected:
   uint32_t id_;
   // Data read by the QuicStream.
-  QuicString* read_buffer_;
+  std::string* read_buffer_;
   // Whether the QuicStream is closed.
   bool closed_ = false;
 
@@ -173,7 +174,9 @@
     ip.FromString("0.0.0.0");
     bool owns_writer = true;
 
-    alarm_factory_ = QuicMakeUnique<test::MockAlarmFactory>();
+    // We only use QuartcFactory for its role as an alarm factory.
+    QuartcFactoryConfig config;
+    alarm_factory_ = QuicMakeUnique<QuartcFactory>(config);
 
     connection_ = QuicMakeUnique<QuicConnection>(
         0, QuicSocketAddress(ip, 0), this /*QuicConnectionHelperInterface*/,
@@ -207,9 +210,9 @@
   std::unique_ptr<MockQuartcStreamDelegate> mock_stream_delegate_;
   std::unique_ptr<MockQuicSession> session_;
   // Data written by the ReliableQuicStreamAdapterTest.
-  QuicString write_buffer_;
+  std::string write_buffer_;
   // Data read by the ReliableQuicStreamAdapterTest.
-  QuicString read_buffer_;
+  std::string read_buffer_;
   std::unique_ptr<QuicAlarmFactory> alarm_factory_;
   std::unique_ptr<QuicConnection> connection_;
   // Used to implement the QuicConnectionHelperInterface.
@@ -222,7 +225,7 @@
   CreateReliableQuicStream();
   char message[] = "Foo bar";
   test::QuicTestMemSliceVector data({std::make_pair(message, 7)});
-  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+  stream_->Write(data.span(), kDefaultParam);
   EXPECT_EQ("Foo bar", write_buffer_);
 }
 
@@ -231,7 +234,7 @@
   CreateReliableQuicStream();
   char message[] = "Foo bar";
   test::QuicTestMemSliceVector data({std::make_pair(message, 5)});
-  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+  stream_->Write(data.span(), kDefaultParam);
   EXPECT_EQ("Foo b", write_buffer_);
 }
 
@@ -244,11 +247,11 @@
 
   // The stream is not yet writable, so data will be buffered.
   session_->set_writable(false);
-  stream_->WriteMemSlices(data.span(), /*fin=*/false);
+  stream_->Write(data.span(), kDefaultParam);
 
   // Check that data is buffered.
   EXPECT_TRUE(stream_->HasBufferedData());
-  EXPECT_EQ(7u, stream_->BufferedDataBytes());
+  EXPECT_EQ(7u, stream_->bytes_buffered());
 
   // Check that the stream told its delegate about the buffer change.
   EXPECT_EQ(7u, mock_stream_delegate_->last_bytes_buffered());
@@ -262,10 +265,10 @@
   test::QuicTestMemSliceVector data1({std::make_pair(message1, 5)});
 
   // More writes go into the buffer.
-  stream_->WriteMemSlices(data1.span(), /*fin=*/false);
+  stream_->Write(data1.span(), kDefaultParam);
 
   EXPECT_TRUE(stream_->HasBufferedData());
-  EXPECT_EQ(12u, stream_->BufferedDataBytes());
+  EXPECT_EQ(12u, stream_->bytes_buffered());
   EXPECT_EQ(12u, mock_stream_delegate_->last_bytes_buffered());
   EXPECT_EQ(0ul, write_buffer_.size());
 
@@ -274,7 +277,7 @@
   stream_->OnCanWrite();
 
   EXPECT_FALSE(stream_->HasBufferedData());
-  EXPECT_EQ(0u, stream_->BufferedDataBytes());
+  EXPECT_EQ(0u, stream_->bytes_buffered());
   EXPECT_EQ(0u, mock_stream_delegate_->last_bytes_buffered());
   EXPECT_EQ("Foo barxyzzy", write_buffer_);
 }
@@ -314,11 +317,10 @@
   EXPECT_EQ("Hello", read_buffer_);
 }
 
-// Streams do not call OnReceived() after StopReading().
-// Note: this is tested here because Quartc relies on this behavior.
-TEST_F(QuartcStreamTest, StopReading) {
+// Streams do not call OnReceived() after FinishReading().
+TEST_F(QuartcStreamTest, FinishReading) {
   CreateReliableQuicStream();
-  stream_->StopReading();
+  stream_->FinishReading();
 
   QuicStreamFrame frame(kStreamId, false, 0, "Hello, World!");
   stream_->OnStreamFrame(frame);
@@ -346,8 +348,10 @@
   QuicStreamFrame frame(kStreamId, true, 0, 0);
   stream_->OnStreamFrame(frame);
 
+  QuartcStreamInterface::WriteParameters param;
+  param.fin = true;
   test::QuicTestMemSliceVector data({});
-  stream_->WriteMemSlices(data.span(), /*fin=*/true);
+  stream_->Write(data.span(), param);
 
   // Check that the OnClose() callback occurred.
   EXPECT_TRUE(mock_stream_delegate_->closed());
diff --git a/net/third_party/quic/quartc/quartc_task_runner_interface.h b/net/third_party/quic/quartc/quartc_task_runner_interface.h
new file mode 100644
index 0000000..b3560b3c
--- /dev/null
+++ b/net/third_party/quic/quartc/quartc_task_runner_interface.h
@@ -0,0 +1,51 @@
+// Copyright (c) 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 NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_TASK_RUNNER_INTERFACE_H_
+#define NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_TASK_RUNNER_INTERFACE_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+namespace quic {
+
+// Used by platform specific QuicAlarms. For example, WebRTC will use it to set
+// and cancel an alarm. When setting an alarm, the task runner will schedule a
+// task on rtc::Thread. When canceling an alarm, the canceler for that task will
+// be called.
+class QuartcTaskRunnerInterface {
+ public:
+  virtual ~QuartcTaskRunnerInterface() {}
+
+  class Task {
+   public:
+    virtual ~Task() {}
+
+    // Called when it's time to start the task.
+    virtual void Run() = 0;
+  };
+
+  // A handler used to cancel a scheduled task. In some cases, a task cannot
+  // be directly canceled with its pointer. For example, in WebRTC, the task
+  // will be scheduled on rtc::Thread. When canceling a task, its pointer cannot
+  // locate the scheduled task in the thread message queue. So when scheduling a
+  // task, an additional handler (ScheduledTask) will be returned.
+  class ScheduledTask {
+   public:
+    virtual ~ScheduledTask() {}
+
+    // Cancels a scheduled task, meaning the task will not be run.
+    virtual void Cancel() = 0;
+  };
+
+  // Schedules a task, which will be run after the given delay. A ScheduledTask
+  // may be used to cancel the task.
+  virtual std::unique_ptr<ScheduledTask> Schedule(Task* task,
+                                                  uint64_t delay_ms) = 0;
+};
+
+}  // namespace quic
+
+#endif  // NET_THIRD_PARTY_QUIC_QUARTC_QUARTC_TASK_RUNNER_INTERFACE_H_
diff --git a/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h b/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
index c5e5849..0bc7246 100644
--- a/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
+++ b/services/device/media_transfer_protocol/media_transfer_protocol_daemon_client.h
@@ -40,7 +40,7 @@
   // A callback to be called when DBus method call fails.
   using ErrorCallback = base::OnceClosure;
 
-  // A callback to handle the result of EnumerateAutoMountableDevices.
+  // A callback to handle the result of EnumerateStorages.
   // The argument is the enumerated storage names.
   using EnumerateStoragesCallback =
       base::OnceCallback<void(const std::vector<std::string>& storage_names)>;
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 8698b6e..d218b3dc 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -884,6 +884,56 @@
       "chromedriver"
     ]
   },
+  "android-go-perf": {
+    "isolated_scripts": [
+      {
+        "args": [
+          "-v",
+          "--browser=android-chromium",
+          "--upload-results",
+          "--run-ref-build",
+          "--test-shard-map-filename=android_go_shard_map.json"
+        ],
+        "isolate_name": "performance_test_suite",
+        "merge": {
+          "args": [
+            "--service-account-file",
+            "/creds/service_accounts/service-account-chromium-perf-histograms.json"
+          ],
+          "script": "//tools/perf/process_perf_results.py"
+        },
+        "name": "performance_test_suite",
+        "override_compile_targets": [
+          "performance_test_suite"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "O",
+              "device_os_flavor": "google",
+              "device_type": "gobo",
+              "os": "Android",
+              "pool": "chrome.tests.perf"
+            }
+          ],
+          "expiration": 21600,
+          "hard_timeout": 25200,
+          "ignore_task_failure": false,
+          "io_timeout": 1800,
+          "shards": 19,
+          "upload_test_results": true
+        },
+        "trigger_script": {
+          "args": [
+            "--multiple-dimension-script-verbose",
+            "True"
+          ],
+          "script": "//testing/trigger_scripts/perf_device_trigger.py"
+        }
+      }
+    ]
+  },
   "android-nexus5x-perf": {
     "isolated_scripts": [
       {
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index c7bdd71..0086f0e 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -359,7 +359,7 @@
 crbug.com/591099 external/wpt/fetch/cross-origin-resource-policy/fetch.any.html [ Timeout ]
 crbug.com/591099 external/wpt/fetch/http-cache/basic-auth-cache-test.html [ Timeout ]
 crbug.com/591099 external/wpt/fullscreen/api/document-exit-fullscreen-nested-in-iframe-manual.html [ Pass ]
-crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure ]
+crbug.com/591099 external/wpt/geolocation-API/PositionOptions.https.html [ Failure Pass ]
 crbug.com/591099 external/wpt/html-media-capture/capture_audio_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_image_cancel-manual.html [ Failure ]
 crbug.com/591099 external/wpt/html-media-capture/capture_video_cancel-manual.html [ Failure ]
@@ -368,7 +368,7 @@
 crbug.com/591099 external/wpt/html/browsers/the-window-object/window-open-noopener.html?_self [ Timeout ]
 crbug.com/591099 external/wpt/html/editing/focus/sequential-focus-navigation-and-the-tabindex-attribute/focus-tabindex-positive.html [ Timeout ]
 crbug.com/863040 external/wpt/html/editing/focus/tabindex-focus-flag.html [ Crash ]
-crbug.com/591099 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.worker.html [ Failure ]
+crbug.com/591099 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/serialization-via-idb.any.worker.html [ Crash Failure ]
 crbug.com/591099 external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-domain-success.sub.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/color.html [ Failure ]
 crbug.com/591099 external/wpt/html/rendering/non-replaced-elements/the-page/body-margin-2j.html [ Failure ]
@@ -410,7 +410,7 @@
 crbug.com/591099 external/wpt/picture-in-picture/request-picture-in-picture-twice.html [ Pass ]
 crbug.com/591099 external/wpt/pointerevents/pointerevent_click_during_capture-manual.html [ Crash Timeout ]
 crbug.com/591099 external/wpt/quirks/line-height-calculation.html [ Failure ]
-crbug.com/591099 external/wpt/requestidlecallback/callback-iframe.html [ Pass Timeout ]
+crbug.com/591099 external/wpt/requestidlecallback/callback-iframe.html [ Pass ]
 crbug.com/591099 external/wpt/requestidlecallback/callback-timeout-when-busy.html [ Timeout ]
 crbug.com/591099 external/wpt/requestidlecallback/callback-timeout.html [ Timeout ]
 crbug.com/591099 external/wpt/service-workers/service-worker/navigation-preload/broken-chunked-encoding.https.html [ Failure ]
@@ -548,7 +548,7 @@
 crbug.com/591099 fast/ruby/position-after.html [ Failure ]
 crbug.com/591099 fast/scrolling/content-box-smaller-than-scrollbar.html [ Failure ]
 crbug.com/591099 fast/scrolling/jquery-rtl-scroll-type.html [ Failure ]
-crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Pass ]
+crbug.com/591099 fast/scrolling/scrollbar-tickmarks-hittest.html [ Failure Pass ]
 crbug.com/591099 fast/shapes/shape-outside-floats/shape-outside-clip-path-selection.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/inline-block-with-padding.html [ Failure ]
 crbug.com/591099 fast/sub-pixel/repaint-subpixel-layer-in-subpixel-composited-layer.html [ Failure ]
@@ -592,6 +592,7 @@
 crbug.com/855039 html/details_summary/details-writing-mode-align-right.html [ Failure ]
 crbug.com/855039 html/details_summary/details-writing-mode.html [ Failure ]
 crbug.com/591099 http/tests/devtools/console-resource-errors.js [ Failure Pass ]
+crbug.com/591099 http/tests/devtools/console/console-correct-suggestions.js [ Failure Pass ]
 crbug.com/591099 http/tests/devtools/console/console-search.js [ Timeout ]
 crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure ]
 crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js [ Failure ]
@@ -618,7 +619,7 @@
 crbug.com/591099 http/tests/security/setDomainRelaxationForbiddenForURLScheme.html [ Crash ]
 crbug.com/591099 http/tests/security/xssAuditor/block-does-not-leak-location.html [ Failure ]
 crbug.com/591099 http/tests/websocket/invalid-subprotocol-characters.html [ Pass Timeout ]
-crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Pass Timeout ]
+crbug.com/591099 idle-callback/test-runner-run-idle-tasks.html [ Pass ]
 crbug.com/714962 images/color-profile-background-clip-text.html [ Failure ]
 crbug.com/591099 images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/591099 images/feature-policy-max-downscaling-image.html [ Failure ]
@@ -633,12 +634,12 @@
 crbug.com/591099 media/video-zoom.html [ Failure ]
 crbug.com/591099 paint/inline/focus-ring-under-absolute-with-relative-continuation.html [ Failure ]
 crbug.com/591099 paint/invalidation/background/background-misaligned.html [ Failure ]
-crbug.com/591099 paint/invalidation/block-layout-inline-children-replaced.html [ Failure ]
-crbug.com/591099 paint/invalidation/box/box-inline-resize.html [ Failure ]
-crbug.com/591099 paint/invalidation/clip/clipped-relative.html [ Failure ]
+crbug.com/591099 paint/invalidation/block-layout-inline-children-replaced.html [ Failure Pass ]
+crbug.com/591099 paint/invalidation/box/box-inline-resize.html [ Failure Pass ]
+crbug.com/591099 paint/invalidation/clip/clipped-relative.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/clip/control-clip.html [ Failure ]
 crbug.com/591099 paint/invalidation/clip/outline-clip-change.html [ Failure ]
-crbug.com/591099 paint/invalidation/clip/replaced-clipped-positioned-not-wrong-incremental-repainting.html [ Failure ]
+crbug.com/591099 paint/invalidation/clip/replaced-clipped-positioned-not-wrong-incremental-repainting.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/compositing/clipping-should-not-repaint-composited-descendants.html [ Failure ]
 crbug.com/591099 paint/invalidation/compositing/subpixel-offset-scaled-transform-composited.html [ Failure ]
 crbug.com/591099 paint/invalidation/css-grid-layout/grid-item-change-column-repaint.html [ Failure ]
@@ -654,8 +655,8 @@
 crbug.com/591099 paint/invalidation/flexbox/scrollbars-changed.html [ Failure ]
 crbug.com/591099 paint/invalidation/float-new-in-block.html [ Failure ]
 crbug.com/591099 paint/invalidation/forms/slider-thumb-float.html [ Failure ]
-crbug.com/591099 paint/invalidation/image/do-not-paint-below-image-baseline.html [ Failure ]
-crbug.com/591099 paint/invalidation/image/percent-size-image-resize-container.html [ Failure ]
+crbug.com/591099 paint/invalidation/image/do-not-paint-below-image-baseline.html [ Failure Pass ]
+crbug.com/591099 paint/invalidation/image/percent-size-image-resize-container.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/line-flow-with-floats-1.html [ Failure ]
 crbug.com/591099 paint/invalidation/line-flow-with-floats-10.html [ Failure ]
 crbug.com/591099 paint/invalidation/line-flow-with-floats-3.html [ Failure ]
@@ -664,7 +665,7 @@
 crbug.com/591099 paint/invalidation/line-flow-with-floats-6.html [ Failure ]
 crbug.com/591099 paint/invalidation/line-flow-with-floats-7.html [ Failure ]
 crbug.com/591099 paint/invalidation/line-flow-with-floats-9.html [ Failure ]
-crbug.com/591099 paint/invalidation/list-marker-2.html [ Failure ]
+crbug.com/591099 paint/invalidation/list-marker-2.html [ Failure Pass ]
 crbug.com/824918 paint/invalidation/multicol/multicol-repaint.html [ Failure ]
 crbug.com/591099 paint/invalidation/offset-change-wrong-invalidation-with-float.html [ Failure ]
 crbug.com/591099 paint/invalidation/outline/focus-continuations.html [ Failure ]
@@ -683,14 +684,14 @@
 crbug.com/591099 paint/invalidation/overflow/justify-self-overflow-change.html [ Failure ]
 crbug.com/591099 paint/invalidation/position/intermediate-layout-position.html [ Failure ]
 crbug.com/591099 paint/invalidation/position/justify-content-position-change.html [ Failure ]
-crbug.com/591099 paint/invalidation/position/positioned-list-offset-change-repaint.html [ Failure ]
+crbug.com/591099 paint/invalidation/position/positioned-list-offset-change-repaint.html [ Failure Pass ]
 crbug.com/714962 paint/invalidation/position/relative-positioned-movement-repaint.html [ Failure ]
 crbug.com/591099 paint/invalidation/position/relayout-fixed-position-after-scale.html [ Failure ]
 crbug.com/591099 paint/invalidation/resize-iframe-text.html [ Failure ]
 crbug.com/591099 paint/invalidation/scroll/fixed-child-of-transformed-move-after-scroll.html [ Failure ]
 crbug.com/591099 paint/invalidation/scroll/repaint-composited-child-in-scrolled-container.html [ Failure ]
-crbug.com/591099 paint/invalidation/selection/selected-replaced.html [ Failure ]
-crbug.com/591099 paint/invalidation/selection/selection-clear-after-move.html [ Failure ]
+crbug.com/591099 paint/invalidation/selection/selected-replaced.html [ Failure Pass ]
+crbug.com/591099 paint/invalidation/selection/selection-clear-after-move.html [ Failure Pass ]
 crbug.com/591099 paint/invalidation/selection/selection-rl.html [ Failure ]
 crbug.com/591099 paint/invalidation/stacking-context-lost.html [ Failure ]
 crbug.com/591099 paint/invalidation/svg/animated-path-inside-transformed-html.xhtml [ Failure Pass ]
@@ -712,11 +713,11 @@
 crbug.com/591099 printing/iframe-svg-in-object-print.html [ Failure ]
 crbug.com/591099 scrollbars/auto-scrollbar-fit-content.html [ Failure ]
 crbug.com/591099 storage/indexeddb/cursor-continue-validity.html [ Timeout ]
-crbug.com/591099 storage/indexeddb/index-cursor.html [ Timeout ]
+crbug.com/591099 storage/indexeddb/index-cursor.html [ Pass Timeout ]
 crbug.com/591099 storage/indexeddb/mozilla/indexes.html [ Timeout ]
 crbug.com/591099 storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Timeout ]
-crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass ]
-crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Timeout ]
+crbug.com/591099 storage/indexeddb/objectstore-cursor.html [ Pass Timeout ]
+crbug.com/591099 storage/indexeddb/objectstore-keycursor.html [ Pass Timeout ]
 crbug.com/591099 svg/custom/object-sizing-no-width-height.xhtml [ Failure ]
 crbug.com/591099 svg/filters/feTurbulence-bad-seeds.html [ Failure ]
 crbug.com/591099 svg/in-html/sizing/svg-inline.html [ Failure ]
@@ -738,16 +739,15 @@
 crbug.com/591099 tables/mozilla/bugs/bug2973.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug30692.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug50695-2.html [ Failure ]
-crbug.com/591099 tables/mozilla/bugs/bug5538.html [ Failure ]
+crbug.com/591099 tables/mozilla/bugs/bug5538.html [ Failure Pass ]
 crbug.com/591099 tables/mozilla/bugs/bug55527.html [ Failure ]
 crbug.com/591099 tables/mozilla_expected_failures/bugs/bug3166-16.html [ Failure ]
 crbug.com/591099 virtual/android/ [ Skip ]
 crbug.com/591099 virtual/exotic-color-space/ [ Skip ]
 crbug.com/591099 virtual/feature-policy-vibrate/ [ Skip ]
-crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Failure Timeout ]
+crbug.com/591099 virtual/gpu-rasterization/images/color-profile-image-filter-all.html [ Failure ]
 crbug.com/591099 virtual/gpu-rasterization/images/feature-policy-max-downscaling-image.html [ Failure ]
 crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-color-over-image.html [ Pass Timeout ]
-crbug.com/591099 virtual/gpu/fast/canvas/canvas-blending-image-over-color.html [ Pass Timeout ]
 crbug.com/591099 virtual/layout_ng/ [ Skip ]
 crbug.com/824918 virtual/layout_ng_experimental/ [ Skip ]
 crbug.com/591099 virtual/mojo-blob-urls/external/wpt/FileAPI/url/sandboxed-iframe.html [ Pass ]
@@ -755,7 +755,7 @@
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/background-tab-on-submit-synthesized-ctrl-click.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects.html [ Failure ]
 crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/mainthread-touchpad-fling-latching.html [ Pass ]
-crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Pass ]
+crbug.com/591099 virtual/mouseevent_fractional/fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Failure Pass ]
 crbug.com/591099 virtual/new-remote-playback-pipeline/ [ Skip ]
 crbug.com/591099 virtual/outofblink-cors/ [ Skip ]
 crbug.com/591099 virtual/paint-timing/external/wpt/paint-timing/sibling-painting-first-image.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 7a0b5c8..d717819c 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -4,7 +4,7 @@
 Bug(none) external/wpt/clear-site-data/storage.https.html [ Failure ]
 Bug(none) external/wpt/clear-site-data/navigation.https.html [ Timeout ]
 Bug(none) external/wpt/html/browsers/offline/appcache/workers/appcache-worker.html [ Timeout ]
-crbug.com/829417 external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Timeout ]
+crbug.com/829417 external/wpt/html/browsers/offline/appcache/workers/appcache-worker.https.html [ Crash Timeout ]
 crbug.com/771118 external/wpt/service-workers/service-worker/mime-sniffing.https.html [ Failure ]
 
 Bug(none) http/tests/misc/redirect-to-about-blank.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e653287f..596dc92 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1686,19 +1686,37 @@
 # Timeout tests in dictionary order.
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/sandboxed-iframe-fetch-event.https.html [ Timeout ]
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/worker-in-sandboxed-iframe-by-csp-fetch-event.https.html [ Timeout ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/send-authentication-existing-session-manual.htm [ Timeout ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/send-redirect-bogus-sync.htm [ Timeout ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/send-authentication-existing-session-manual.htm [ Timeout ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/send-redirect-bogus-sync.htm [ Timeout ]
 
 # Failing tests in dictionary order.
 crbug.com/736308 virtual/outofblink-cors/external/wpt/service-workers/service-worker/navigation-timing.https.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/access-control-and-redirects-async.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/access-control-sandboxed-iframe-denied-without-wildcard.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/access-control-sandboxed-iframe-denied.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/data-uri.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/event-upload-progress-crossorigin.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/event-upload-progress.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors/external/wpt/xhr/send-redirect-to-cors.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/fetch/chromium/error-messages.html [ Failure ]
-crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-no-credential-prompt.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-removal.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-subdomains.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/service-workers/service-worker/navigation-timing.https.html [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/access-control-and-redirects-async.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/access-control-sandboxed-iframe-denied-without-wildcard.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/access-control-sandboxed-iframe-denied.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/data-uri.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/event-upload-progress-crossorigin.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/event-upload-progress.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/send-authentication-prompt-2-manual.htm [ Failure ]
+crbug.com/736308 virtual/outofblink-cors-ns/external/wpt/xhr/send-redirect-to-cors.htm [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/fetch/chromium/error-messages.html [ Failure ]
-crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-no-credential-prompt.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-all.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-exact-match.html [ Failure ]
 crbug.com/736308 virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-whitelisting-removal.html [ Failure ]
@@ -1866,7 +1884,6 @@
 crbug.com/749492 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/009.html [ Skip ]
 crbug.com/749492 external/wpt/html/browsers/browsing-the-web/navigating-across-documents/010.html [ Skip ]
 crbug.com/490511 external/wpt/html/browsers/offline/application-cache-api/api_update.https.html [ Failure Pass ]
-crbug.com/490511 [ Linux Win ] external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type.html [ Failure ]
 crbug.com/108417 external/wpt/html/rendering/non-replaced-elements/tables/table-border-1.html [ Failure ]
 crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/color.html [ Failure ]
 crbug.com/490511 external/wpt/html/rendering/non-replaced-elements/the-hr-element-0/width.html [ Failure ]
@@ -2110,7 +2127,7 @@
 crbug.com/377696 printing/width-overflow.html [ Skip ]
 
 crbug.com/658305 css3/filters/buffer-offset.html [ Failure Pass ]
-crbug.com/658305 css3/filters/effect-all-on-background-hw.html [ Failure Pass ]
+crbug.com/658305 css3/filters/effect-all-on-background-hw.html [ Failure Pass Timeout ]
 crbug.com/658305 css3/filters/effect-reference-after.html [ Failure Pass ]
 crbug.com/658305 css3/filters/effect-reference-colorspace.html [ Failure Pass ]
 crbug.com/658305 crbug.com/758133 css3/filters/effect-reference-colorspace-hw.html [ Failure Pass Timeout ]
@@ -3541,10 +3558,20 @@
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/too_many_cues_wrapped.html [ Failure ]
 crbug.com/815116 external/wpt/workers/name-property.html [ Timeout Failure Pass ]
 crbug.com/626703 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 virtual/outofblink-cors-ns/external/wpt/xhr/event-readystatechange-loaded.htm [ Failure Timeout ]
 crbug.com/626703 external/wpt/xhr/preserve-ua-header-on-redirect.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/preserve-ua-header-on-redirect.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/xhr/preserve-ua-header-on-redirect.htm [ Failure ]
 crbug.com/626703 external/wpt/xhr/send-content-type-string.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/send-content-type-string.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/xhr/send-content-type-string.htm [ Failure ]
 crbug.com/626703 external/wpt/xhr/send-entity-body-document.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/send-entity-body-document.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/xhr/send-entity-body-document.htm [ Failure ]
 crbug.com/626703 external/wpt/xhr/setrequestheader-header-allowed.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors/external/wpt/xhr/setrequestheader-header-allowed.htm [ Failure ]
+crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/xhr/setrequestheader-header-allowed.htm [ Failure ]
 crbug.com/626703 [ Linux Win ] external/wpt/css/selectors/selector-placeholder-shown-type-change-001.html [ Failure ]
 crbug.com/626703 [ Linux Win ] external/wpt/css/selectors/selector-read-write-type-change-002.html [ Failure ]
 crbug.com/626703 [ Linux Win ] external/wpt/css/selectors/selector-required-type-change-002.html [ Failure ]
@@ -3564,6 +3591,9 @@
 crbug.com/636055 external/wpt/css/css-multicol/multicol-span-all-margin-nested-002.xht [ Failure ]
 crbug.com/792446 external/wpt/css/css-multicol/multicol-span-float-001.xht [ Failure ]
 
+# Skip a virtual test that wpt-importer is unable to update baseline for correctly.
+crbug.com/866802 virtual/video-surface-layer/external/wpt/picture-in-picture/idlharness.window.html [ Skip ]
+
 # This test times out on debug builds, see https://crbug.com/755810
 crbug.com/626703 [ Debug ] external/wpt/html/semantics/tabular-data/processing-model-1/span-limits.html [ Skip ]
 
@@ -3585,12 +3615,16 @@
 crbug.com/861564 external/wpt/workers/baseurl/alpha/xhr-in-worker.html [ Failure ]
 crbug.com/861564 external/wpt/workers/interfaces/WorkerGlobalScope/location/redirect.html [ Failure ]
 crbug.com/861564 external/wpt/xhr/open-url-redirected-worker-origin.htm [ Failure ]
+crbug.com/861564 virtual/outofblink-cors/external/wpt/xhr/open-url-redirected-worker-origin.htm [ Failure ]
+crbug.com/861564 virtual/outofblink-cors-ns/external/wpt/xhr/open-url-redirected-worker-origin.htm [ Failure ]
 
 # crbug.com/861564 is ongoing for classic shared workers.
 crbug.com/861564 external/wpt/workers/baseurl/alpha/importScripts-in-sharedworker.html [ Failure ]
 crbug.com/861564 external/wpt/workers/baseurl/alpha/xhr-in-sharedworker.html [ Failure ]
 crbug.com/861564 external/wpt/workers/interfaces/WorkerGlobalScope/location/redirect-sharedworker.html [ Failure ]
 crbug.com/861564 external/wpt/xhr/open-url-redirected-sharedworker-origin.htm [ Failure ]
+crbug.com/861564 virtual/outofblink-cors/external/wpt/xhr/open-url-redirected-sharedworker-origin.htm [ Failure ]
+crbug.com/861564 virtual/outofblink-cors-ns/external/wpt/xhr/open-url-redirected-sharedworker-origin.htm [ Failure ]
 
 # crbug.com/861564 is ongoing for module dedicated workers.
 crbug.com/861564 external/wpt/workers/baseurl/alpha/xhr-in-moduleworker.html [ Failure ]
@@ -3851,6 +3885,8 @@
 crbug.com/820334 virtual/outofblink-cors-ns/external/wpt/fetch/api/request/request-cache-default-conditional.html [ Timeout Pass ]
 
 crbug.com/765116 external/wpt/xhr/responsexml-document-properties.htm [ Failure ]
+crbug.com/765116 virtual/outofblink-cors/external/wpt/xhr/responsexml-document-properties.htm [ Failure ]
+crbug.com/765116 virtual/outofblink-cors-ns/external/wpt/xhr/responsexml-document-properties.htm [ Failure ]
 
 # Link highlights currently paint under ancestor affects but this is being
 # changed with BlinkGenPropertyTrees. Until that launches, this test will fail.
@@ -3920,6 +3956,8 @@
 crbug.com/715718 external/wpt/media-source/mediasource-activesourcebuffers.html [ Failure Pass ]
 crbug.com/715718 external/wpt/media-source/mediasource-remove.html [ Failure Pass ]
 crbug.com/715718 [ Win ] external/wpt/xhr/FormData-append.html [ Failure Pass ]
+crbug.com/715718 [ Win ] virtual/outofblink-cors/external/wpt/xhr/FormData-append.html [ Failure Pass ]
+crbug.com/715718 [ Win ] virtual/outofblink-cors-ns/external/wpt/xhr/FormData-append.html [ Failure Pass ]
 crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/align-items-004.htm [ Failure Pass ]
 crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/flex-minimum-width-flex-items-001.xht [ Failure Pass ]
 crbug.com/715718 [ Win ] external/wpt/css/css-flexbox/flex-minimum-width-flex-items-003.xht [ Failure Pass ]
@@ -4754,3 +4792,12 @@
 crbug.com/867532 [ Linux ] external/wpt/workers/modules/dedicated-worker-import.any.worker.html [ Timeout Pass ]
 crbug.com/867628 [ Mac ] virtual/user-activation-v2/fast/events/middleClickAutoscroll-click-hyperlink.html [ Failure Pass ]
 crbug.com/867628 [ Mac ] virtual/user-activation-v2/fast/events/middleClickAutoscroll-nested-divs-forbidden.html [ Timeout Pass ]
+
+# Sheriff 2018-07-26
+crbug.com/867376 [ Mac Linux ] css3/filters/filter-repaint-composited-fallback-crash.html [ Timeout Pass ]
+crbug.com/867376 [ Mac ] external/wpt/encoding/textdecoder-fatal-single-byte.any.html [ Timeout Pass ]
+crbug.com/867376 [ Mac ] http/tests/devtools/elements/elements-inspect-iframe-from-different-domain.js [ Timeout Pass ]
+crbug.com/867376 [ Mac ] http/tests/devtools/elements/css-variables/resolve-inherited-css-variables.js [ Timeout Pass ]
+crbug.com/867376 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-image-over-color.html [ Timeout Pass ]
+crbug.com/867376 [ Linux ] virtual/gpu/fast/canvas/canvas-blending-image-over-image.html [ Timeout Pass ]
+crbug.com/867376 [ Linux ] virtual/gpu-rasterization/images/color-profile-mask-image-svg.html [ Timeout Pass ]
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites
index 8c4af7f..4bbc2c7 100644
--- a/third_party/WebKit/LayoutTests/VirtualTestSuites
+++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -498,6 +498,11 @@
   },
   {
     "prefix": "outofblink-cors",
+    "base": "external/wpt/xhr",
+    "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
+  },
+  {
+    "prefix": "outofblink-cors",
     "base": "http/tests/fetch",
     "args": ["--enable-features=OutOfBlinkCORS,ServiceWorkerServicification"]
   },
@@ -528,6 +533,11 @@
   },
   {
     "prefix": "outofblink-cors-ns",
+    "base": "external/wpt/xhr",
+    "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
+  },
+  {
+    "prefix": "outofblink-cors-ns",
     "base": "http/tests/fetch",
     "args": ["--enable-features=OutOfBlinkCORS,NetworkService"]
   },
diff --git a/third_party/WebKit/LayoutTests/animations/stability/css-animation-null-effect-crash-expected.txt b/third_party/WebKit/LayoutTests/animations/stability/css-animation-null-effect-crash-expected.txt
new file mode 100644
index 0000000..3bd76f7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/stability/css-animation-null-effect-crash-expected.txt
@@ -0,0 +1 @@
+This should not crash
diff --git a/third_party/WebKit/LayoutTests/animations/stability/css-animation-null-effect-crash.html b/third_party/WebKit/LayoutTests/animations/stability/css-animation-null-effect-crash.html
new file mode 100644
index 0000000..a06b9122
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/stability/css-animation-null-effect-crash.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Crash updating a CSS animation after setting its effect to null</title>
+
+<style>
+@keyframes anim {
+  from {
+    margin-left: 0px;
+  }
+  to {
+    margin-left: 100px;
+  }
+}
+</style>
+
+<div id="box" style="width:100px; height: 100px; background: black; animation: anim 1s"></div>
+<p>This should not crash</p>
+
+<script>
+if (window.testRunner)
+  testRunner.dumpAsText();
+
+const animation = box.getAnimations()[0];
+animation.effect = null;
+// Cause an update of the CSS animation by changing the duration.
+box.style.animationDuration = "2s";
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type-ref.html
index 902c1724..879ca92 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type-ref.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type-ref.html
@@ -4,4 +4,6 @@
 <body>
   <input type="text">
   <input type="text">
+  <input type="text" disabled>
+  <input type="text" disabled>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type.html
index 1ff38cd1..a5c7a60 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/bindings/the-input-element-as-a-text-entry-widget/unrecognized-type-should-fallback-as-text-type.html
@@ -5,4 +5,6 @@
 <body>
   <input>
   <input type="unknown">
+  <input disabled>
+  <input type="unknown" disabled>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html
new file mode 100644
index 0000000..863fe84
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/TrustedTypePolicyFactory-createPolicy.tentative.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js" ></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+<body>
+<script>
+  async_test(t => {
+    var policy = window.trustedTypes.createPolicy('SomeName')
+        .then(t.step_func_done(policy => {
+           assert_true(policy instanceof TrustedTypePolicy);
+           assert_equals(policy.name, 'SomeName');
+    }));
+  }, "policy.name = name");
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/Window-trustedTypes.tentative.html b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/Window-trustedTypes.tentative.html
new file mode 100644
index 0000000..ef44877
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/Window-trustedTypes.tentative.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="support/helper.sub.js"></script>
+<body>
+<script>
+  test(t => {
+    let factory = window.trustedTypes;
+    assert_true(factory instanceof TrustedTypePolicyFactory);
+  }, "factory = window.trustedTypes");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-expected.html b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-expected.html
new file mode 100644
index 0000000..c18e9d8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-expected.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+div {
+  display: inline-block;
+  float: left;
+  background: silver;
+  width: 100px;
+  height: 100px;
+  margin: 20px;
+  font-size: 25px;
+  overflow: hidden;
+  line-height: 1;
+}
+.first-line::first-line {
+  font-size: 30px;
+}
+</style>
+<div>baar</div>
+<div>baarbaar baarbaar</div>
+<div>baarbaarbaar baarbaarbaar baarbaarbaar baarbaarbaar baarbaarbaar</div>
+<div>baar baar baar baar</div>
+<div>baar</div>
+<div>b &#x55e8;</div>
+<div class="first-line">baar</div>
+<div class="first-line">baarbaar baarbaar</div>
+<div class="first-line">baarbaarbaar baarbaarbaar baarbaarbaar baarbaarbaar baarbaarbaar</div>
+<div class="first-line">baar baar baar baar</div>
+<div class="first-line">baar</div>
+<div class="first-line">b &#x55e8;</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-tab-expected.html b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-tab-expected.html
new file mode 100644
index 0000000..7ffbe90e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-tab-expected.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+pre {
+  display: inline-block;
+  float: left;
+  background: silver;
+  width: 100px;
+  height: 100px;
+  margin: 20px;
+  font-family: monospace;
+  font-size: 10px;
+  overflow: hidden;
+  white-space: pre-wrap;
+  line-height: 1;
+}
+.first-line::first-line {
+  font-size: 15px;
+}
+</style>
+<pre>bar bar bar</pre>
+<pre>bar&#9;bar&#9;bar</pre>
+<pre class="first-line">bar bar bar</pre>
+<pre class="first-line">bar&#9;bar&#9;bar</pre>
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-tab.html b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-tab.html
new file mode 100644
index 0000000..655b215
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data-tab.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="match" href="change-text-node-data-tab-expected.html">
+<style>
+pre {
+  display: inline-block;
+  float: left;
+  background: silver;
+  width: 100px;
+  height: 100px;
+  margin: 20px;
+  font-family: monospace;
+  font-size: 10px;
+  overflow: hidden;
+  white-space: pre-wrap;
+  contain: layout size;
+  line-height: 1;
+}
+.first-line::first-line {
+  font-size: 15px;
+}
+</style>
+<script>
+  const originalValues = [
+    "foo",
+    "foo",
+  ];
+  const newValues = [
+    "bar bar bar",
+    "bar\tbar\tbar",
+  ];
+
+  function setupTest() {
+    originalValues.forEach((text) => {
+      let pre = document.createElement("pre");
+      pre.appendChild(document.createTextNode(text));
+      document.body.appendChild(pre);
+    });
+
+    originalValues.forEach((text) => {
+      let firstLinePre = document.createElement("pre");
+      firstLinePre.className = "first-line";
+      firstLinePre.appendChild(document.createTextNode(text));
+      document.body.appendChild(firstLinePre);
+    });
+  }
+
+  function changeTextNodeData() {
+    let pres = document.getElementsByTagName("pre");
+    for (let i = 0; i < pres.length; i++) {
+      pres[i].childNodes[0].data = newValues[i % newValues.length];
+    }
+  }
+
+  function runTest() {
+    setupTest();
+    document.body.offsetLeft;
+    changeTextNodeData();
+  }
+</script>
+<body onload="runTest();">
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data.html b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data.html
new file mode 100644
index 0000000..3ce763e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/containment/change-text-node-data.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="match" href="change-text-node-data-expected.html">
+<style>
+div {
+  display: inline-block;
+  float: left;
+  background: silver;
+  width: 100px;
+  height: 100px;
+  margin: 20px;
+  font-size: 25px;
+  overflow: hidden;
+  contain: layout size;
+  line-height: 1;
+}
+.first-line::first-line {
+  font-size: 30px;
+}
+</style>
+<script>
+  const originalValues = [
+    "foo",
+    "foofoo foofoo",
+    "foofoofoo foofoofoo foofoofoo foofoofoo foofoofoo",
+    "foo",
+    "foo foo foo foo foo",
+    "foo",
+  ];
+  const newValues = [
+    "baar",
+    "baarbaar baarbaar",
+    "baarbaarbaar baarbaarbaar baarbaarbaar baarbaarbaar baarbaarbaar",
+    "baar baar baar baar",
+    "baar",
+    "b \u55e8",
+  ];
+
+  function setupTest() {
+    originalValues.forEach((text) => {
+      let div = document.createElement("div");
+      div.appendChild(document.createTextNode(text));
+      document.body.appendChild(div);
+    });
+
+    originalValues.forEach((text) => {
+      let firstLineDiv = document.createElement("div");
+      firstLineDiv.className = "first-line";
+      firstLineDiv.appendChild(document.createTextNode(text));
+      document.body.appendChild(firstLineDiv);
+    });
+  }
+
+  function changeTextNodeData() {
+    let divs = document.getElementsByTagName("div");
+    for (let i = 0; i < divs.length; i++) {
+      divs[i].childNodes[0].data = newValues[i % newValues.length];
+    }
+  }
+
+  function runTest() {
+    setupTest();
+    document.body.offsetLeft;
+    changeTextNodeData();
+  }
+</script>
+<body onload="runTest();">
+</body>
diff --git a/third_party/WebKit/LayoutTests/fast/xmlhttprequest/xmlhttprequest-no-file-access-expected.txt b/third_party/WebKit/LayoutTests/fast/xmlhttprequest/xmlhttprequest-no-file-access-expected.txt
index 2a04bac..8214650e 100644
--- a/third_party/WebKit/LayoutTests/fast/xmlhttprequest/xmlhttprequest-no-file-access-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/xmlhttprequest/xmlhttprequest-no-file-access-expected.txt
@@ -1,4 +1,4 @@
 CONSOLE WARNING: line 22: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 23: Failed to load xmlhttprequest-no-file-access-expected.txt: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 23: Access to XMLHttpRequest at 'xmlhttprequest-no-file-access-expected.txt' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 
 The child iframe cannot paste its textual results into this iframe because it is considered a different domain - that's the point of this test! Therefore, success is denoted by the child iframe calling notifyDone. The test will hang if something goes amiss with the access control checks.
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/console-xhr-logging-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/console-xhr-logging-expected.txt
index 8d3352f..648886b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/console-xhr-logging-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/console-xhr-logging-expected.txt
@@ -41,7 +41,7 @@
 
 Message count: 3
 console-xhr-logging.js:13 sending a GET request to http://localhost:8000/devtools/resources/xhr-exists.html
-VM:37 Failed to load http://localhost:8000/devtools/resources/xhr-exists.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+VM:37 Access to XMLHttpRequest at 'http://localhost:8000/devtools/resources/xhr-exists.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
@@ -71,7 +71,7 @@
 
 Message count: 2
 console-xhr-logging.js:13 sending a GET request to http://localhost:8000/devtools/resources/xhr-exists.html
-VM:37 Failed to load http://localhost:8000/devtools/resources/xhr-exists.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+VM:37 Access to XMLHttpRequest at 'http://localhost:8000/devtools/resources/xhr-exists.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 makeXHR @ VM:37
 makeSimpleXHRWithPayload @ VM:13
 makeSimpleXHR @ VM:9
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-basic-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-basic-expected.txt
index c1f2cfe1..58dbd0f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-basic-expected.txt
@@ -1,5 +1,5 @@
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=1: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=2: The 'Access-Control-Allow-Origin' header has a value 'http://some.other.origin:80' that is not equal to the supplied origin. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://some.other.origin:80' that is not equal to the supplied origin.
 Test that basic EventSource cross-origin requests fail until they are allowed by the Access-Control-Allow-Origin header.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-non-http-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-non-http-expected.txt
index f58bfef0..e47cb76 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-non-http-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-non-http-expected.txt
@@ -1,7 +1,7 @@
-CONSOLE ERROR: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load motd: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'ftp://127.0.0.1/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at '127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 Test EventSource with non-HTTP protocol schemes in the URL.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-redirect-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-redirect-expected.txt
index 074f1b1..d5e89fb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-redirect-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-redirect-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that basic EventSource cross-origin requests fail on redirect.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-with-credentials-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-with-credentials-expected.txt
index 6f48db8..34a16ba 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-with-credentials-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/eventsource-cors-with-credentials-expected.txt
@@ -1,6 +1,6 @@
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=1: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=2: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=3: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=3' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
 Test that EventSource cross-origin requests with credentials fail until the correct CORS headers are sent.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-basic-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-basic-expected.txt
index 0365adc..d19dcf53 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-basic-expected.txt
@@ -1,5 +1,5 @@
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=1: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=2: The 'Access-Control-Allow-Origin' header has a value 'http://some.other.origin:80' that is not equal to the supplied origin. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php?count=2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://some.other.origin:80' that is not equal to the supplied origin.
 [Worker] Test that basic EventSource cross-origin requests fail until they are allowed by the Access-Control-Allow-Origin header.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt
index b6585b2..bbbb437 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-non-http-expected.txt
@@ -1,7 +1,7 @@
-CONSOLE ERROR: Failed to load ftp://127.0.0.1/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load motd: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'ftp://127.0.0.1/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at '127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to resource at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 [Worker] Test EventSource with non-HTTP protocol schemes in the URL.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-redirect-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-redirect-expected.txt
index 254860bf..7139ecdb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-redirect-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-redirect-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://127.0.0.1:8080/eventsource/resources/es-cors-basic.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 [Worker] Test that basic EventSource cross-origin requests fail on redirect.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-with-credentials-expected.txt b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-with-credentials-expected.txt
index e8d4d61..74a829f1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-with-credentials-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/eventsource/workers/eventsource-cors-with-credentials-expected.txt
@@ -1,6 +1,6 @@
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=1: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=2: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=3: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to resource at 'http://127.0.0.1:8080/eventsource/resources/es-cors-credentials.php?count=3' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
 [Worker] Test that EventSource cross-origin requests with credentials fail until the correct CORS headers are sent.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/error-messages-expected.txt b/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/error-messages-expected.txt
index e33c21d8..885d352 100644
--- a/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/error-messages-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/fetch/chromium/error-messages-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/fetch/resources/doctype.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
+CONSOLE ERROR: Access to fetch at 'http://localhost:8000/fetch/resources/doctype.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
 CONSOLE ERROR: Fetch API cannot load http://localhost:8000/fetch/resources/redirect-loop.php?Count=100&ACAOrigin=*. Redirect failed.
 This is a testharness.js-based test.
 PASS fetch() with 200 should not output error messages
diff --git a/third_party/WebKit/LayoutTests/http/tests/htmlimports/cors-same-origin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/htmlimports/cors-same-origin-expected.txt
index bc7f9468..504217b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/htmlimports/cors-same-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/htmlimports/cors-same-origin-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Imported resource at 'http://localhost:8080/htmlimports/resources/resources/hello.html?1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. The response had HTTP status code 404.
+CONSOLE ERROR: Access to imported resource at 'http://localhost:8080/htmlimports/resources/resources/hello.html?1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 PASS basic.import.querySelector('h1').innerHTML is "Hello, CORS!"
 PASS nested.import.querySelector('#sameOriginNoCors').import is null
 PASS nested.import.querySelector('#sameOriginCors').import.querySelector('h1').innerHTML is "Hello, CORS!"
diff --git a/third_party/WebKit/LayoutTests/http/tests/htmlimports/cross-origin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/htmlimports/cross-origin-expected.txt
index 67255ef..ef52e39 100644
--- a/third_party/WebKit/LayoutTests/http/tests/htmlimports/cross-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/htmlimports/cross-origin-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Imported resource at 'http://localhost:8080/htmlimports/resources/hello.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to imported resource at 'http://localhost:8080/htmlimports/resources/hello.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 PASS target.import is null
 PASS successfullyParsed is true
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/htmlimports/import-script-block-crossorigin-dynamic-expected.txt b/third_party/WebKit/LayoutTests/http/tests/htmlimports/import-script-block-crossorigin-dynamic-expected.txt
index ede990a..1018a2ed 100644
--- a/third_party/WebKit/LayoutTests/http/tests/htmlimports/import-script-block-crossorigin-dynamic-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/htmlimports/import-script-block-crossorigin-dynamic-expected.txt
@@ -1,5 +1,5 @@
-CONSOLE ERROR: Access to Script at 'http://127.0.0.1:8000/htmlimports/resources/external-script.js' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
-CONSOLE ERROR: Access to Script at 'http://127.0.0.1:8000/htmlimports/resources/cors-js.cgi' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://127.0.0.1:8000/htmlimports/resources/external-script.js' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to script at 'http://127.0.0.1:8000/htmlimports/resources/cors-js.cgi' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8000' that is not equal to the supplied origin.
 This test ensures that crossorigin-marked script elements are blocked properly
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-anonymous-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-anonymous-expected.txt
index 8e533d42..00adcb5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-anonymous-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-anonymous-expected.txt
@@ -1,6 +1,6 @@
-CONSOLE ERROR: Access to Image at 'http://localhost:8000/security/resources/abe.png' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://localhost:8000/security/resources/abe-allow-credentials.php' to 'http://localhost:8000/security/resources/abe-allow-credentials.php' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://127.0.0.1:8000/security/resources/abe-allow-credentials.php' to 'http://127.0.0.1:8000/security/resources/abe-allow-credentials.php' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/abe.png' (redirected from 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://localhost:8000/security/resources/abe.png') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://localhost:8000/security/resources/abe-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://127.0.0.1:8000/security/resources/abe-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
 Testing the handling of CORS-enabled fetch in the presence of 'anonymous' redirects.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-no-cors-expected.txt
index bec56fbb..842d6daa 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-no-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/img-crossorigin-redirect-no-cors-expected.txt
@@ -1,7 +1,7 @@
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/abe.png' to 'http://localhost:8000/security/resources/abe.png' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/abe-allow-star.php' to 'http://localhost:8000/security/resources/abe-allow-star.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/abe-allow-credentials.php' to 'http://localhost:8000/security/resources/abe-allow-credentials.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://127.0.0.1:8000/security/resources/abe-allow-credentials.php' to 'http://127.0.0.1:8000/security/resources/abe-allow-credentials.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/abe.png' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/abe-allow-star.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/abe-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to image at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://127.0.0.1:8000/security/resources/abe-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Testing the handling of CORS-enabled fetch in the presence of 'No CORS' redirects.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/img-with-failed-cors-check-fails-to-load-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/img-with-failed-cors-check-fails-to-load-expected.txt
index deb333d..f84ce56 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/img-with-failed-cors-check-fails-to-load-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/img-with-failed-cors-check-fails-to-load-expected.txt
@@ -1,3 +1,3 @@
-CONSOLE ERROR: Access to Image at 'http://localhost:8080/security/resources/red200x100.png' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to image at 'http://localhost:8080/security/resources/red200x100.png' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 ALERT: PASS: The error event was called.
 This test passes if the image below does not load. 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/isolatedWorld/cross-origin-xhr-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/isolatedWorld/cross-origin-xhr-expected.txt
index ecc5aa7..a3bbeda 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/isolatedWorld/cross-origin-xhr-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/isolatedWorld/cross-origin-xhr-expected.txt
@@ -1,6 +1,6 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/security/isolatedWorld/resources/cross-origin-xhr.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Tests that isolated worlds can have XHRs run in a different origin.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-reinserted-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-reinserted-expected.txt
index 2de567d..3fa6837 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-reinserted-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-reinserted-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to CSS stylesheet at 'http://127.0.0.1:8080/resources/slow-script.pl?delay=100' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to CSS stylesheet at 'http://127.0.0.1:8080/resources/slow-script.pl?delay=100' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that re-inserting a CORS-loading stylesheet is correctly handled.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-use-credentials-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-use-credentials-expected.txt
index 8cbf6be..00ab067 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-use-credentials-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/link-crossorigin-stylesheet-use-credentials-expected.txt
@@ -1,5 +1,5 @@
-CONSOLE ERROR: Access to CSS stylesheet at 'http://localhost:8080/security/resources/green-background-allow-star.php?1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Access to CSS stylesheet at 'http://localhost:8080/security/resources/green-background-allow-star.php?2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to CSS stylesheet at 'http://localhost:8080/security/resources/green-background-allow-star.php?1' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to CSS stylesheet at 'http://localhost:8080/security/resources/green-background-allow-star.php?2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
 Test that a linked stylesheet with a crossorigin=use-credentials attributes loads expected CORS enabled resources.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/preload-script-crossorigin-fails-cross-origin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/preload-script-crossorigin-fails-cross-origin-expected.txt
index 82aa13a5..fc0a447 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/preload-script-crossorigin-fails-cross-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/preload-script-crossorigin-fails-cross-origin-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/cors-script.php?delay=100&cors=false&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-script.php?delay=100&cors=false&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Preload of script with CORS failure only shows one error
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-2-expected.txt
index f189924a..dc46028 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-2-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 In an XHTML document, test that a script element with a crossorigin attribute does not load a cross-origin script when the resource sharing check fails on the response.
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-expected.txt
index a564194..a0de358 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-fails-cross-origin-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a script element with a crossorigin attribute does not load a cross-origin script when the resource sharing check fails on the response.
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-loads-correctly-credentials-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-loads-correctly-credentials-2-expected.txt
index 1170d344..e24830c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-loads-correctly-credentials-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-loads-correctly-credentials-2-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&credentials=true&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&credentials=true&value=FAIL' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 This test passes if the inserted script fails to load due to CORS.
 
 PASS (expected error reported)
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-anonymous-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-anonymous-expected.txt
index 31484d6..a31e7726 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-anonymous-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-anonymous-expected.txt
@@ -1,6 +1,6 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/localScript.js' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://localhost:8000/security/resources/script-allow-credentials.php' to 'http://localhost:8000/security/resources/script-allow-credentials.php' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://127.0.0.1:8000/security/resources/script-allow-credentials.php' to 'http://127.0.0.1:8000/security/resources/script-allow-credentials.php' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/localScript.js' (redirected from 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://localhost:8000/security/resources/localScript.js') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://localhost:8000/security/resources/script-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-redirect.php?mode=anonymous&url=http://127.0.0.1:8000/security/resources/script-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
 Testing the handling of CORS-enabled script fetch in the presence of 'anonymous' redirects.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-credentials-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-credentials-expected.txt
index 4207171d4..afaa703 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-credentials-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-credentials-expected.txt
@@ -1,7 +1,7 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/localScript.js' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Access to Script at 'http://127.0.0.1:8000/security/resources/script-allow-credentials.php' from origin 'null' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8000' that is not equal to the supplied origin. Origin 'null' is therefore not allowed access.
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/script-allow-star.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Access to Script at 'http://127.0.0.1:8000/security/resources/script-allow-star.php' from origin 'null' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'null' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/localScript.js' (redirected from 'http://localhost:8000/security/resources/cors-redirect.php?mode=use-credentials&url=http://localhost:8000/security/resources/localScript.js') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to script at 'http://127.0.0.1:8000/security/resources/script-allow-credentials.php' (redirected from 'http://localhost:8000/security/resources/cors-redirect.php?mode=use-credentials&url=http://127.0.0.1:8000/security/resources/script-allow-credentials.php') from origin 'null' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://127.0.0.1:8000' that is not equal to the supplied origin.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/script-allow-star.php' (redirected from 'http://localhost:8000/security/resources/cors-redirect.php?mode=use-credentials&url=http://localhost:8000/security/resources/script-allow-star.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
+CONSOLE ERROR: Access to script at 'http://127.0.0.1:8000/security/resources/script-allow-star.php' (redirected from 'http://localhost:8000/security/resources/cors-redirect.php?mode=use-credentials&url=http://127.0.0.1:8000/security/resources/script-allow-star.php') from origin 'null' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
 Testing the handling of CORS-enabled script fetch in the presence of 'credentialled' redirects.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-no-cors-expected.txt
index 7f274b6..8817333 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-no-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-crossorigin-redirect-no-cors-expected.txt
@@ -1,7 +1,7 @@
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/localScript.js' to 'http://localhost:8000/security/resources/localScript.js' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/script-allow-star.php' to 'http://localhost:8000/security/resources/script-allow-star.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/script-allow-credentials.php' to 'http://localhost:8000/security/resources/script-allow-credentials.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Redirect from 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://127.0.0.1:8000/security/resources/script-allow-credentials.php' to 'http://127.0.0.1:8000/security/resources/script-allow-credentials.php' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/localScript.js' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/script-allow-star.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://localhost:8000/security/resources/script-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-redirect.php?mode=no&url=http://127.0.0.1:8000/security/resources/script-allow-credentials.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Testing the handling of CORS-enabled
 
 PASS/FAIL descriptions are of the form, 'CORS request type': 'redirect CORS type' => 'resource'
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-onerror-crossorigin-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-onerror-crossorigin-no-cors-expected.txt
index 5b40877..547202d6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-onerror-crossorigin-no-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-onerror-crossorigin-no-cors-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/cors-script.php?fail=true&cors=false' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-script.php?fail=true&cors=false' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 The test passes if 'window.onerror' is not invoked on a script loaded with a 'crossorigin' attribute, but delivered without valid CORS headers.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/script-with-failed-cors-check-fails-to-load-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/script-with-failed-cors-check-fails-to-load-expected.txt
index 4b3e10415..13fd048 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/script-with-failed-cors-check-fails-to-load-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/script-with-failed-cors-check-fails-to-load-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8080/security/resources/alert-fail.js' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8080/security/resources/alert-fail.js' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 This test passes if the script does not load.
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/subresource-integrity-script-no-cors-bad-integrity-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/subresource-integrity-script-no-cors-bad-integrity-expected.txt
index c840e51..9a8fa93 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/subresource-integrity-script-no-cors-bad-integrity-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/subresource-integrity-script-no-cors-bad-integrity-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&value=ran2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to script at 'http://localhost:8000/security/resources/cors-script.php?cors=false&value=ran2' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 This is a testharness.js-based test.
 PASS SRI on cross origin CORS disabled script, with bad integrity
 Harness: the test ran to completion.
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/text-track-crossorigin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/text-track-crossorigin-expected.txt
index 46ef797..d6ff2a4 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/text-track-crossorigin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/text-track-crossorigin-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE ERROR: Text track from origin 'http://localhost:8000' has been blocked from loading: Not at same origin as the document, and parent of track element does not have a 'crossorigin' attribute. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Access to Text track at 'http://localhost:8000/security/resources/captions-with-access-control-headers.php?count=0' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to text track at 'http://localhost:8000/security/resources/captions-with-access-control-headers.php?count=0' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 CONSOLE ERROR: Text track from origin 'http://localhost:8000' has been blocked from loading: Not at same origin as the document, and parent of track element does not have a 'crossorigin' attribute. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
 Tests loading cross-domain <track>.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash-expected.txt
index 450f57f8..cf80ac7 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash-expected.txt
@@ -1,2 +1,2 @@
-CONSOLE ERROR: Access to Image at 'http://localhost:8080/misc/resources/compass.jpg' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to image at 'http://localhost:8080/misc/resources/compass.jpg' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 >>>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash2-expected.txt
index f1bf486..9f627c58 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/video-poster-cross-origin-crash2-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Access to Image at 'http://localhost:8080/nonesuch.png' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. The response had HTTP status code 404.
+CONSOLE ERROR: Access to image at 'http://localhost:8080/nonesuch.png' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test passes if it doesn't crash.
 
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-no-credential-prompt-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-no-credential-prompt-expected.txt
index 1ee0dfd..49e9e60 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-no-credential-prompt-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-no-credential-prompt-expected.txt
@@ -1,2 +1,2 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/basic-auth/basic-auth.php?uid=41531: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access. The response had HTTP status code 401.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/basic-auth/basic-auth.php?uid=41531' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 There should be no authentication prompt displayed, since this is a cross-origin request. In automatic mode, the test relies on logging of authentication sheets.
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
index 991ed31..a18432e1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
@@ -1,16 +1,16 @@
 CONSOLE WARNING: line 8: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-expected.txt
index a549a52..4c806ebf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-expected.txt
@@ -1,3 +1,3 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 PASS
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-2-expected.txt
index f05c29b..456dd8f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-2-expected.txt
@@ -1,4 +1,4 @@
 CONSOLE WARNING: line 48: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 50: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 50: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 PASS
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-expected.txt
index 9faf1f1..011473bb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/cross-site-denied-response-sync-expected.txt
@@ -1,4 +1,4 @@
 CONSOLE WARNING: line 53: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 55: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 55: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 PASS
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/onerror-event-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/onerror-event-expected.txt
index d46bab5b..b8dbc2f9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/onerror-event-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/onerror-event-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-basic-denied.cgi: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/access-control-basic-denied.cgi' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 This test that the error event is fired for XMLHttpRequests
 
 PASS: error event fired.
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/ontimeout-event-override-after-failure-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/ontimeout-event-override-after-failure-expected.txt
index 43b3133..1bb79e4 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/ontimeout-event-override-after-failure-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/ontimeout-event-override-after-failure-expected.txt
@@ -1,3 +1,3 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-basic-denied.cgi: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/access-control-basic-denied.cgi' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 PASS: Timeout override did not reactivate timer after failure
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling-expected.txt
index 33a9df0..27e1fe3b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling-expected.txt
@@ -1,13 +1,13 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/test.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/test.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 XMLHttpRequest doesn't crash even when open() is invoked synchronously to handling of a response to a cross-origin request.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling-expected.txt
index 01c3f5c4..2d876c1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling-expected.txt
@@ -1,13 +1,13 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 XMLHttpRequest doesn't crash even when open() is invoked synchronously to handling of an invalid preflight response.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
index 695a65e3..852fd959 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
@@ -1,13 +1,13 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' to 'http://localhost:8000/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 XMLHttpRequest doesn't crash even when open() is invoked synchronously to handling of a redirect response to a cross-origin request.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/07-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/07-expected.txt
index 3104bad..9e29b8b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/07-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/07-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fwww2.localhost%3A8000: The 'Access-Control-Allow-Origin' header has a value 'http://www2.localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fwww2.localhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://www2.localhost:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/08-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/08-expected.txt
index dd5a13ce..9a93023 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/08-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/08-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains the invalid value '//localhost:8000'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '//localhost:8000'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/09-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/09-expected.txt
index d49d549..040ddda 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/09-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/09-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains the invalid value '://localhost:8000'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '://localhost:8000'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/10-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/10-expected.txt
index 705914312..17f11d1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/10-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/10-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=ftp%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header has a value 'ftp://localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=ftp%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'ftp://localhost:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/11-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/11-expected.txt
index 4edaa97c..e692777 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/11-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/11-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains the invalid value 'http:://localhost:8000'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value 'http:://localhost:8000'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/12-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/12-expected.txt
index dc7beeb0..d849ceb1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/12-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/12-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header has a value 'http:/localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http:/localhost:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/13-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/13-expected.txt
index d222a61..bb54efc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/13-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/13-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3Alocalhost%3A8000: The 'Access-Control-Allow-Origin' header has a value 'http:localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3Alocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http:localhost:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/14-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/14-expected.txt
index 947071c..d346bfaf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/14-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/14-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=localhost%3A8000: The 'Access-Control-Allow-Origin' header has a value 'localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=localhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'localhost:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/15-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/15-expected.txt
index a1a3612..da126ea 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/15-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/15-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%3F: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000?' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%3F' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000?' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/16-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/16-expected.txt
index 901af71..2e0f21f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/16-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/16-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2F: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2F' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/17-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/17-expected.txt
index abc57e3..dcd472f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/17-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/17-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%20%2F: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8000 /', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%20%2F' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8000 /', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/18-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/18-expected.txt
index 0fbbeb7..108592d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/18-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/18-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%23: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000#' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%23' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000#' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/19-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/19-expected.txt
index 79589c8..f19e2fdf 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/19-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/19-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2523: The 'Access-Control-Allow-Origin' header contains the invalid value 'http://localhost:8000%23'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2523' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value 'http://localhost:8000%23'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/20-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/20-expected.txt
index 8f69ba3..1ef884fe 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/20-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/20-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%3A80: The 'Access-Control-Allow-Origin' header contains the invalid value 'http://localhost:8000:80'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%3A80' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value 'http://localhost:8000:80'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/21-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/21-expected.txt
index bd64b1f5..37e331bc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/21-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/21-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2C%20*: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8000, *', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2C%20*' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8000, *', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/22-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/22-expected.txt
index ece4e563..47fb6a1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/22-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/22-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%00: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%00' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/23-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/23-expected.txt
index 1751337f..61bf5dcb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/23-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/23-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=HTTP%3A%2F%2FLOCALHOST%3A8000: The 'Access-Control-Allow-Origin' header has a value 'HTTP://LOCALHOST:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=HTTP%3A%2F%2FLOCALHOST%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'HTTP://LOCALHOST:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/24-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/24-expected.txt
index 85a5577c..d7d3ec5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/24-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/24-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=HTTP%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header has a value 'HTTP://localhost:8000' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=HTTP%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'HTTP://localhost:8000' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/25-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/25-expected.txt
index 20b1cac..b89fe6d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/25-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/25-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=-: The 'Access-Control-Allow-Origin' header contains the invalid value '-'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=-' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '-'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/26-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/26-expected.txt
index 10ce2665..3aea299 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/26-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/26-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=**: The 'Access-Control-Allow-Origin' header contains the invalid value '**'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=**' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '**'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/27-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/27-expected.txt
index 9465f1d..2a1990b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/27-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/27-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%00*: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%00*' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/28-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/28-expected.txt
index c56dd05..eb43d80f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/28-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/28-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%00: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%00' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/29-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/29-expected.txt
index d7cf512c..51a44ad 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/29-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/29-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%27*%27: The 'Access-Control-Allow-Origin' header contains the invalid value ''*''. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%27*%27' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value ''*''.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/30-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/30-expected.txt
index 46998df3..e7c33b8 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/30-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/30-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%22*%22: The 'Access-Control-Allow-Origin' header contains the invalid value '"*"'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%22*%22' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '"*"'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/31-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/31-expected.txt
index cbfbbc47..437f71c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/31-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/31-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%20*: The 'Access-Control-Allow-Origin' header contains multiple values '* *', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%20*' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '* *', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/32-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/32-expected.txt
index 1293e18..35886dc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/32-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/32-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*http%3A%2F%2F*: The 'Access-Control-Allow-Origin' header contains the invalid value '*http://*'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*http%3A%2F%2F*' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '*http://*'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/33-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/33-expected.txt
index b6eea2e7..553a1a9 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/33-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/33-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains the invalid value '*http://localhost:8000'. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value '*http://localhost:8000'.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/34-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/34-expected.txt
index 43caa70..f359b51 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/34-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/34-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%20http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values '* http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%20http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '* http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/35-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/35-expected.txt
index b99ee5fa..9d31f17f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/35-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/35-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%2C%20http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=*%2C%20http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/36-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/36-expected.txt
index e92ff09..ff6118e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/36-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/36-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%00http%3A%2F%2Flocalhost%3A8000: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=%00http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/37-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/37-expected.txt
index c18c4e8..36de428 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/37-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/37-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=null%20http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values 'null http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=null%20http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'null http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/38-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/38-expected.txt
index aa3254c..3bf0449 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/38-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/38-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fexample.net: The 'Access-Control-Allow-Origin' header has a value 'http://example.net' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fexample.net' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://example.net' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/39-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/39-expected.txt
index ec786bdf..dec68905 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/39-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/39-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fexample.net%20http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values 'http://example.net http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fexample.net%20http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://example.net http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/40-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/40-expected.txt
index 8f09933..6cba0aac 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/40-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/40-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fexample.net%2C%20http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values 'http://example.net, http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Fexample.net%2C%20http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://example.net, http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/41-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/41-expected.txt
index 6a07755..3900d3a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/41-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/41-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origins=http%3A%2F%2Fexample.net,http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values 'http://example.net, http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origins=http%3A%2F%2Fexample.net,http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://example.net, http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/42-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/42-expected.txt
index 27c13e1..c0603b0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/42-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/42-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origins=http%3A%2F%2Flocalhost%3A8000,http%3A%2F%2Flocalhost%3A8000: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8000, http://localhost:8000', but only one is allowed. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origins=http%3A%2F%2Flocalhost%3A8000,http%3A%2F%2Flocalhost%3A8000' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'http://localhost:8000, http://localhost:8000', but only one is allowed.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/43-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/43-expected.txt
index 7e36415..59dd0a37 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/43-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/43-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=null: The 'Access-Control-Allow-Origin' header has a value 'null' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=null' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'null' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/44-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/44-expected.txt
index ab3efc8..03641231 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/44-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/44-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=: The 'Access-Control-Allow-Origin' header contains the invalid value ''. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains the invalid value ''.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/45-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/45-expected.txt
index 7bda2cc9..095a3e1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/45-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/45-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2Fxmlhttprequest%2Fresources%2Forigin-exact-matching-iframe.html%3F45: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/xmlhttprequest/resources/origin-exact-matching-iframe.html?45' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2Fxmlhttprequest%2Fresources%2Forigin-exact-matching-iframe.html%3F45' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/xmlhttprequest/resources/origin-exact-matching-iframe.html?45' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/46-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/46-expected.txt
index 47053e8..60209bc 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/46-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/46-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2Fxmlhttprequest%2Fresources%2F: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/xmlhttprequest/resources/' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2Fxmlhttprequest%2Fresources%2F' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/xmlhttprequest/resources/' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/47-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/47-expected.txt
index 210e6d2..0129e496 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/47-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-exact-matching/47-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 24: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 1: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2Fxmlhttprequest%2Fresources%2Forigin-exact-matching-iframe.html%3F47: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/xmlhttprequest/resources/origin-exact-matching-iframe.html?47' that is not equal to the supplied origin. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/access-control-allow-lists.php?origin=http%3A%2F%2Flocalhost%3A8000%2Fxmlhttprequest%2Fresources%2Forigin-exact-matching-iframe.html%3F47' from origin 'http://localhost:8000' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:8000/xmlhttprequest/resources/origin-exact-matching-iframe.html?47' that is not equal to the supplied origin.
 
 
 --------
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt
index e631929..64cc5d5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-https-expected.txt
@@ -1,6 +1,6 @@
 CONSOLE WARNING: line 18: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 20: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt?sync: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt?async: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 20: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt?sync' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt?async' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Tests that origin whitelisting for https does not match http URLs.
 
 Testing: http://localhost:8000/xmlhttprequest/resources/get.txt (sync)
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt
index 8b2566e..6dac77a 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-ip-addresses-with-subdomains-expected.txt
@@ -1,6 +1,6 @@
 CONSOLE WARNING: line 14: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 16: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://127.0.0.1:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access.
+CONSOLE ERROR: line 16: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/get.txt' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://127.0.0.1:8000/xmlhttprequest/resources/get.txt' from origin 'http://localhost:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Specifying that an IP address should match subdomains doesn't make sense. This test verifies that it doesn't do anything.
 
 Testing: http://127.0.0.1:8000/xmlhttprequest/resources/get.txt (sync)
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-removal-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-removal-expected.txt
index 81621e2..41ce841 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-removal-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/origin-whitelisting-removal-expected.txt
@@ -1,12 +1,12 @@
 CONSOLE WARNING: line 17: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 19: Failed to load http://localhost:8000/xmlhttprequest/resources/get.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 19: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/get.txt' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Tests the behavior of whitelisting origins and removing them later.
 
 Testing: source origin: http://127.0.0.1:8000 destination origin: http:localhost 
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt
index 8dd1dce..a5f6b2ea 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-async-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-allow-lists.php: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/access-control-allow-lists.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test verifies that content MIME type is set correctly when Blob is sent using XMLHttpRequest asynchronously.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt
index 7281292..353c26c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/post-blob-content-type-sync-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 49: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 52: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-allow-lists.php: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 52: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/access-control-allow-lists.php' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test verifies that content MIME type is set correctly when Blob is sent using XMLHttpRequest synchronously.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-2-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-2-expected.txt
index c8910a2..1c7f53d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-2-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/reply.xml') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-expected.txt
index c8910a2..1c7f53d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/reply.xml') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-expected.txt
index ed93a6c..0774721 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/reply.xml') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-sync-expected.txt
index f380eaad..ed072a9c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-sync-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-post-sync-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 30: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 31: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 31: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/reply.xml') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
index adb03c3..df69073b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 25: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 26: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml: Redirect from 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml' to 'http://localhost:8000/xmlhttprequest/resources/reply.xml' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 26: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin chain of redirects to a server that responds is indistinguishable from one that does not. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-expected.txt
index 28fa719..309b022 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-sync-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 25: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 26: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 26: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8000/xmlhttprequest/resources/reply.xml') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin redirect to a server that responds is indistinguishable from one that does not. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-tripmine-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-tripmine-expected.txt
index ec2f7afa..75806cdb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-tripmine-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/redirect-cross-origin-tripmine-expected.txt
@@ -1,24 +1,24 @@
 CONSOLE WARNING: line 21: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: line 1: Failed to load http://localhost:8000/resources/tripmine.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=303&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=303&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=302&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=302&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=301&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=301&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=301&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=303&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=303&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=302&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=302&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=307&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=301&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=301&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: line 1: Access to XMLHttpRequest at 'http://localhost:8000/resources/tripmine.php' (redirected from 'http://127.0.0.1:8000/resources/redirect.php?code=301&url=http://localhost:8000/resources/tripmine.php') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a cross-origin redirect does not result in a non-simple request being sent to the target.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-expected.txt
index 6dcf331..992297c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a simple cross-origin request to a server that responds (but does not permit cross-origin requests) is indistinguishable from one that does not exist. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-expected.txt
index 59b8f4f..6be3108 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a simple cross-origin request to a server that responds (but does not permit cross-origin requests) is indistinguishable from one that does not exist. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-sync-expected.txt
index 37f4263..71aa531 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-sync-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-post-sync-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 30: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 32: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 32: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a simple cross-origin request to a server that responds (but does not permit cross-origin requests) is indistinguishable from one that does not exist. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-sync-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-sync-expected.txt
index 835f11a..65fcbc4f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-sync-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-denied-events-sync-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 25: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 26: Failed to load http://localhost:8000/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 26: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/reply.xml' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that a simple cross-origin request to a server that responds (but does not permit cross-origin requests) is indistinguishable from one that does not exist. Should say PASS:
 
 PASS
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-progress-events-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-progress-events-expected.txt
index c34b512..1932402 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-progress-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/simple-cross-origin-progress-events-expected.txt
@@ -1,5 +1,5 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/cross-site-progress-events.cgi: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/cross-site-progress-events.cgi: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/cross-site-progress-events.cgi' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/cross-site-progress-events.cgi' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test that upload progress events are not dispatched for simple cross-origin requests (i.e. if the listener is set after calling send(), and there are no other reasons to make a preflight request).
 
 Test 1: The URL is allowed for cross-origin requests
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/upload-request-error-event-order-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/upload-request-error-event-order-expected.txt
index 3c435c1..a8a5912c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/upload-request-error-event-order-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/upload-request-error-event-order-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/cross-site-progress-events.cgi: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/cross-site-progress-events.cgi' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test to validate the order in which the events are fired in case of a request error.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt
index f820d73..e94261c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/access-control-basic-get-fail-non-simple-expected.txt
@@ -1,4 +1,4 @@
-CONSOLE ERROR: line 37: Failed to load http://localhost:8000/xmlhttprequest/resources/access-control-basic-get-fail-non-simple.cgi: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 37: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/resources/access-control-basic-get-fail-non-simple.cgi' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 GET should not trigger a preflight request from a worker unless it has non-simple headers.
 
 PASS: Cross-domain access allowed for simple get.
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
index 4c171e65..086a854 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
@@ -1,15 +1,15 @@
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 29: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 29: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt
index c3e4ac95..4a45f7fc1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events-expected.txt
@@ -1,5 +1,5 @@
 CONSOLE WARNING: line 18: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 35: Failed to load http://localhost:8000/xmlhttprequest/xmlhttprequest-sync-vs-async-assertion-failure.html: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 35: Access to XMLHttpRequest at 'http://localhost:8000/xmlhttprequest/xmlhttprequest-sync-vs-async-assertion-failure.html' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 Test for:
 
 bug 40996: Progress event should not be fired during synchronous XMLHttpRequest;
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect-expected.txt b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect-expected.txt
index 73ddf4b..4c1fd95 100644
--- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/xmlhttprequest-unsafe-redirect-expected.txt
@@ -1,6 +1,6 @@
 CONSOLE WARNING: line 52: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 54: Failed to load http://localhost:8080/xmlhttprequest/resources/forbidden.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8080/xmlhttprequest/resources/forbidden.txt: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
+CONSOLE ERROR: line 54: Access to XMLHttpRequest at 'http://localhost:8080/xmlhttprequest/resources/forbidden.txt' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8080/xmlhttprequest/resources/forbidden.txt') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
+CONSOLE ERROR: Access to XMLHttpRequest at 'http://localhost:8080/xmlhttprequest/resources/forbidden.txt' (redirected from 'http://127.0.0.1:8000/xmlhttprequest/resources/redirect.php?url=http://localhost:8080/xmlhttprequest/resources/forbidden.txt') from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
 This tests that unsafe redirects won't be allowed when making an XMLHttpRequest.
 Sync XHR started.
 readyState change 1
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png
index f314a8d..deea223e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.txt
index 4ad9e5f..ae04ec1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/input-appearance-height-expected.txt
@@ -76,10 +76,10 @@
         LayoutBR {BR} at (107,194) size 0x0
         LayoutText {#text} at (0,201) size 49x19
           text run at (0,201) width 49: "isindex "
-        LayoutTextControl {INPUT} at (49,200) size 183x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
-        LayoutText {#text} at (232,201) size 4x19
-          text run at (232,201) width 4: " "
-        LayoutBR {BR} at (236,216) size 0x0
+        LayoutTextControl {INPUT} at (49,200) size 181x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+        LayoutText {#text} at (230,201) size 4x19
+          text run at (230,201) width 4: " "
+        LayoutBR {BR} at (234,216) size 0x0
         LayoutText {#text} at (0,223) size 64x19
           text run at (0,223) width 64: "password "
         LayoutTextControl {INPUT} at (64,222) size 181x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
@@ -96,8 +96,8 @@
   LayoutBlockFlow {DIV} at (2,3) size 177x16
 layer at (37,53) size 177x16
   LayoutBlockFlow {DIV} at (2,3) size 177x16
-layer at (60,231) size 177x16
-  LayoutBlockFlow {DIV} at (3,3) size 177x16
+layer at (59,231) size 177x16
+  LayoutBlockFlow {DIV} at (2,3) size 177x16
 layer at (74,253) size 177x16
   LayoutBlockFlow {DIV} at (2,3) size 177x16
 layer at (55,275) size 164x16
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt
deleted file mode 100644
index 7386346..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-same-origin-post-async-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-same-origin-post-async-expected.txt
deleted file mode 100644
index 85f9a5c..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-same-origin-post-async-expected.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png
index 513a2a80..fdba5057 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.txt
index d5fb380..b5d6e7f2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/input-appearance-height-expected.txt
@@ -76,10 +76,10 @@
         LayoutBR {BR} at (104,194) size 0x0
         LayoutText {#text} at (0,201) size 45x19
           text run at (0,201) width 45: "isindex "
-        LayoutTextControl {INPUT} at (45,200) size 175x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
-        LayoutText {#text} at (220,201) size 4x19
-          text run at (220,201) width 4: " "
-        LayoutBR {BR} at (224,216) size 0x0
+        LayoutTextControl {INPUT} at (45,200) size 173x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
+        LayoutText {#text} at (218,201) size 4x19
+          text run at (218,201) width 4: " "
+        LayoutBR {BR} at (222,216) size 0x0
         LayoutText {#text} at (0,223) size 63x19
           text run at (0,223) width 63: "password "
         LayoutTextControl {INPUT} at (63,222) size 173x22 [bgcolor=#FFFFFF] [border: (2px inset #EEEEEE)]
@@ -96,8 +96,8 @@
   LayoutBlockFlow {DIV} at (2,3) size 169x16
 layer at (36,53) size 169x16
   LayoutBlockFlow {DIV} at (2,3) size 169x16
-layer at (56,231) size 169x16
-  LayoutBlockFlow {DIV} at (3,3) size 169x16
+layer at (55,231) size 169x16
+  LayoutBlockFlow {DIV} at (2,3) size 169x16
 layer at (73,253) size 169x16
   LayoutBlockFlow {DIV} at (2,3) size 169x16
 layer at (54,275) size 156x16
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/xhr/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/xhr/README.txt
new file mode 100644
index 0000000..25c7135
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/external/wpt/xhr/README.txt
@@ -0,0 +1,3 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "http/tests/fetch" directory for testing fetch with CORS.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
index 65df437..45a0a6b9 100644
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
@@ -1,16 +1,16 @@
 CONSOLE WARNING: line 8: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
deleted file mode 100644
index 5e6e463..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-XMLHttpRequest doesn't crash even when open() is invoked synchronously to handling of a redirect response to a cross-origin request.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt
deleted file mode 100644
index 7386346..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-get-sync-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt
deleted file mode 100644
index 7386346..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt
deleted file mode 100644
index 7386346..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
deleted file mode 100644
index ce34f64..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CONSOLE WARNING: line 25: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 26: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-Test that a cross-origin chain of redirects to a server that responds is indistinguishable from one that does not. Should say PASS:
-
-PASS
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
index 17984a9..785ec72 100644
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors-ns/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
@@ -1,15 +1,15 @@
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/external/wpt/xhr/README.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/external/wpt/xhr/README.txt
new file mode 100644
index 0000000..25c7135
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/external/wpt/xhr/README.txt
@@ -0,0 +1,3 @@
+This directory is for testing out-of-blink CORS implementation.
+
+We use "http/tests/fetch" directory for testing fetch with CORS.
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
index 65df437..45a0a6b9 100644
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/cross-origin-unsupported-url-expected.txt
@@ -1,16 +1,16 @@
 CONSOLE WARNING: line 8: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
deleted file mode 100644
index 5e6e463..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-CONSOLE ERROR: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-XMLHttpRequest doesn't crash even when open() is invoked synchronously to handling of a redirect response to a cross-origin request.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt
deleted file mode 100644
index 7386346..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-cross-origin-post-sync-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt
deleted file mode 100644
index 7386346..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/origin-header-same-origin-post-sync-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-CONSOLE WARNING: line 13: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-PASS: Cross-domain access allowed.
-HTTP_ORIGIN: http://127.0.0.1:8000
-
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
deleted file mode 100644
index ce34f64..0000000
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/redirect-cross-origin-sync-double-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-CONSOLE WARNING: line 25: Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.
-CONSOLE ERROR: line 26: Failed to load http://localhost:8000/xmlhttprequest/resources/redirect.php?url=/xmlhttprequest/resources/reply.xml: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8000' is therefore not allowed access.
-Test that a cross-origin chain of redirects to a server that responds is indistinguishable from one that does not. Should say PASS:
-
-PASS
-
diff --git a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
index 17984a9..785ec72 100644
--- a/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/outofblink-cors/http/tests/xmlhttprequest/workers/cross-origin-unsupported-url-expected.txt
@@ -1,15 +1,15 @@
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: line 13: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load mailto:foo@bar.com: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load localhost:8080/: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
-CONSOLE ERROR: Failed to load tel:1234: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: line 13: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'mailto:foo@bar.com' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'localhost:8080/' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
+CONSOLE ERROR: Access to XMLHttpRequest at 'tel:1234' from origin 'http://127.0.0.1:8000' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, https.
 This is a testharness.js-based test.
 PASS sync test for url=mailto:foo@bar.com, contentType=undefined
 PASS sync test for url=mailto:foo@bar.com, contentType=application/json
diff --git a/third_party/WebKit/LayoutTests/virtual/video-surface-layer/external/wpt/picture-in-picture/idlharness.window-expected.txt b/third_party/WebKit/LayoutTests/virtual/video-surface-layer/external/wpt/picture-in-picture/idlharness.window-expected.txt
index 0c0c0659..43a7519 100644
--- a/third_party/WebKit/LayoutTests/virtual/video-surface-layer/external/wpt/picture-in-picture/idlharness.window-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/video-surface-layer/external/wpt/picture-in-picture/idlharness.window-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+PASS idlharness
 PASS picture-in-picture interfaces.
 PASS Partial interface HTMLVideoElement: original interface defined
 PASS Partial interface Document: original interface defined
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 4020663..0c26b9f 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -7262,6 +7262,14 @@
     attribute @@toStringTag
     method constructor
     method toString
+interface TrustedTypePolicy
+    attribute @@toStringTag
+    getter name
+    method constructor
+interface TrustedTypePolicyFactory
+    attribute @@toStringTag
+    method constructor
+    method createPolicy
 interface TrustedURL
     static method create
     static method unsafelyCreate
@@ -10441,6 +10449,7 @@
     getter statusbar
     getter styleMedia
     getter toolbar
+    getter trustedTypes
     getter visualViewport
     getter webgpu
     getter webkitStorageInfo
diff --git a/third_party/blink/perf_tests/layout/change-text-css-contain.html b/third_party/blink/perf_tests/layout/change-text-css-contain.html
new file mode 100644
index 0000000..4a9c913
--- /dev/null
+++ b/third_party/blink/perf_tests/layout/change-text-css-contain.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<style>
+body {
+  display: grid;
+  grid: repeat(100, 30px) / repeat(100, 60px);
+}
+
+span {
+  border: solid;
+  width: 60px;
+  height: 30px;
+  box-sizing: border-box;
+  contain: size layout;
+  line-height: 1;
+}
+</style>
+<script src="../resources/runner.js"></script>
+<script>
+  let textNodes = [];
+
+  function populateData() {
+    for (let i = 0; i < 100*100; i++) {
+      let span = document.createElement('span');
+      span.classList.add('cell');
+      let textNode = document.createTextNode('' + (100 * Math.random()).toFixed(2));
+      span.appendChild(textNode);
+      document.body.appendChild(span);
+      textNodes.push(textNode);
+    }
+  }
+
+  function startTest() {
+    populateData();
+
+    PerfTestRunner.forceLayout();
+
+    PerfTestRunner.measureRunsPerSecond({
+      description: "Measures performance of changing text nodes content.",
+      run: function() {
+        for (let i = 0; i < textNodes.length; i++) {
+          textNodes[i].data = '' + (100 * Math.random()).toFixed(2);
+        }
+
+        PerfTestRunner.forceLayout();
+      },
+    });
+  }
+</script>
+<body onload="startTest();">
+</body>
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index ea32357e..aeaecc9 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -78,6 +78,7 @@
   BLINK_PLATFORM_EXPORT static void EnableBlinkHeapIncrementalMarking(bool);
   BLINK_PLATFORM_EXPORT static void EnableBloatedRendererDetection(bool);
   BLINK_PLATFORM_EXPORT static void EnableCacheInlineScriptCode(bool);
+  BLINK_PLATFORM_EXPORT static void EnableIsolatedCodeCache(bool);
   BLINK_PLATFORM_EXPORT static void EnableCanvas2dImageChromium(bool);
   BLINK_PLATFORM_EXPORT static void EnableCSSHexAlphaColor(bool);
   BLINK_PLATFORM_EXPORT static void EnableCSSFragmentIdentifiers(bool);
diff --git a/third_party/blink/public/web/web_print_params.h b/third_party/blink/public/web/web_print_params.h
index 11ec70a..1809e25 100644
--- a/third_party/blink/public/web/web_print_params.h
+++ b/third_party/blink/public/web/web_print_params.h
@@ -49,7 +49,7 @@
   WebSize paper_size;
 
   // Specifies user selected DPI for printing.
-  int printer_dpi;
+  int printer_dpi = 72;
 
   // Specifies the scale factor in percent. 100 is 1:1 (default scaling).
   int scale_factor = 100;
@@ -59,48 +59,26 @@
 
   // Specifies whether to reduce/enlarge/retain the print contents to fit the
   // printable area. (This is used only by plugin printing).
-  WebPrintScalingOption print_scaling_option;
+  WebPrintScalingOption print_scaling_option =
+      kWebPrintScalingOptionFitToPrintableArea;
 
   // Specifies whether printing layout needs to be applied.
-  bool use_printing_layout;
+  bool use_printing_layout = true;
 
   // Specifies how many pages per sheet. This parameter is for N-up mode.
-  size_t pages_per_sheet;
+  size_t pages_per_sheet = 1;
 
-  WebPrintParams()
-      : printer_dpi(72),
-        print_scaling_option(kWebPrintScalingOptionFitToPrintableArea),
-        use_printing_layout(true),
-        pages_per_sheet(1) {}
+  WebPrintParams() = default;
 
   WebPrintParams(const WebSize& paper_size)
       : WebPrintParams(paper_size, true) {}
 
   WebPrintParams(const WebSize& paper_size, bool use_printing_layout)
       : print_content_area(WebRect(0, 0, paper_size.width, paper_size.height)),
-        printable_area(WebRect(0, 0, paper_size.width, paper_size.height)),
+        printable_area(print_content_area),
         paper_size(paper_size),
-        printer_dpi(72),
         print_scaling_option(kWebPrintScalingOptionSourceSize),
-        use_printing_layout(use_printing_layout),
-        pages_per_sheet(1) {}
-
-  WebPrintParams(const WebRect& print_content_area,
-                 const WebRect& printable_area,
-                 const WebSize& paper_size,
-                 int printer_dpi,
-                 int scale_factor,
-                 WebPrintScalingOption print_scaling_option,
-                 bool use_printing_layout,
-                 int pages_per_sheet)
-      : print_content_area(print_content_area),
-        printable_area(printable_area),
-        paper_size(paper_size),
-        printer_dpi(printer_dpi),
-        scale_factor(scale_factor),
-        print_scaling_option(print_scaling_option),
-        use_printing_layout(use_printing_layout),
-        pages_per_sheet(pages_per_sheet) {}
+        use_printing_layout(use_printing_layout) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
index 83a66393..3ce2910 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_initializer.cc
@@ -552,8 +552,7 @@
 
   v8::Local<v8::WasmCompiledModule> module =
       v8::Local<v8::WasmCompiledModule>::Cast(source);
-  if (static_cast<size_t>(module->GetWasmWireBytes()->Length()) >
-      kWasmWireBytesLimit) {
+  if (module->GetWasmWireBytesRef().size > kWasmWireBytesLimit) {
     ThrowRangeException(
         args.GetIsolate(),
         "WebAssembly.Instance is disallowed on the main thread, "
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl.cc b/third_party/blink/renderer/controller/oom_intervention_impl.cc
index 4d9b60c7..139e8a2 100644
--- a/third_party/blink/renderer/controller/oom_intervention_impl.cc
+++ b/third_party/blink/renderer/controller/oom_intervention_impl.cc
@@ -185,6 +185,7 @@
       // mojo strong binding is disconnected.
       pauser_.reset(new ScopedPagePauser);
     }
+    timer_.Stop();
   }
 
   OomInterventionMetrics* metrics_shared =
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl.h b/third_party/blink/renderer/controller/oom_intervention_impl.h
index 4d548e15..8227bf6 100644
--- a/third_party/blink/renderer/controller/oom_intervention_impl.h
+++ b/third_party/blink/renderer/controller/oom_intervention_impl.h
@@ -39,6 +39,9 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(OomInterventionImplTest, DetectedAndDeclined);
   FRIEND_TEST_ALL_PREFIXES(OomInterventionImplTest, CalculateProcessFootprint);
+  FRIEND_TEST_ALL_PREFIXES(OomInterventionImplTest, StopWatchingAfterDetection);
+  FRIEND_TEST_ALL_PREFIXES(OomInterventionImplTest,
+                           ContinueWatchingWithoutDetection);
 
   void Check(TimerBase*);
 
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl_test.cc b/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
index b49e173..3cc5976 100644
--- a/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
+++ b/third_party/blink/renderer/controller/oom_intervention_impl_test.cc
@@ -177,6 +177,34 @@
   EXPECT_FALSE(page->Paused());
 }
 
+TEST_F(OomInterventionImplTest, StopWatchingAfterDetection) {
+  OomInterventionMetrics mock_metrics = {};
+  // Set value more than the threshold to trigger intervention.
+  mock_metrics.current_blink_usage_kb = (kTestBlinkThreshold / 1024) + 1;
+  mock_metrics.current_private_footprint_kb = (kTestPMFThreshold / 1024) - 1;
+  mock_metrics.current_swap_kb = (kTestSwapThreshold / 1024) - 1;
+  mock_metrics.current_vm_size_kb = (kTestVmSizeThreshold / 1024) - 1;
+  intervention_->SetMetrics(mock_metrics);
+
+  DetectOnceOnBlankPage();
+
+  EXPECT_FALSE(intervention_->timer_.IsActive());
+}
+
+TEST_F(OomInterventionImplTest, ContinueWatchingWithoutDetection) {
+  OomInterventionMetrics mock_metrics = {};
+  // Set value less than the threshold to not trigger intervention.
+  mock_metrics.current_blink_usage_kb = (kTestBlinkThreshold / 1024) - 1;
+  mock_metrics.current_private_footprint_kb = (kTestPMFThreshold / 1024) - 1;
+  mock_metrics.current_swap_kb = (kTestSwapThreshold / 1024) - 1;
+  mock_metrics.current_vm_size_kb = (kTestVmSizeThreshold / 1024) - 1;
+  intervention_->SetMetrics(mock_metrics);
+
+  DetectOnceOnBlankPage();
+
+  EXPECT_TRUE(intervention_->timer_.IsActive());
+}
+
 TEST_F(OomInterventionImplTest, CalculateProcessFootprint) {
   const char kStatusFile[] =
       "First:  1\n Second: 2 kB\nVmSwap: 10 kB \n Third: 10 kB\n Last: 8";
diff --git a/third_party/blink/renderer/core/animation/css/css_animations.cc b/third_party/blink/renderer/core/animation/css/css_animations.cc
index b78f42e..47c3e13 100644
--- a/third_party/blink/renderer/core/animation/css/css_animations.cc
+++ b/third_party/blink/renderer/core/animation/css/css_animations.cc
@@ -502,10 +502,11 @@
     animation->SetCompositorPending(true);
 
   for (const auto& entry : pending_update_.AnimationsWithUpdates()) {
-    KeyframeEffect* effect = ToKeyframeEffect(entry.animation->effect());
-
-    effect->SetModel(entry.effect->Model());
-    effect->UpdateSpecifiedTiming(entry.effect->SpecifiedTiming());
+    if (entry.animation->effect()) {
+      KeyframeEffect* effect = ToKeyframeEffect(entry.animation->effect());
+      effect->SetModel(entry.effect->Model());
+      effect->UpdateSpecifiedTiming(entry.effect->SpecifiedTiming());
+    }
 
     running_animations_[entry.index]->Update(entry);
   }
diff --git a/third_party/blink/renderer/core/core_idl_files.gni b/third_party/blink/renderer/core/core_idl_files.gni
index da0063a..cb2afa4 100644
--- a/third_party/blink/renderer/core/core_idl_files.gni
+++ b/third_party/blink/renderer/core/core_idl_files.gni
@@ -136,6 +136,8 @@
                     "trustedtypes/trusted_html.idl",
                     "trustedtypes/trusted_script_url.idl",
                     "trustedtypes/trusted_url.idl",
+                    "trustedtypes/trusted_type_policy.idl",
+                    "trustedtypes/trusted_type_policy_factory.idl",
                     "editing/selection.idl",
                     "events/animation_event.idl",
                     "events/animation_playback_event.idl",
diff --git a/third_party/blink/renderer/core/css/themeWin.css b/third_party/blink/renderer/core/css/themeWin.css
index 2616d89e..ed659ee 100644
--- a/third_party/blink/renderer/core/css/themeWin.css
+++ b/third_party/blink/renderer/core/css/themeWin.css
@@ -32,13 +32,12 @@
    WebCore/css/html.css. So far we have used this file exclusively for
    making our form elements match Firefox's. */
 
-input:not([type]), 
-input[type="email" i],
-input[type="number" i],
-input[type="password" i],
-input[type="tel" i],
-input[type="url" i],
-input[type="text" i] {
+/*
+ * Update padding for all text-like types including unknown types.
+ * Non-text types have input[type="foo" i] with padding properties in
+ * html.css or themeInputMultipleFields.css.
+ */
+input {
     padding:1px 0;
 }
 
@@ -58,30 +57,25 @@
     color: #c4c4c4;
 }
 
-/* Not sure this is the right color. #EBEBE4 is what Firefox uses.
-   FIXME: Figure out how to support legacy input rendering. 
-   FIXME: Add input[type="file" i] once we figure out our file inputs.
-   FIXME: Add input[type="image" i] once we figure out our image inputs.
-   FIXME: We probably do the wrong thing if you put an invalid input type.
-          do we care?
-*/
+/* Not sure this is the right color. #EBEBE4 is what Firefox uses. */
 textarea:disabled,
-input:not([type]):disabled, 
-input[type="color" i]:disabled,
-input[type="date" i]:disabled,
-input[type="datetime" i]:disabled,
-input[type="datetime-local" i]:disabled,
-input[type="email" i]:disabled,
-input[type="month" i]:disabled,
-input[type="password" i]:disabled,
-input[type="number" i]:disabled,
-input[type="search" i]:disabled,
-input[type="tel" i]:disabled,
-input[type="text" i]:disabled,
-input[type="time" i]:disabled,
-input[type="url" i]:disabled,
-input[type="week" i]:disabled {
-    background-color: #EBEBE4; 
+input:disabled {
+    background-color: #EBEBE4;
+}
+
+/* Cancel the above rule set for some input types. */
+input[type="button" i]:disabled,
+input[type="reset" i]:disabled,
+input[type="submit" i]:disabled {
+    background-color: ButtonFace;
+}
+input[type="checkbox" i]:disabled,
+input[type="file" i]:disabled,
+input[type="hidden" i]:disabled,
+input[type="image" i]:disabled,
+input[type="radio" i]:disabled,
+input[type="range" i]:disabled {
+    background-color: initial;
 }
 
 input[type="search" i]::-webkit-search-cancel-button {
diff --git a/third_party/blink/renderer/core/editing/editor.cc b/third_party/blink/renderer/core/editing/editor.cc
index 858da736..ef0a85a 100644
--- a/third_party/blink/renderer/core/editing/editor.cc
+++ b/third_party/blink/renderer/core/editing/editor.cc
@@ -238,9 +238,12 @@
   FrameSelection& selection = GetFrameSelection();
   if (!selection.IsAvailable())
     return false;
-  return selection.ComputeVisibleSelectionInDOMTreeDeprecated().IsRange() &&
+  frame_->GetDocument()->UpdateStyleAndLayoutIgnorePendingStylesheets();
+  const VisibleSelectionInFlatTree& visible_selection =
+      selection.ComputeVisibleSelectionInFlatTree();
+  return visible_selection.IsRange() &&
          !IsInPasswordFieldWithUnrevealedPassword(
-             selection.ComputeVisibleSelectionInDOMTree().Start());
+             ToPositionInDOMTree(visible_selection.Start()));
 }
 
 bool Editor::CanPaste() const {
diff --git a/third_party/blink/renderer/core/editing/editor_test.cc b/third_party/blink/renderer/core/editing/editor_test.cc
index 42dc372e..724217e 100644
--- a/third_party/blink/renderer/core/editing/editor_test.cc
+++ b/third_party/blink/renderer/core/editing/editor_test.cc
@@ -6,6 +6,8 @@
 
 #include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
 #include "third_party/blink/renderer/core/editing/commands/editor_command.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/testing/editing_test_base.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
@@ -26,6 +28,13 @@
   }
 };
 
+TEST_F(EditorTest, CanCopyCrossingShadowBoundary) {
+  const SelectionInDOMTree selection = SetSelectionTextToBody(
+      "<p><template data-mode=open>^abc</template></p><b>|</b>");
+  Selection().SetSelection(selection, SetSelectionOptions());
+  EXPECT_TRUE(GetDocument().GetFrame()->GetEditor().CanCopy());
+}
+
 TEST_F(EditorTest, copyGeneratedPassword) {
   // Checks that if the password field has the value generated by Chrome
   // (HTMLInputElement::shouldRevealPassword will be true), copying the field
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.cc b/third_party/blink/renderer/core/frame/local_dom_window.cc
index b8c7fad..414ffe5 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.cc
+++ b/third_party/blink/renderer/core/frame/local_dom_window.cc
@@ -98,6 +98,7 @@
 #include "third_party/blink/renderer/core/script/modulator.h"
 #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
 #include "third_party/blink/renderer/core/timing/window_performance.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h"
 #include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
@@ -281,6 +282,12 @@
   DispatchEvent(Event::Create(EventTypeNames::languagechange));
 }
 
+TrustedTypePolicyFactory* LocalDOMWindow::trustedTypes() const {
+  if (!trusted_types_)
+    trusted_types_ = TrustedTypePolicyFactory::Create(GetFrame());
+  return trusted_types_.Get();
+}
+
 Document* LocalDOMWindow::CreateDocument(const String& mime_type,
                                          const DocumentInit& init,
                                          bool force_xhtml) {
@@ -469,6 +476,7 @@
   media_ = nullptr;
   custom_elements_ = nullptr;
   application_cache_ = nullptr;
+  trusted_types_ = nullptr;
 }
 
 void LocalDOMWindow::SendOrientationChangeEvent() {
@@ -1686,6 +1694,7 @@
   visitor->Trace(post_message_timers_);
   visitor->Trace(visualViewport_);
   visitor->Trace(event_listener_observers_);
+  visitor->Trace(trusted_types_);
   DOMWindow::Trace(visitor);
   Supplementable<LocalDOMWindow>::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/core/frame/local_dom_window.h b/third_party/blink/renderer/core/frame/local_dom_window.h
index f64aaa4..3b1f204a 100644
--- a/third_party/blink/renderer/core/frame/local_dom_window.h
+++ b/third_party/blink/renderer/core/frame/local_dom_window.h
@@ -69,6 +69,7 @@
 class SerializedScriptValue;
 class SourceLocation;
 class StyleMedia;
+class TrustedTypePolicyFactory;
 class USVStringOrTrustedURL;
 class V8FrameRequestCallback;
 class V8IdleRequestCallback;
@@ -330,6 +331,8 @@
 
   void AcceptLanguagesChanged();
 
+  TrustedTypePolicyFactory* trustedTypes() const;
+
  protected:
   // EventTarget overrides.
   void AddedEventListener(const AtomicString& event_type,
@@ -407,6 +410,8 @@
 
   HeapHashSet<Member<PostMessageTimer>> post_message_timers_;
   HeapHashSet<WeakMember<EventListenerObserver>> event_listener_observers_;
+
+  mutable Member<TrustedTypePolicyFactory> trusted_types_;
 };
 
 DEFINE_TYPE_CASTS(LocalDOMWindow,
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 3bb296c..0321eaf0 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -916,6 +916,7 @@
     : Frame(client, page, owner, LocalWindowProxyManager::Create(*this)),
       frame_scheduler_(page.GetPageScheduler()
                            ? page.GetPageScheduler()->CreateFrameScheduler(
+                                 this,
                                  client->GetFrameBlameContext(),
                                  IsMainFrame()
                                      ? FrameScheduler::FrameType::kMainFrame
@@ -1449,4 +1450,18 @@
           std::move(request), GetDocument());
 }
 
+ukm::UkmRecorder* LocalFrame::GetUkmRecorder() {
+  Document* document = GetDocument();
+  if (!document)
+    return nullptr;
+  return document->UkmRecorder();
+}
+
+int64_t LocalFrame::GetUkmSourceId() {
+  Document* document = GetDocument();
+  if (!document)
+    return ukm::kInvalidSourceId;
+  return document->UkmSourceID();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 79dec44..0e2bb30 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -104,6 +104,7 @@
 extern template class CORE_EXTERN_TEMPLATE_EXPORT Supplement<LocalFrame>;
 
 class CORE_EXPORT LocalFrame final : public Frame,
+                                     public FrameScheduler::Delegate,
                                      public Supplementable<LocalFrame> {
   USING_GARBAGE_COLLECTED_MIXIN(LocalFrame);
 
@@ -394,6 +395,10 @@
                    const FloatSize& original_page_size,
                    float maximum_shrink_ratio);
 
+  // FrameScheduler::Delegate overrides:
+  ukm::UkmRecorder* GetUkmRecorder() override;
+  ukm::SourceId GetUkmSourceId() override;
+
   std::unique_ptr<FrameScheduler> frame_scheduler_;
 
   // Holds all PauseSubresourceLoadingHandles allowing either |this| to delete
diff --git a/third_party/blink/renderer/core/frame/window.idl b/third_party/blink/renderer/core/frame/window.idl
index 2b97ed8..e0ece69c 100644
--- a/third_party/blink/renderer/core/frame/window.idl
+++ b/third_party/blink/renderer/core/frame/window.idl
@@ -217,6 +217,10 @@
     readonly attribute boolean isSecureContext;
 
     attribute DOMMatrixConstructor WebKitCSSMatrix;
+
+    //TrustedTypes API
+    //http://github.com/wicg/trusted-types
+    [RuntimeEnabled=TrustedDOMTypes] readonly attribute TrustedTypePolicyFactory trustedTypes;
 };
 
 Window implements GlobalEventHandlers;
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.cc b/third_party/blink/renderer/core/html/html_anchor_element.cc
index 833fc4f..53d26a5 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.cc
+++ b/third_party/blink/renderer/core/html/html_anchor_element.cc
@@ -46,6 +46,9 @@
 #include "third_party/blink/renderer/platform/network/network_hints.h"
 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
 
+#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
+
 namespace blink {
 
 using namespace HTMLNames;
@@ -249,6 +252,11 @@
   setAttribute(hrefAttr, value);
 }
 
+void HTMLAnchorElement::setHref(const USVStringOrTrustedURL& stringOrTrustedURL,
+                                ExceptionState& exception_state) {
+  setAttribute(hrefAttr, stringOrTrustedURL, exception_state);
+}
+
 KURL HTMLAnchorElement::Url() const {
   return Href();
 }
diff --git a/third_party/blink/renderer/core/html/html_anchor_element.h b/third_party/blink/renderer/core/html/html_anchor_element.h
index 46fa0615..eff69542 100644
--- a/third_party/blink/renderer/core/html/html_anchor_element.h
+++ b/third_party/blink/renderer/core/html/html_anchor_element.h
@@ -58,6 +58,9 @@
   kRelationNoOpener = 0x00040000,
 };
 
+class ExceptionState;
+class USVStringOrTrustedURL;
+
 class CORE_EXPORT HTMLAnchorElement : public HTMLElement, public DOMURLUtils {
   DEFINE_WRAPPERTYPEINFO();
 
@@ -68,6 +71,7 @@
 
   KURL Href() const;
   void SetHref(const AtomicString&);
+  void setHref(const USVStringOrTrustedURL&, ExceptionState&);
 
   const AtomicString& GetName() const;
 
diff --git a/third_party/blink/renderer/core/html/html_hyperlink_element_utils.idl b/third_party/blink/renderer/core/html/html_hyperlink_element_utils.idl
index c2e628ca..bf2021fb 100644
--- a/third_party/blink/renderer/core/html/html_hyperlink_element_utils.idl
+++ b/third_party/blink/renderer/core/html/html_hyperlink_element_utils.idl
@@ -8,7 +8,7 @@
     NoInterfaceObject // Always used on target of 'implements'
 ] interface HTMLHyperlinkElementUtils {
 
-    [CEReactions, RaisesException=Setter, CallWith=ScriptState] stringifier attribute URLString href;
+    [CEReactions, RaisesException=Setter] stringifier attribute URLString href;
     readonly attribute USVString origin;
 
     [CEReactions] attribute USVString protocol;
diff --git a/third_party/blink/renderer/core/layout/layout_text.cc b/third_party/blink/renderer/core/layout/layout_text.cc
index e45c457..e4f0984 100644
--- a/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/third_party/blink/renderer/core/layout/layout_text.cc
@@ -1490,6 +1490,23 @@
   return FirstTextBox() ? FirstTextBox()->Y().ToFloat() : 0;
 }
 
+bool LayoutText::CanOptimizeSetText() const {
+  // If we have only one line of text and "contain: layout size" we can avoid
+  // doing a layout and only paint in the SetText() operation.
+  return Parent()->IsLayoutBlockFlow() &&
+         (Parent()->ShouldApplyLayoutContainment() &&
+          Parent()->ShouldApplySizeContainment()) &&
+         FirstTextBox() &&
+         (FirstTextBox() == LastTextBox() &&
+          // If "line-height" is "normal" we might need to recompute the
+          // baseline which is not straight forward.
+          !StyleRef().LineHeight().IsNegative() &&
+          // We would need to recompute the position if "direction" is "rtl" or
+          // "text-align" is not the default one.
+          StyleRef().IsLeftToRightDirection() &&
+          (StyleRef().GetTextAlign(true) == ETextAlign::kStart));
+}
+
 void LayoutText::SetTextWithOffset(scoped_refptr<StringImpl> text,
                                    unsigned offset,
                                    unsigned len,
@@ -1497,6 +1514,31 @@
   if (!force && Equal(text_.Impl(), text.get()))
     return;
 
+  if (CanOptimizeSetText() &&
+      // Check that we are replacing the whole text.
+      offset == 0 && len == TextLength()) {
+    const ComputedStyle* style_to_use =
+        FirstTextBox()->GetLineLayoutItem().Style(
+            FirstTextBox()->IsFirstLineStyle());
+    TextRun text_run = TextRun(String(text));
+    text_run.SetTabSize(!style_to_use->CollapseWhiteSpace(),
+                        style_to_use->GetTabSize());
+    FloatRect glyph_bounds;
+    float text_width =
+        style_to_use->GetFont().Width(text_run, nullptr, &glyph_bounds);
+    // TODO(rego): We could avoid measuring text width in some specific
+    // situations (e.g. if "white-space" property is "pre" and "overflow-wrap"
+    // is "normal").
+    if (text_width <= ContainingBlock()->ContentLogicalWidth()) {
+      FirstTextBox()->ManuallySetStartLenAndLogicalWidth(
+          offset, text->length(), LayoutUnit(text_width));
+      SetText(std::move(text), force, true);
+      lines_dirty_ = false;
+      valid_ng_items_ = false;
+      return;
+    }
+  }
+
   unsigned old_len = TextLength();
   unsigned new_len = text->length();
   int delta = new_len - old_len;
@@ -1676,7 +1718,9 @@
   }
 }
 
-void LayoutText::SetText(scoped_refptr<StringImpl> text, bool force) {
+void LayoutText::SetText(scoped_refptr<StringImpl> text,
+                         bool force,
+                         bool avoid_layout_and_only_paint) {
   DCHECK(text);
 
   if (!force && Equal(text_.Impl(), text.get()))
@@ -1688,8 +1732,12 @@
   // To avoid that, we call setNeedsLayoutAndPrefWidthsRecalc() only if this
   // LayoutText has parent.
   if (Parent()) {
-    SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
-        LayoutInvalidationReason::kTextChanged);
+    if (avoid_layout_and_only_paint) {
+      SetShouldDoFullPaintInvalidation();
+    } else {
+      SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+          LayoutInvalidationReason::kTextChanged);
+    }
   }
   known_to_have_no_overflow_and_no_fallback_fonts_ = false;
 
diff --git a/third_party/blink/renderer/core/layout/layout_text.h b/third_party/blink/renderer/core/layout/layout_text.h
index c5773395..fb644af 100644
--- a/third_party/blink/renderer/core/layout/layout_text.h
+++ b/third_party/blink/renderer/core/layout/layout_text.h
@@ -184,7 +184,9 @@
   float FirstRunX() const;
   float FirstRunY() const;
 
-  virtual void SetText(scoped_refptr<StringImpl>, bool force = false);
+  virtual void SetText(scoped_refptr<StringImpl>,
+                       bool force = false,
+                       bool avoid_layout_and_only_paint = false);
   void SetTextWithOffset(scoped_refptr<StringImpl>,
                          unsigned offset,
                          unsigned len,
@@ -362,6 +364,8 @@
 
   LayoutRect LocalVisualRectIgnoringVisibility() const final;
 
+  bool CanOptimizeSetText() const;
+
   // We put the bitfield first to minimize padding on 64-bit.
  protected:
   // Whether or not we can be broken into multiple lines.
diff --git a/third_party/blink/renderer/core/layout/layout_text_fragment.cc b/third_party/blink/renderer/core/layout/layout_text_fragment.cc
index 1e34a60..5e37b07 100644
--- a/third_party/blink/renderer/core/layout/layout_text_fragment.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_fragment.cc
@@ -92,8 +92,10 @@
   return result->Substring(Start(), FragmentLength());
 }
 
-void LayoutTextFragment::SetText(scoped_refptr<StringImpl> text, bool force) {
-  LayoutText::SetText(std::move(text), force);
+void LayoutTextFragment::SetText(scoped_refptr<StringImpl> text,
+                                 bool force,
+                                 bool avoid_layout_and_only_paint) {
+  LayoutText::SetText(std::move(text), force, avoid_layout_and_only_paint);
 
   start_ = 0;
   fragment_length_ = TextLength();
diff --git a/third_party/blink/renderer/core/layout/layout_text_fragment.h b/third_party/blink/renderer/core/layout/layout_text_fragment.h
index 42bcacb..56272e4 100644
--- a/third_party/blink/renderer/core/layout/layout_text_fragment.h
+++ b/third_party/blink/renderer/core/layout/layout_text_fragment.h
@@ -70,7 +70,9 @@
 
   scoped_refptr<StringImpl> OriginalText() const override;
 
-  void SetText(scoped_refptr<StringImpl>, bool force = false) override;
+  void SetText(scoped_refptr<StringImpl>,
+               bool force = false,
+               bool avoid_layout_and_only_paint = false) override;
   void SetTextFragment(scoped_refptr<StringImpl>,
                        unsigned start,
                        unsigned length);
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.cc b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
index 80dca35b5..2b1e7ae 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.cc
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.cc
@@ -794,4 +794,22 @@
 
 #endif
 
+void InlineTextBox::ManuallySetStartLenAndLogicalWidth(
+    unsigned start,
+    unsigned len,
+    LayoutUnit logical_width) {
+  DCHECK(!IsDirty());
+  DCHECK_EQ(Root().FirstChild(), this);
+  DCHECK_EQ(Root().FirstChild(), Root().LastChild());
+  DCHECK(Root().FirstChild()->IsText());
+
+  start_ = start;
+  len_ = len;
+
+  SetLogicalWidth(logical_width);
+
+  if (!KnownToHaveNoOverflow() && g_text_boxes_with_overflow)
+    g_text_boxes_with_overflow->erase(this);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/line/inline_text_box.h b/third_party/blink/renderer/core/layout/line/inline_text_box.h
index fb34617..947c6ed 100644
--- a/third_party/blink/renderer/core/layout/line/inline_text_box.h
+++ b/third_party/blink/renderer/core/layout/line/inline_text_box.h
@@ -60,6 +60,9 @@
   InlineTextBox* NextForSameLayoutObject() const { return next_text_box_; }
   void SetNextForSameLayoutObject(InlineTextBox* n) { next_text_box_ = n; }
   void SetPreviousForSameLayoutObject(InlineTextBox* p) { prev_text_box_ = p; }
+  void ManuallySetStartLenAndLogicalWidth(unsigned start,
+                                          unsigned len,
+                                          LayoutUnit logical_width);
 
   // FIXME: These accessors should DCHECK(!isDirty()). See
   // https://bugs.webkit.org/show_bug.cgi?id=97264
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc
index aeaeab8..8422e12b 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -173,6 +173,20 @@
   const Member<ThreadableLoader> loader_;
 };
 
+class ThreadableLoader::AssignOnScopeExit final {
+  STACK_ALLOCATED();
+
+ public:
+  AssignOnScopeExit(const KURL& from, KURL* to) : from_(from), to_(to) {}
+  ~AssignOnScopeExit() { *to_ = from_; }
+
+ private:
+  const KURL& from_;
+  KURL* to_;
+
+  DISALLOW_COPY_AND_ASSIGN(AssignOnScopeExit);
+};
+
 // Max number of CORS redirects handled in ThreadableLoader. Same number
 // as net/url_request/url_request.cc, and same number as
 // https://fetch.spec.whatwg.org/#concept-http-fetch, Step 4.
@@ -274,6 +288,8 @@
   if (cors_enabled)
     cors_redirect_limit_ = kMaxCORSRedirects;
 
+  initial_request_url_ = request.Url();
+  last_request_url_ = initial_request_url_;
   request_context_ = request.GetRequestContext();
   fetch_request_mode_ = request.GetFetchRequestMode();
   fetch_credentials_mode_ = request.GetFetchCredentialsMode();
@@ -292,13 +308,9 @@
                         network::mojom::FetchRequestMode::kSameOrigin) {
     ThreadableLoaderClient* client = client_;
     Clear();
-    ResourceError error = ResourceError::CancelledDueToAccessCheckError(
-        request.Url(), ResourceRequestBlockedReason::kOther,
-        CORS::GetErrorString(
-            CORS::ErrorParameter::CreateForDisallowedByMode(request.Url())));
-    GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
-        kJSMessageSource, kErrorMessageLevel, error.LocalizedDescription()));
-    client->DidFail(error);
+    client->DidFail(ResourceError(
+        request.Url(), network::CORSErrorStatus(
+                           network::mojom::CORSError::kDisallowedByMode)));
     return;
   }
 
@@ -442,28 +454,25 @@
   // send a request, preflighted or not, that's guaranteed to be denied.
   if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled(
           request.Url().Protocol())) {
-    DispatchDidFailAccessControlCheck(
-        ResourceError::CancelledDueToAccessCheckError(
-            request.Url(), ResourceRequestBlockedReason::kOther,
-            String::Format(
-                "Cross origin requests are only supported for protocol "
-                "schemes: %s.",
-                SchemeRegistry::ListOfCORSEnabledURLSchemes().Ascii().data())));
+    DispatchDidFail(ResourceError(
+        request.Url(), network::CORSErrorStatus(
+                           network::mojom::CORSError::kCORSDisabledScheme)));
     return;
   }
 
   // Non-secure origins may not make "external requests":
   // https://wicg.github.io/cors-rfc1918/#integration-fetch
   String error_message;
+  // TODO(yhirano): Consider moving this branch elsewhere.
   if (!GetExecutionContext()->IsSecureContext(error_message) &&
       request.IsExternalRequest()) {
-    DispatchDidFailAccessControlCheck(
-        ResourceError::CancelledDueToAccessCheckError(
-            request.Url(), ResourceRequestBlockedReason::kOrigin,
-            "Requests to internal network resources are not allowed "
-            "from non-secure contexts (see https://goo.gl/Y0ZkNV). "
-            "This is an experimental restriction which is part of "
-            "'https://mikewest.github.io/cors-rfc1918/'."));
+    // TODO(yhirano): Fix the link.
+    DispatchDidFail(ResourceError::CancelledDueToAccessCheckError(
+        request.Url(), ResourceRequestBlockedReason::kOrigin,
+        "Requests to internal network resources are not allowed "
+        "from non-secure contexts (see https://goo.gl/Y0ZkNV). "
+        "This is an experimental restriction which is part of "
+        "'https://mikewest.github.io/cors-rfc1918/'."));
     return;
   }
 
@@ -613,146 +622,144 @@
     const ResourceResponse& redirect_response) {
   DCHECK(client_);
   DCHECK_EQ(resource, GetResource());
+  {
+    AssignOnScopeExit assign_on_scope_exit(new_request.Url(),
+                                           &last_request_url_);
 
-  checker_.RedirectReceived();
+    checker_.RedirectReceived();
 
-  const KURL& new_url = new_request.Url();
-  const KURL& original_url = redirect_response.Url();
+    const KURL& new_url = new_request.Url();
+    const KURL& original_url = redirect_response.Url();
 
-  if (!actual_request_.IsNull()) {
-    DCHECK(!out_of_blink_cors_);
-    ReportResponseReceived(resource->Identifier(), redirect_response);
+    if (!actual_request_.IsNull()) {
+      DCHECK(!out_of_blink_cors_);
+      ReportResponseReceived(resource->Identifier(), redirect_response);
 
-    HandlePreflightFailure(
-        original_url, CORS::GetErrorString(
-                          CORS::ErrorParameter::CreateForDisallowedRedirect()));
-
-    return false;
-  }
-
-  if (redirect_mode_ == network::mojom::FetchRedirectMode::kManual) {
-    // We use |redirect_mode_| to check the original redirect mode.
-    // |new_request| is a new request for redirect. So we don't set the
-    // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
-    DCHECK(new_request.UseStreamOnResponse());
-    // There is no need to read the body of redirect response because there is
-    // no way to read the body of opaque-redirect filtered response's internal
-    // response.
-    // TODO(horo): If we support any API which expose the internal body, we will
-    // have to read the body. And also HTTPCache changes will be needed because
-    // it doesn't store the body of redirect responses.
-    ResponseReceived(resource, redirect_response,
-                     std::make_unique<EmptyDataHandle>());
-
-    if (client_) {
-      DCHECK(actual_request_.IsNull());
-      NotifyFinished(resource);
-    }
-
-    return false;
-  }
-
-  if (redirect_mode_ == network::mojom::FetchRedirectMode::kError) {
-    ThreadableLoaderClient* client = client_;
-    Clear();
-    client->DidFailRedirectCheck();
-
-    return false;
-  }
-
-  if (out_of_blink_cors_) {
-    client_->DidReceiveRedirectTo(new_url);
-    return client_->WillFollowRedirect(new_url, redirect_response);
-  }
-
-  // Allow same origin requests to continue after allowing clients to audit the
-  // redirect.
-  if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
-    client_->DidReceiveRedirectTo(new_url);
-    return client_->WillFollowRedirect(new_url, redirect_response);
-  }
-
-  if (cors_redirect_limit_ <= 0) {
-    ThreadableLoaderClient* client = client_;
-    Clear();
-    client->DidFailRedirectCheck();
-    return false;
-  }
-
-  --cors_redirect_limit_;
-
-  probe::didReceiveCORSRedirectResponse(
-      GetExecutionContext(), resource->Identifier(),
-      GetDocument() && GetDocument()->GetFrame()
-          ? GetDocument()->GetFrame()->Loader().GetDocumentLoader()
-          : nullptr,
-      redirect_response, resource);
-
-  base::Optional<network::mojom::CORSError> redirect_error =
-      CORS::CheckRedirectLocation(new_url);
-  if (redirect_error) {
-    DispatchDidFailAccessControlCheck(
-        ResourceError::CancelledDueToAccessCheckError(
-            original_url, ResourceRequestBlockedReason::kOther,
-            CORS::GetErrorString(CORS::ErrorParameter::CreateForRedirectCheck(
-                *redirect_error, original_url, new_url))));
-    return false;
-  }
-
-  if (cors_flag_) {
-    // The redirect response must pass the access control check if the CORS
-    // flag is set.
-    base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess(
-        original_url, redirect_response.HttpStatusCode(),
-        redirect_response.HttpHeaderFields(),
-        new_request.GetFetchCredentialsMode(), *GetSecurityOrigin());
-    if (access_error) {
-      DispatchDidFailAccessControlCheck(
-          ResourceError::CancelledDueToAccessCheckError(
-              original_url, ResourceRequestBlockedReason::kOther,
-              CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
-                  *access_error, original_url,
-                  redirect_response.HttpStatusCode(), *GetSecurityOrigin(),
-                  request_context_, new_url))));
+      HandlePreflightFailure(
+          original_url,
+          network::CORSErrorStatus(
+              network::mojom::CORSError::kPreflightDisallowedRedirect));
       return false;
     }
+
+    if (redirect_mode_ == network::mojom::FetchRedirectMode::kManual) {
+      // We use |redirect_mode_| to check the original redirect mode.
+      // |new_request| is a new request for redirect. So we don't set the
+      // redirect mode of it in WebURLLoaderImpl::Context::OnReceivedRedirect().
+      DCHECK(new_request.UseStreamOnResponse());
+      // There is no need to read the body of redirect response because there is
+      // no way to read the body of opaque-redirect filtered response's internal
+      // response.
+      // TODO(horo): If we support any API which expose the internal body, we
+      // will have to read the body. And also HTTPCache changes will be needed
+      // because it doesn't store the body of redirect responses.
+      ResponseReceived(resource, redirect_response,
+                       std::make_unique<EmptyDataHandle>());
+
+      if (client_) {
+        DCHECK(actual_request_.IsNull());
+        NotifyFinished(resource);
+      }
+
+      return false;
+    }
+
+    if (redirect_mode_ == network::mojom::FetchRedirectMode::kError) {
+      ThreadableLoaderClient* client = client_;
+      Clear();
+      client->DidFailRedirectCheck();
+
+      return false;
+    }
+
+    if (out_of_blink_cors_) {
+      client_->DidReceiveRedirectTo(new_url);
+      client_->WillFollowRedirect(new_url, redirect_response);
+      return true;
+    }
+
+    // Allow same origin requests to continue after allowing clients to audit
+    // the redirect.
+    if (IsAllowedRedirect(new_request.GetFetchRequestMode(), new_url)) {
+      client_->DidReceiveRedirectTo(new_url);
+      return client_->WillFollowRedirect(new_url, redirect_response);
+    }
+
+    if (cors_redirect_limit_ <= 0) {
+      ThreadableLoaderClient* client = client_;
+      Clear();
+      client->DidFailRedirectCheck();
+      return false;
+    }
+
+    --cors_redirect_limit_;
+
+    probe::didReceiveCORSRedirectResponse(
+        GetExecutionContext(), resource->Identifier(),
+        GetDocument() && GetDocument()->GetFrame()
+            ? GetDocument()->GetFrame()->Loader().GetDocumentLoader()
+            : nullptr,
+        redirect_response, resource);
+
+    base::Optional<network::mojom::CORSError> redirect_error =
+        CORS::CheckRedirectLocation(new_url);
+    if (redirect_error) {
+      DispatchDidFail(ResourceError(original_url,
+                                    network::CORSErrorStatus(*redirect_error)));
+      return false;
+    }
+
+    if (cors_flag_) {
+      // The redirect response must pass the access control check if the CORS
+      // flag is set.
+      base::Optional<network::CORSErrorStatus> access_error = CORS::CheckAccess(
+          original_url, redirect_response.HttpStatusCode(),
+          redirect_response.HttpHeaderFields(),
+          new_request.GetFetchCredentialsMode(), *GetSecurityOrigin());
+      if (access_error) {
+        DispatchDidFail(ResourceError(original_url, *access_error));
+        return false;
+      }
+    }
+
+    client_->DidReceiveRedirectTo(new_url);
+
+    // FIXME: consider combining this with CORS redirect handling performed by
+    // CrossOriginAccessControl::handleRedirect().
+    if (GetResource())
+      checker_.WillRemoveClient();
+    ClearResource();
+
+    // If
+    // - CORS flag is set, and
+    // - the origin of the redirect target URL is not same origin with the
+    //   origin of the current request's URL
+    // set the source origin to a unique opaque origin.
+    //
+    // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
+    if (cors_flag_) {
+      scoped_refptr<const SecurityOrigin> original_origin =
+          SecurityOrigin::Create(original_url);
+      scoped_refptr<const SecurityOrigin> new_origin =
+          SecurityOrigin::Create(new_url);
+      if (!original_origin->IsSameSchemeHostPort(new_origin.get()))
+        security_origin_ = SecurityOrigin::CreateUniqueOpaque();
+    }
+
+    // Set |cors_flag_| so that further logic (corresponds to the main fetch in
+    // the spec) will be performed with CORS flag set.
+    // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
+    cors_flag_ = true;
+
+    // Save the referrer to use when following the redirect.
+    override_referrer_ = true;
+    // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
+    // closed and we stop storing the referrer string as a `Referer` header.
+    referrer_after_redirect_ =
+        Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy());
   }
-
-  client_->DidReceiveRedirectTo(new_url);
-
-  // FIXME: consider combining this with CORS redirect handling performed by
-  // CrossOriginAccessControl::handleRedirect().
-  if (GetResource())
-    checker_.WillRemoveClient();
-  ClearResource();
-
-  // If
-  // - CORS flag is set, and
-  // - the origin of the redirect target URL is not same origin with the origin
-  //   of the current request's URL
-  // set the source origin to a unique opaque origin.
-  //
-  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
-  if (cors_flag_) {
-    scoped_refptr<const SecurityOrigin> original_origin =
-        SecurityOrigin::Create(original_url);
-    scoped_refptr<const SecurityOrigin> new_origin =
-        SecurityOrigin::Create(new_url);
-    if (!original_origin->IsSameSchemeHostPort(new_origin.get()))
-      security_origin_ = SecurityOrigin::CreateUniqueOpaque();
-  }
-
-  // Set |cors_flag_| so that further logic (corresponds to the main fetch in
-  // the spec) will be performed with CORS flag set.
-  // See https://fetch.spec.whatwg.org/#http-redirect-fetch.
-  cors_flag_ = true;
-
-  // Save the referrer to use when following the redirect.
-  override_referrer_ = true;
-  // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
-  // closed and we stop storing the referrer string as a `Referer` header.
-  referrer_after_redirect_ =
-      Referrer(new_request.HttpReferrer(), new_request.GetReferrerPolicy());
+  // We're initiating a new request (for redirect), so update
+  // |last_request_url_| by destroying |assign_on_scope_exit|.
 
   ResourceRequest cross_origin_request(new_request);
 
@@ -826,46 +833,35 @@
                                  actual_request_.GetFetchCredentialsMode(),
                                  *GetSecurityOrigin());
   if (cors_error_status) {
-    HandlePreflightFailure(
-        response.Url(),
-        CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
-            *cors_error_status, response.Url(), 0 /* status_code */,
-            *GetSecurityOrigin(), request_context_)));
+    HandlePreflightFailure(response.Url(), *cors_error_status);
     return;
   }
 
   base::Optional<network::mojom::CORSError> preflight_error =
       CORS::CheckPreflight(response.HttpStatusCode());
   if (preflight_error) {
-    HandlePreflightFailure(
-        response.Url(), CORS::GetErrorString(
-                            CORS::ErrorParameter::CreateForPreflightStatusCheck(
-                                response.HttpStatusCode())));
+    HandlePreflightFailure(response.Url(),
+                           network::CORSErrorStatus(*preflight_error));
     return;
   }
 
+  base::Optional<network::CORSErrorStatus> error_status;
   if (actual_request_.IsExternalRequest()) {
-    base::Optional<network::CORSErrorStatus> external_preflight_status =
-        CORS::CheckExternalPreflight(response.HttpHeaderFields());
-    if (external_preflight_status) {
-      HandlePreflightFailure(
-          response.Url(),
-          CORS::GetErrorString(
-              CORS::ErrorParameter::CreateForExternalPreflightCheck(
-                  *external_preflight_status)));
+    error_status = CORS::CheckExternalPreflight(response.HttpHeaderFields());
+    if (error_status) {
+      HandlePreflightFailure(response.Url(), *error_status);
       return;
     }
   }
 
   String access_control_error_description;
-  if (!CORS::EnsurePreflightResultAndCacheOnSuccess(
-          response.HttpHeaderFields(), GetSecurityOrigin()->ToString(),
-          actual_request_.Url(), actual_request_.HttpMethod(),
-          actual_request_.HttpHeaderFields(),
-          actual_request_.GetFetchCredentialsMode(),
-          &access_control_error_description)) {
-    HandlePreflightFailure(response.Url(), access_control_error_description);
-  }
+  error_status = CORS::EnsurePreflightResultAndCacheOnSuccess(
+      response.HttpHeaderFields(), GetSecurityOrigin()->ToString(),
+      actual_request_.Url(), actual_request_.HttpMethod(),
+      actual_request_.HttpHeaderFields(),
+      actual_request_.GetFetchCredentialsMode());
+  if (error_status)
+    HandlePreflightFailure(response.Url(), *error_status);
 }
 
 void ThreadableLoader::ReportResponseReceived(
@@ -931,12 +927,9 @@
     if (fetch_request_mode_ != network::mojom::FetchRequestMode::kNoCORS &&
         response.ResponseTypeViaServiceWorker() ==
             network::mojom::FetchResponseType::kOpaque) {
-      DispatchDidFailAccessControlCheck(
-          ResourceError::CancelledDueToAccessCheckError(
-              response.Url(), ResourceRequestBlockedReason::kOther,
-              CORS::GetErrorString(
-                  CORS::ErrorParameter::CreateForInvalidResponse(
-                      response.Url(), *GetSecurityOrigin()))));
+      DispatchDidFail(ResourceError(
+          response.Url(), network::CORSErrorStatus(
+                              network::mojom::CORSError::kInvalidResponse)));
       return;
     }
 
@@ -964,12 +957,7 @@
         fetch_credentials_mode_, *GetSecurityOrigin());
     if (access_error) {
       ReportResponseReceived(resource->Identifier(), response);
-      DispatchDidFailAccessControlCheck(
-          ResourceError::CancelledDueToAccessCheckError(
-              response.Url(), ResourceRequestBlockedReason::kOther,
-              CORS::GetErrorString(CORS::ErrorParameter::CreateForAccessCheck(
-                  *access_error, response.Url(), response.HttpStatusCode(),
-                  *GetSecurityOrigin(), request_context_))));
+      DispatchDidFail(ResourceError(response.Url(), *access_error));
       return;
     }
   }
@@ -1081,43 +1069,23 @@
   LoadRequest(actual_request, actual_options);
 }
 
-void ThreadableLoader::HandlePreflightFailure(const KURL& url,
-                                              const String& error_description) {
+void ThreadableLoader::HandlePreflightFailure(
+    const KURL& url,
+    const network::CORSErrorStatus& error_status) {
   // Prevent NotifyFinished() from bypassing access check.
   actual_request_ = ResourceRequest();
 
-  DispatchDidFailAccessControlCheck(
-      ResourceError::CancelledDueToAccessCheckError(
-          url, ResourceRequestBlockedReason::kOther, error_description));
-}
-
-void ThreadableLoader::DispatchDidFailAccessControlCheck(
-    const ResourceError& error) {
-  const String message = "Failed to load " + error.FailingURL() + ": " +
-                         error.LocalizedDescription();
-  GetExecutionContext()->AddConsoleMessage(
-      ConsoleMessage::Create(kJSMessageSource, kErrorMessageLevel, message));
-
-  ThreadableLoaderClient* client = client_;
-  Clear();
-  client->DidFail(error);
+  DispatchDidFail(ResourceError(url, error_status));
 }
 
 void ThreadableLoader::DispatchDidFail(const ResourceError& error) {
   if (error.CORSErrorStatus()) {
-    DCHECK(out_of_blink_cors_);
-    // TODO(toyoshim): Should consider to pass correct arguments instead of
-    // KURL(), and 0 to GetErrorString().
-    // We still need plumbing some more information.
+    String message = CORS::GetErrorString(
+        *error.CORSErrorStatus(), initial_request_url_, last_request_url_,
+        *GetSecurityOrigin(), Resource::kRaw,
+        resource_loader_options_.initiator_info.name);
     GetExecutionContext()->AddConsoleMessage(ConsoleMessage::Create(
-        kJSMessageSource, kErrorMessageLevel,
-        "Failed to load " + error.FailingURL() + ": " +
-            CORS::GetErrorString(CORS::ErrorParameter::Create(
-                                     *error.CORSErrorStatus(),
-                                     KURL(error.FailingURL()), KURL(), 0,
-                                     *GetSecurityOrigin(), request_context_))
-                .Utf8()
-                .data()));
+        kJSMessageSource, kErrorMessageLevel, std::move(message)));
   }
   ThreadableLoaderClient* client = client_;
   Clear();
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.h b/third_party/blink/renderer/core/loader/threadable_loader.h
index b75e734..d639375d 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.h
+++ b/third_party/blink/renderer/core/loader/threadable_loader.h
@@ -135,6 +135,7 @@
   void Trace(blink::Visitor* visitor) override;
 
  private:
+  class AssignOnScopeExit;
   class DetachedClient;
 
   static std::unique_ptr<ResourceRequest> CreateAccessControlPreflightRequest(
@@ -186,12 +187,11 @@
   void LoadActualRequest();
   // Clears actual_request_ and reports access control check failure to
   // m_client.
-  void HandlePreflightFailure(const KURL&, const String& error_description);
+  void HandlePreflightFailure(const KURL&, const network::CORSErrorStatus&);
   // Investigates the response for the preflight request. If successful,
   // the actual request will be made later in NotifyFinished().
   void HandlePreflightResponse(const ResourceResponse&);
 
-  void DispatchDidFailAccessControlCheck(const ResourceError&);
   void DispatchDidFail(const ResourceError&);
 
   void PrepareCrossOriginRequest(ResourceRequest&) const;
@@ -252,6 +252,9 @@
   ResourceRequest actual_request_;
   ResourceLoaderOptions actual_options_;
 
+  KURL initial_request_url_;
+  KURL last_request_url_;
+
   // stores request headers in case of a cross-origin redirect.
   HTTPHeaderMap request_headers_;
 
diff --git a/third_party/blink/renderer/core/loader/threadable_loader_test.cc b/third_party/blink/renderer/core/loader/threadable_loader_test.cc
index 805d2cb..8a7cdf37 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader_test.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader_test.cc
@@ -714,13 +714,11 @@
   CreateLoader();
   CallCheckpoint(1);
 
-  String error_message = String::Format(
-      "Failed to load '%s': Cross origin requests are not allowed by request "
-      "mode.",
-      ErrorURL().GetString().Utf8().data());
-  EXPECT_CALL(*Client(), DidFail(ResourceError::CancelledDueToAccessCheckError(
-                             ErrorURL(), ResourceRequestBlockedReason::kOther,
-                             error_message)));
+  EXPECT_CALL(
+      *Client(),
+      DidFail(ResourceError(
+          ErrorURL(), network::CORSErrorStatus(
+                          network::mojom::CORSError::kDisallowedByMode))));
   EXPECT_CALL(GetCheckpoint(), Call(2));
 
   StartLoader(ErrorURL(), network::mojom::FetchRequestMode::kSameOrigin);
@@ -765,13 +763,11 @@
   CallCheckpoint(1);
 
   EXPECT_CALL(GetCheckpoint(), Call(2));
-  EXPECT_CALL(
-      *Client(),
-      DidFail(ResourceError::CancelledDueToAccessCheckError(
-          SuccessURL(), ResourceRequestBlockedReason::kOther,
-          "No 'Access-Control-Allow-Origin' header is present on the requested "
-          "resource. Origin 'http://fake.url' is therefore not allowed "
-          "access.")));
+  EXPECT_CALL(*Client(),
+              DidFail(ResourceError(
+                  SuccessURL(),
+                  network::CORSErrorStatus(
+                      network::mojom::CORSError::kMissingAllowOriginHeader))));
 
   StartLoader(SuccessURL(), network::mojom::FetchRequestMode::kCORS);
   CallCheckpoint(2);
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index f88a1ce..c1140f5 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -841,20 +841,6 @@
   return false;
 }
 
-ukm::UkmRecorder* Page::GetUkmRecorder() {
-  Frame* frame = MainFrame();
-  if (!frame->IsLocalFrame())
-    return nullptr;
-  return ToLocalFrame(frame)->GetDocument()->UkmRecorder();
-}
-
-int64_t Page::GetUkmSourceId() {
-  Frame* frame = MainFrame();
-  if (!frame->IsLocalFrame())
-    return -1;
-  return ToLocalFrame(frame)->GetDocument()->UkmSourceID();
-}
-
 void Page::AddAutoplayFlags(int32_t value) {
   autoplay_flags_ |= value;
 }
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index 1be0402..41f555af 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -312,8 +312,6 @@
   void ReportIntervention(const String& message) override;
   bool RequestBeginMainFrameNotExpected(bool new_state) override;
   void SetLifecycleState(PageLifecycleState) override;
-  ukm::UkmRecorder* GetUkmRecorder() override;
-  int64_t GetUkmSourceId() override;
 
   void AddAutoplayFlags(int32_t flags);
   void ClearAutoplayFlags();
diff --git a/third_party/blink/renderer/core/trustedtypes/BUILD.gn b/third_party/blink/renderer/core/trustedtypes/BUILD.gn
index 36b86dc..b372c247 100644
--- a/third_party/blink/renderer/core/trustedtypes/BUILD.gn
+++ b/third_party/blink/renderer/core/trustedtypes/BUILD.gn
@@ -10,6 +10,10 @@
     "trusted_html.h",
     "trusted_script_url.cc",
     "trusted_script_url.h",
+    "trusted_type_policy.cc",
+    "trusted_type_policy.h",
+    "trusted_type_policy_factory.cc",
+    "trusted_type_policy_factory.h",
     "trusted_url.cc",
     "trusted_url.h",
   ]
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
new file mode 100644
index 0000000..506b1f1
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.cc
@@ -0,0 +1,21 @@
+// 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 "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
+
+namespace blink {
+
+TrustedTypePolicy* TrustedTypePolicy::Create(const String& policyName) {
+  return new TrustedTypePolicy(policyName);
+}
+
+String TrustedTypePolicy::name() const {
+  return name_;
+}
+
+TrustedTypePolicy::TrustedTypePolicy(const String& policyName) {
+  name_ = policyName;
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h
new file mode 100644
index 0000000..b1aeb81f
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+
+namespace blink {
+
+class CORE_EXPORT TrustedTypePolicy final : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  static TrustedTypePolicy* Create(const String& policyName);
+
+  String name() const;
+
+ private:
+  TrustedTypePolicy(const String& policyName);
+
+  String name_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_H_
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
new file mode 100644
index 0000000..7e3afa3
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
@@ -0,0 +1,11 @@
+// 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.
+
+// https://github.com/wicg/trusted-types
+[
+    Exposed=(Window),
+    RuntimeEnabled=TrustedDOMTypes
+] interface TrustedTypePolicy {
+    readonly attribute DOMString name;
+};
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
new file mode 100644
index 0000000..61b8e23
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.cc
@@ -0,0 +1,27 @@
+// 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 "third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/trustedtypes/trusted_type_policy.h"
+#include "third_party/blink/renderer/platform/bindings/to_v8.h"
+
+namespace blink {
+
+ScriptPromise TrustedTypePolicyFactory::createPolicy(ScriptState* script_state,
+                                                     const String& policyName) {
+  TrustedTypePolicy* policy = TrustedTypePolicy::Create(policyName);
+  return ScriptPromise::Cast(script_state, ToV8(policy, script_state));
+}
+
+TrustedTypePolicyFactory::TrustedTypePolicyFactory(LocalFrame* frame)
+    : DOMWindowClient(frame) {}
+
+void TrustedTypePolicyFactory::Trace(blink::Visitor* visitor) {
+  ScriptWrappable::Trace(visitor);
+  DOMWindowClient::Trace(visitor);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
new file mode 100644
index 0000000..47687ab
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_FACTORY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_FACTORY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class LocalFrame;
+class ScriptPromise;
+
+class CORE_EXPORT TrustedTypePolicyFactory final : public ScriptWrappable,
+                                                   public DOMWindowClient {
+  DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(TrustedTypePolicyFactory);
+
+ public:
+  static TrustedTypePolicyFactory* Create(LocalFrame* frame) {
+    return new TrustedTypePolicyFactory(frame);
+  }
+
+  static ScriptPromise createPolicy(ScriptState*, const String&);
+
+  void Trace(blink::Visitor*) override;
+
+ private:
+  explicit TrustedTypePolicyFactory(LocalFrame*);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_TRUSTEDTYPES_TRUSTED_TYPE_POLICY_FACTORY_H_
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
new file mode 100644
index 0000000..17e5c76
--- /dev/null
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
@@ -0,0 +1,12 @@
+// 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.
+
+// https://github.com/wicg/trusted-types
+
+[
+    Exposed=(Window),
+    RuntimeEnabled=TrustedDOMTypes
+] interface TrustedTypePolicyFactory {
+    [CallWith=ScriptState] Promise<TrustedTypePolicy> createPolicy(DOMString policyName);
+};
diff --git a/third_party/blink/renderer/core/url/dom_url.cc b/third_party/blink/renderer/core/url/dom_url.cc
index 23defdf7..5b000de 100644
--- a/third_party/blink/renderer/core/url/dom_url.cc
+++ b/third_party/blink/renderer/core/url/dom_url.cc
@@ -55,10 +55,6 @@
   ScriptWrappable::Trace(visitor);
 }
 
-void DOMURL::setHref(const String& value) {
-  SetInput(value);
-}
-
 void DOMURL::SetInput(const String& value) {
   KURL url(BlankURL(), value);
   if (url.IsValid()) {
diff --git a/third_party/blink/renderer/core/url/dom_url.h b/third_party/blink/renderer/core/url/dom_url.h
index 56d52e56..3a7d578 100644
--- a/third_party/blink/renderer/core/url/dom_url.h
+++ b/third_party/blink/renderer/core/url/dom_url.h
@@ -70,8 +70,6 @@
 
   void Trace(blink::Visitor*) override;
 
-  void setHref(const String&);
-
  private:
   friend class URLSearchParams;
   DOMURL(const String& url, const KURL& base, ExceptionState&);
diff --git a/third_party/blink/renderer/core/url/dom_url_utils.cc b/third_party/blink/renderer/core/url/dom_url_utils.cc
index 928053a..6e05c1b 100644
--- a/third_party/blink/renderer/core/url/dom_url_utils.cc
+++ b/third_party/blink/renderer/core/url/dom_url_utils.cc
@@ -26,9 +26,6 @@
 
 #include "third_party/blink/renderer/core/url/dom_url_utils.h"
 
-#include "third_party/blink/renderer/bindings/core/v8/usv_string_or_trusted_url.h"
-#include "third_party/blink/renderer/core/dom/document.h"
-#include "third_party/blink/renderer/core/trustedtypes/trusted_url.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/weborigin/known_ports.h"
 
@@ -36,25 +33,7 @@
 
 DOMURLUtils::~DOMURLUtils() = default;
 
-void DOMURLUtils::setHref(ScriptState* script_state,
-                          const USVStringOrTrustedURL& stringOrUrl,
-                          ExceptionState& exception_state) {
-  DCHECK(stringOrUrl.IsUSVString() ||
-         RuntimeEnabledFeatures::TrustedDOMTypesEnabled());
-  DCHECK(!stringOrUrl.IsNull());
-
-  if (ExecutionContext::From(script_state)->IsDocument()) {
-    Document* document = ToDocument((ExecutionContext::From(script_state)));
-    if (!stringOrUrl.IsTrustedURL() && document->RequireTrustedTypes()) {
-      exception_state.ThrowTypeError(
-          "This document requires `TrustedURL` assignment.");
-      return;
-    }
-  }
-
-  String value = stringOrUrl.IsUSVString()
-                     ? stringOrUrl.GetAsUSVString()
-                     : stringOrUrl.GetAsTrustedURL()->toString();
+void DOMURLUtils::setHref(const String& value) {
   SetInput(value);
 }
 
diff --git a/third_party/blink/renderer/core/url/dom_url_utils.h b/third_party/blink/renderer/core/url/dom_url_utils.h
index 24327551..75f00cea 100644
--- a/third_party/blink/renderer/core/url/dom_url_utils.h
+++ b/third_party/blink/renderer/core/url/dom_url_utils.h
@@ -33,10 +33,7 @@
 
 namespace blink {
 
-class ExceptionState;
-class ScriptState;
 class KURL;
-class USVStringOrTrustedURL;
 
 class CORE_EXPORT DOMURLUtils : public DOMURLUtilsReadOnly {
  public:
@@ -44,7 +41,7 @@
   virtual void SetInput(const String&) = 0;
   ~DOMURLUtils() override;
 
-  void setHref(ScriptState*, const USVStringOrTrustedURL&, ExceptionState&);
+  void setHref(const String&);
 
   void setProtocol(const String&);
   void setUsername(const String&);
diff --git a/third_party/blink/renderer/core/url/dom_url_utils_read_only.cc b/third_party/blink/renderer/core/url/dom_url_utils_read_only.cc
index fdb51e4..ad8b1027 100644
--- a/third_party/blink/renderer/core/url/dom_url_utils_read_only.cc
+++ b/third_party/blink/renderer/core/url/dom_url_utils_read_only.cc
@@ -33,14 +33,14 @@
 
 namespace blink {
 
-String DOMURLUtilsReadOnly::href(ScriptState*, ExceptionState&) {
+String DOMURLUtilsReadOnly::href(ExceptionState&) {
   const KURL& kurl = Url();
   if (kurl.IsNull())
     return Input();
   return kurl.GetString();
 }
 
-void DOMURLUtilsReadOnly::href(ScriptState*, USVStringOrTrustedURL& result) {
+void DOMURLUtilsReadOnly::href(USVStringOrTrustedURL& result) {
   result.SetUSVString(href());
 }
 
diff --git a/third_party/blink/renderer/core/url/dom_url_utils_read_only.h b/third_party/blink/renderer/core/url/dom_url_utils_read_only.h
index 6544b71..ef99f711 100644
--- a/third_party/blink/renderer/core/url/dom_url_utils_read_only.h
+++ b/third_party/blink/renderer/core/url/dom_url_utils_read_only.h
@@ -35,7 +35,6 @@
 namespace blink {
 
 class ExceptionState;
-class ScriptState;
 class USVStringOrTrustedURL;
 
 class CORE_EXPORT DOMURLUtilsReadOnly {
@@ -44,8 +43,8 @@
   virtual String Input() const = 0;
   virtual ~DOMURLUtilsReadOnly() = default;
 
-  void href(ScriptState*, USVStringOrTrustedURL&);
-  String href(ScriptState* = nullptr, ExceptionState& = ASSERT_NO_EXCEPTION);
+  void href(USVStringOrTrustedURL&);
+  String href(ExceptionState& = ASSERT_NO_EXCEPTION);
 
   static String origin(const KURL&);
   String origin() { return origin(Url()); }
diff --git a/third_party/blink/renderer/core/workers/BUILD.gn b/third_party/blink/renderer/core/workers/BUILD.gn
index 57a95632..ac2bd37 100644
--- a/third_party/blink/renderer/core/workers/BUILD.gn
+++ b/third_party/blink/renderer/core/workers/BUILD.gn
@@ -78,10 +78,6 @@
     "worker_settings.h",
     "worker_thread.cc",
     "worker_thread.h",
-    "worker_thread_lifecycle_context.cc",
-    "worker_thread_lifecycle_context.h",
-    "worker_thread_lifecycle_observer.cc",
-    "worker_thread_lifecycle_observer.h",
     "worklet.cc",
     "worklet.h",
     "worklet_global_scope.cc",
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_test.cc b/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
index 424710b..a258a45d 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_test.cc
@@ -150,25 +150,14 @@
   }
 
   void Trace(blink::Visitor* visitor) override {
-    visitor->Trace(mock_worker_thread_lifecycle_observer_);
     DedicatedWorkerMessagingProxy::Trace(visitor);
   }
 
  private:
   std::unique_ptr<WorkerThread> CreateWorkerThread() override {
-    auto worker_thread =
-        std::make_unique<DedicatedWorkerThreadForTest>(WorkerObjectProxy());
-    mock_worker_thread_lifecycle_observer_ =
-        new MockWorkerThreadLifecycleObserver(
-            worker_thread->GetWorkerThreadLifecycleContext());
-    EXPECT_CALL(*mock_worker_thread_lifecycle_observer_,
-                ContextDestroyed(testing::_))
-        .Times(1);
-    return std::move(worker_thread);
+    return std::make_unique<DedicatedWorkerThreadForTest>(WorkerObjectProxy());
   }
 
-  Member<MockWorkerThreadLifecycleObserver>
-      mock_worker_thread_lifecycle_observer_;
   scoped_refptr<const SecurityOrigin> security_origin_;
 };
 
diff --git a/third_party/blink/renderer/core/workers/worker_thread.cc b/third_party/blink/renderer/core/workers/worker_thread.cc
index 9704521..4ac594d 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread.cc
@@ -178,7 +178,6 @@
   // period.
   ScheduleToTerminateScriptExecution();
 
-  worker_thread_lifecycle_context_->NotifyContextDestroyed();
   inspector_task_runner_->Dispose();
 
   if (!child_threads_.IsEmpty()) {
@@ -362,8 +361,7 @@
       worker_reporting_proxy_(worker_reporting_proxy),
       shutdown_event_(std::make_unique<WaitableEvent>(
           WaitableEvent::ResetPolicy::kManual,
-          WaitableEvent::InitialState::kNonSignaled)),
-      worker_thread_lifecycle_context_(new WorkerThreadLifecycleContext) {
+          WaitableEvent::InitialState::kNonSignaled)) {
   MutexLocker lock(ThreadSetMutex());
   WorkerThreads().insert(this);
 }
diff --git a/third_party/blink/renderer/core/workers/worker_thread.h b/third_party/blink/renderer/core/workers/worker_thread.h
index d2c9434..62bb302 100644
--- a/third_party/blink/renderer/core/workers/worker_thread.h
+++ b/third_party/blink/renderer/core/workers/worker_thread.h
@@ -43,8 +43,6 @@
 #include "third_party/blink/renderer/core/workers/parent_execution_context_task_runners.h"
 #include "third_party/blink/renderer/core/workers/worker_backing_thread_startup_data.h"
 #include "third_party/blink/renderer/core/workers/worker_inspector_proxy.h"
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h"
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h"
 #include "third_party/blink/renderer/platform/waitable_event.h"
 #include "third_party/blink/renderer/platform/web_task_runner.h"
@@ -175,12 +173,6 @@
   WorkerOrWorkletGlobalScope* GlobalScope();
   WorkerInspectorController* GetWorkerInspectorController();
 
-  // Called for creating WorkerThreadLifecycleObserver on both the main thread
-  // and the worker thread.
-  WorkerThreadLifecycleContext* GetWorkerThreadLifecycleContext() const {
-    return worker_thread_lifecycle_context_;
-  }
-
   // Number of active worker threads.
   static unsigned WorkerThreadCount();
 
@@ -348,11 +340,6 @@
   // mayForciblyTerminateExecution() for details.
   TaskHandle forcible_termination_task_handle_;
 
-  // Created on the main thread heap, but will be accessed cross-thread
-  // when worker thread posts tasks.
-  CrossThreadPersistent<WorkerThreadLifecycleContext>
-      worker_thread_lifecycle_context_;
-
   HashSet<WorkerThread*> child_threads_;
 
   THREAD_CHECKER(parent_thread_checker_);
diff --git a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.cc b/third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.cc
deleted file mode 100644
index 85cf484..0000000
--- a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.cc
+++ /dev/null
@@ -1,26 +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 "third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h"
-
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h"
-
-namespace blink {
-
-WorkerThreadLifecycleContext::WorkerThreadLifecycleContext() {
-  DETACH_FROM_THREAD(thread_checker_);
-}
-
-WorkerThreadLifecycleContext::~WorkerThreadLifecycleContext() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-void WorkerThreadLifecycleContext::NotifyContextDestroyed() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(!was_context_destroyed_);
-  was_context_destroyed_ = true;
-  LifecycleNotifier::NotifyContextDestroyed();
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h b/third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h
deleted file mode 100644
index 0dec708c..0000000
--- a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h
+++ /dev/null
@@ -1,43 +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_RENDERER_CORE_WORKERS_WORKER_THREAD_LIFECYCLE_CONTEXT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_THREAD_LIFECYCLE_CONTEXT_H_
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
-#include "third_party/blink/renderer/platform/lifecycle_notifier.h"
-
-namespace blink {
-
-class WorkerThreadLifecycleObserver;
-
-// Used for notifying observers on the creating thread of worker thread
-// termination. The lifetime of this class is equal to that of WorkerThread.
-// Created and destructed on the thread that constructed the worker.
-class CORE_EXPORT WorkerThreadLifecycleContext final
-    : public GarbageCollectedFinalized<WorkerThreadLifecycleContext>,
-      public LifecycleNotifier<WorkerThreadLifecycleContext,
-                               WorkerThreadLifecycleObserver> {
-  USING_GARBAGE_COLLECTED_MIXIN(WorkerThreadLifecycleContext);
-
- public:
-  WorkerThreadLifecycleContext();
-  ~WorkerThreadLifecycleContext() override;
-  void NotifyContextDestroyed() override;
-
- private:
-  friend class WorkerThreadLifecycleObserver;
-  bool was_context_destroyed_ = false;
-
-  THREAD_CHECKER(thread_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(WorkerThreadLifecycleContext);
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_THREAD_LIFECYCLE_CONTEXT_H_
diff --git a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.cc b/third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.cc
deleted file mode 100644
index c6d5f912..0000000
--- a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.cc
+++ /dev/null
@@ -1,23 +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 "third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h"
-
-#include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_context.h"
-#include "third_party/blink/renderer/platform/wtf/assertions.h"
-#include "third_party/blink/renderer/platform/wtf/wtf.h"
-
-namespace blink {
-
-WorkerThreadLifecycleObserver::WorkerThreadLifecycleObserver(
-    WorkerThreadLifecycleContext* worker_thread_lifecycle_context)
-    : LifecycleObserver(worker_thread_lifecycle_context),
-      was_context_destroyed_before_observer_creation_(
-          worker_thread_lifecycle_context->was_context_destroyed_) {
-}
-
-WorkerThreadLifecycleObserver::~WorkerThreadLifecycleObserver() = default;
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h b/third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h
deleted file mode 100644
index 55cba34..0000000
--- a/third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h
+++ /dev/null
@@ -1,49 +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 THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_THREAD_LIFECYCLE_OBSERVER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_THREAD_LIFECYCLE_OBSERVER_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/lifecycle_observer.h"
-
-namespace blink {
-
-class WorkerThreadLifecycleContext;
-
-// An interface for observing worker thread termination from the main thread.
-// This may be useful, for example, when an object living on the main thread
-// needs to release references to objects on the worker thread before it gets
-// terminated.
-//
-// A class that inherits this interface should override
-// LifecycleObserver::contextDestroyed() that is called on the main thread when
-// the worker thread is about to terminate. While contextDestroyed() is called,
-// it is guaranteed that the worker thread is still alive.
-//
-// A newly created observer should firstly check whether the worker thread is
-// alive by wasContextDestroyedBeforeObserverCreation(). If this return true,
-// the worker thread has already been terminated before the observer is created,
-// and contextDestroyed() is never notified.
-class CORE_EXPORT WorkerThreadLifecycleObserver
-    : public LifecycleObserver<WorkerThreadLifecycleContext,
-                               WorkerThreadLifecycleObserver> {
- public:
-  virtual void ContextDestroyed(WorkerThreadLifecycleContext*) {}
-
- protected:
-  explicit WorkerThreadLifecycleObserver(WorkerThreadLifecycleContext*);
-  virtual ~WorkerThreadLifecycleObserver();
-
-  bool WasContextDestroyedBeforeObserverCreation() const {
-    return was_context_destroyed_before_observer_creation_;
-  }
-
- private:
-  const bool was_context_destroyed_before_observer_creation_;
-};
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_WORKERS_WORKER_THREAD_LIFECYCLE_OBSERVER_H_
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test.cc b/third_party/blink/renderer/core/workers/worker_thread_test.cc
index c959227..ac64b20a 100644
--- a/third_party/blink/renderer/core/workers/worker_thread_test.cc
+++ b/third_party/blink/renderer/core/workers/worker_thread_test.cc
@@ -78,8 +78,6 @@
     security_origin_ = SecurityOrigin::Create(KURL("http://fake.url/"));
     worker_thread_ =
         std::make_unique<WorkerThreadForTest>(nullptr, *reporting_proxy_);
-    lifecycle_observer_ = new MockWorkerThreadLifecycleObserver(
-        worker_thread_->GetWorkerThreadLifecycleContext());
   }
 
   void TearDown() override {}
@@ -115,7 +113,6 @@
     EXPECT_CALL(*reporting_proxy_, DidEvaluateClassicScript(true)).Times(1);
     EXPECT_CALL(*reporting_proxy_, WillDestroyWorkerGlobalScope()).Times(1);
     EXPECT_CALL(*reporting_proxy_, DidTerminateWorkerThread()).Times(1);
-    EXPECT_CALL(*lifecycle_observer_, ContextDestroyed(_)).Times(1);
   }
 
   void ExpectReportingCallsForWorkerPossiblyTerminatedBeforeInitialization() {
@@ -129,7 +126,6 @@
     EXPECT_CALL(*reporting_proxy_, WillDestroyWorkerGlobalScope())
         .Times(AtMost(1));
     EXPECT_CALL(*reporting_proxy_, DidTerminateWorkerThread()).Times(1);
-    EXPECT_CALL(*lifecycle_observer_, ContextDestroyed(_)).Times(1);
   }
 
   void ExpectReportingCallsForWorkerForciblyTerminated() {
@@ -140,7 +136,6 @@
     EXPECT_CALL(*reporting_proxy_, DidEvaluateClassicScript(false)).Times(1);
     EXPECT_CALL(*reporting_proxy_, WillDestroyWorkerGlobalScope()).Times(1);
     EXPECT_CALL(*reporting_proxy_, DidTerminateWorkerThread()).Times(1);
-    EXPECT_CALL(*lifecycle_observer_, ContextDestroyed(_)).Times(1);
   }
 
   ExitCode GetExitCode() { return worker_thread_->GetExitCodeForTesting(); }
@@ -148,7 +143,6 @@
   scoped_refptr<const SecurityOrigin> security_origin_;
   std::unique_ptr<MockWorkerReportingProxy> reporting_proxy_;
   std::unique_ptr<WorkerThreadForTest> worker_thread_;
-  Persistent<MockWorkerThreadLifecycleObserver> lifecycle_observer_;
 };
 
 TEST_F(WorkerThreadTest, ShouldTerminateScriptExecution) {
@@ -296,7 +290,6 @@
   EXPECT_CALL(*reporting_proxy_, DidInitializeWorkerContext()).Times(1);
   EXPECT_CALL(*reporting_proxy_, WillDestroyWorkerGlobalScope()).Times(1);
   EXPECT_CALL(*reporting_proxy_, DidTerminateWorkerThread()).Times(1);
-  EXPECT_CALL(*lifecycle_observer_, ContextDestroyed(_)).Times(1);
 
   Vector<CSPHeaderAndType> headers{
       {"contentSecurityPolicy", kContentSecurityPolicyHeaderTypeReport}};
diff --git a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
index 4e6c5b3b..f5d0fc21 100644
--- a/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
+++ b/third_party/blink/renderer/core/workers/worker_thread_test_helper.h
@@ -25,7 +25,6 @@
 #include "third_party/blink/renderer/core/workers/worker_global_scope.h"
 #include "third_party/blink/renderer/core/workers/worker_reporting_proxy.h"
 #include "third_party/blink/renderer/core/workers/worker_thread.h"
-#include "third_party/blink/renderer/core/workers/worker_thread_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/cross_thread_functional.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
 #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
@@ -40,22 +39,6 @@
 
 namespace blink {
 
-class MockWorkerThreadLifecycleObserver final
-    : public GarbageCollectedFinalized<MockWorkerThreadLifecycleObserver>,
-      public WorkerThreadLifecycleObserver {
-  USING_GARBAGE_COLLECTED_MIXIN(MockWorkerThreadLifecycleObserver);
-
- public:
-  explicit MockWorkerThreadLifecycleObserver(
-      WorkerThreadLifecycleContext* context)
-      : WorkerThreadLifecycleObserver(context) {}
-
-  MOCK_METHOD1(ContextDestroyed, void(WorkerThreadLifecycleContext*));
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(MockWorkerThreadLifecycleObserver);
-};
-
 class FakeWorkerGlobalScope : public WorkerGlobalScope {
  public:
   FakeWorkerGlobalScope(
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 0c491a9..0d07598 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -316,6 +316,7 @@
 video::-internal-media-controls-overflow-button:disabled,
 video::-webkit-media-controls-mute-button:disabled,
 video::-webkit-media-controls-fullscreen-button:disabled {
+  background-color: initial;
   opacity: 0.3;
 }
 
diff --git a/third_party/blink/renderer/modules/websockets/OWNERS b/third_party/blink/renderer/modules/websockets/OWNERS
index d1ce751..d5f5069 100644
--- a/third_party/blink/renderer/modules/websockets/OWNERS
+++ b/third_party/blink/renderer/modules/websockets/OWNERS
@@ -1,4 +1,4 @@
-tyoshino@chromium.org
+ricea@chromium.org
 yhirano@chromium.org
 
 # TEAM: blink-network-dev@chromium.org
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index a176ed33..115a517 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -108,6 +108,10 @@
   RuntimeEnabledFeatures::SetCacheInlineScriptCodeEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableIsolatedCodeCache(bool enable) {
+  RuntimeEnabledFeatures::SetIsolatedCodeCacheEnabled(enable);
+}
+
 void WebRuntimeFeatures::EnableCanvas2dImageChromium(bool enable) {
   RuntimeEnabledFeatures::SetCanvas2dImageChromiumEnabled(enable);
 }
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
index 2c108da..74ba40b 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.cc
@@ -817,7 +817,6 @@
                                         unsigned num_glyphs,
                                         hb_buffer_t* harfbuzz_buffer) {
   DCHECK_EQ(is_horizontal_run, run->IsHorizontal());
-  const SimpleFontData& current_font_data = *run->font_data_;
   const hb_glyph_info_t* glyph_infos =
       hb_buffer_get_glyph_infos(harfbuzz_buffer, nullptr);
   const hb_glyph_position_t* glyph_positions =
@@ -831,7 +830,6 @@
   // and boudning box of glyphs are in physical. It's the caller's
   // responsibility to convert the united physical bounds to logical.
   float total_advance = 0.0f;
-  GlyphBoundsAccumulator bounds(width_);
   bool has_vertical_offsets = !is_horizontal_run;
 
   // HarfBuzz returns result in visual order, no need to flip for RTL.
@@ -864,15 +862,32 @@
         IsSafeToBreakBefore(glyph_infos + start_glyph, num_glyphs, i));
     total_advance += advance;
     has_vertical_offsets |= (offset.Height() != 0);
-
-    bounds.Unite<is_horizontal_run>(
-        glyph_data, current_font_data.BoundsForGlyph(glyph_data.glyph));
-    bounds.origin += advance;
   }
 
   run->width_ = std::max(0.0f, total_advance);
   has_vertical_offsets_ |= has_vertical_offsets;
 
+  ComputeGlyphBounds<is_horizontal_run>(*run);
+}
+
+template <bool is_horizontal_run>
+void ShapeResult::ComputeGlyphBounds(const ShapeResult::RunInfo& run) {
+  // Skia runs much faster if we give a list of glyph ID rather than calling it
+  // on each glyph.
+  const SimpleFontData& current_font_data = *run.font_data_;
+  unsigned num_glyphs = run.glyph_data_.size();
+  Vector<Glyph, 256> glyphs(num_glyphs);
+  for (unsigned i = 0; i < num_glyphs; i++)
+    glyphs[i] = run.glyph_data_[i].glyph;
+  Vector<FloatRect, 256> bounds_list(num_glyphs);
+  current_font_data.BoundsForGlyphs(glyphs, &bounds_list);
+
+  GlyphBoundsAccumulator bounds(width_);
+  for (unsigned i = 0; i < num_glyphs; i++) {
+    const HarfBuzzRunGlyphData& glyph_data = run.glyph_data_[i];
+    bounds.Unite<is_horizontal_run>(glyph_data, bounds_list[i]);
+    bounds.origin += glyph_data.advance;
+  }
   if (!is_horizontal_run)
     bounds.ConvertVerticalRunToLogical(current_font_data.GetFontMetrics());
   glyph_bounding_box_.Unite(bounds.bounds);
diff --git a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
index 63f4e48..5ebad974d 100644
--- a/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
+++ b/third_party/blink/renderer/platform/fonts/shaping/shape_result.h
@@ -301,6 +301,8 @@
                              unsigned start_glyph,
                              unsigned num_glyphs,
                              hb_buffer_t*);
+  template <bool is_horizontal_run>
+  void ComputeGlyphBounds(const ShapeResult::RunInfo&);
   void InsertRun(std::unique_ptr<ShapeResult::RunInfo>,
                  unsigned start_glyph,
                  unsigned num_glyphs,
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.cc b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
index 4b93a92..811beb0 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.cc
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.cc
@@ -354,6 +354,20 @@
   return FloatRect(bounds);
 }
 
+void SimpleFontData::BoundsForGlyphs(const Vector<Glyph, 256> glyphs,
+                                     Vector<FloatRect, 256>* bounds) const {
+  DCHECK_EQ(glyphs.size(), bounds->size());
+
+  if (!platform_data_.size())
+    return;
+
+  Vector<SkRect, 256> skia_bounds(glyphs.size());
+  SkiaTextMetrics(&paint_).GetSkiaBoundsForGlyphs(glyphs, skia_bounds.data());
+
+  for (unsigned i = 0; i < skia_bounds.size(); i++)
+    (*bounds)[i] = FloatRect(skia_bounds[i]);
+}
+
 float SimpleFontData::PlatformWidthForGlyph(Glyph glyph) const {
   if (!platform_data_.size())
     return 0;
diff --git a/third_party/blink/renderer/platform/fonts/simple_font_data.h b/third_party/blink/renderer/platform/fonts/simple_font_data.h
index 0c159ad6..cbf96463 100644
--- a/third_party/blink/renderer/platform/fonts/simple_font_data.h
+++ b/third_party/blink/renderer/platform/fonts/simple_font_data.h
@@ -110,6 +110,7 @@
   }
 
   FloatRect BoundsForGlyph(Glyph) const;
+  void BoundsForGlyphs(const Vector<Glyph, 256>, Vector<FloatRect, 256>*) const;
   FloatRect PlatformBoundsForGlyph(Glyph) const;
   float WidthForGlyph(Glyph) const;
   float PlatformWidthForGlyph(Glyph) const;
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
index 47ee36d..ea9fdbc6 100644
--- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
+++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.cc
@@ -72,6 +72,27 @@
   }
 }
 
+void SkiaTextMetrics::GetSkiaBoundsForGlyphs(const Vector<Glyph, 256> glyphs,
+                                             SkRect* bounds) {
+#if defined(OS_MACOSX)
+  for (unsigned i = 0; i < glyphs.size(); i++) {
+    GetSkiaBoundsForGlyph(glyphs[i], &bounds[i]);
+  }
+#else
+  static_assert(sizeof(Glyph) == 2, "Skia expects 2 bytes glyph id.");
+  paint_->getTextWidths(glyphs.data(), sizeof(Glyph) * glyphs.size(), nullptr,
+                        bounds);
+
+  if (!paint_->isSubpixelText()) {
+    for (unsigned i = 0; i < glyphs.size(); i++) {
+      SkIRect ir;
+      bounds[i].roundOut(&ir);
+      bounds[i].set(ir);
+    }
+  }
+#endif
+}
+
 float SkiaTextMetrics::GetSkiaWidthForGlyph(Glyph glyph) {
   SkScalar sk_width;
   paint_->getTextWidths(&glyph, sizeof(glyph), &sk_width, nullptr);
diff --git a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
index e8a38f94..e49ccee 100644
--- a/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
+++ b/third_party/blink/renderer/platform/fonts/skia/skia_text_metrics.h
@@ -9,6 +9,7 @@
 
 #include <SkPaint.h>
 #include <hb.h>
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
@@ -20,6 +21,7 @@
   void GetGlyphExtentsForHarfBuzz(hb_codepoint_t, hb_glyph_extents_t*);
 
   void GetSkiaBoundsForGlyph(Glyph, SkRect* bounds);
+  void GetSkiaBoundsForGlyphs(const Vector<Glyph, 256>, SkRect*);
   float GetSkiaWidthForGlyph(Glyph);
 
   static hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value);
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.cc b/third_party/blink/renderer/platform/heap/heap_compact.cc
index f9309e1..4594fbfd 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.cc
+++ b/third_party/blink/renderer/platform/heap/heap_compact.cc
@@ -13,6 +13,7 @@
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 namespace blink {
@@ -356,7 +357,7 @@
   if (!do_compact_)
     return;
 
-  traced_slots_.insert(slot);
+  Fixups().Add(slot);
 }
 
 void HeapCompact::RegisterMovingObjectCallback(MovableReference reference,
@@ -421,13 +422,6 @@
 void HeapCompact::StartThreadCompaction() {
   if (!do_compact_)
     return;
-
-  DCHECK(fixups_);
-  // The mapping between the slots and the backing stores are created
-  for (auto** slot : traced_slots_) {
-    fixups_->Add(slot);
-  }
-  traced_slots_.clear();
 }
 
 void HeapCompact::FinishThreadCompaction() {
diff --git a/third_party/blink/renderer/platform/heap/heap_compact.h b/third_party/blink/renderer/platform/heap/heap_compact.h
index b11f12e0..dc32e77b 100644
--- a/third_party/blink/renderer/platform/heap/heap_compact.h
+++ b/third_party/blink/renderer/platform/heap/heap_compact.h
@@ -10,7 +10,6 @@
 #include "base/memory/ptr_util.h"
 #include "third_party/blink/renderer/platform/heap/blink_gc.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
 #include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
 
 #include <bitset>
@@ -165,11 +164,6 @@
   // the range of BlinkGC::ArenaIndices.
   unsigned compactable_arenas_;
 
-  // The set is to remember slots traced during the incremental and atomic
-  // marking phases. The mapping between the slots and the backing stores are
-  // created at the atomic pause phase.
-  HashSet<MovableReference*> traced_slots_;
-
   static bool force_compaction_gc_;
 };
 
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.cc b/third_party/blink/renderer/platform/loader/cors/cors.cc
index 38ad08b..cf4b5be 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -133,20 +133,17 @@
   return network::cors::IsCORSEnabledRequestMode(request_mode);
 }
 
-bool EnsurePreflightResultAndCacheOnSuccess(
+base::Optional<network::CORSErrorStatus> EnsurePreflightResultAndCacheOnSuccess(
     const HTTPHeaderMap& response_header_map,
     const String& origin,
     const KURL& request_url,
     const String& request_method,
     const HTTPHeaderMap& request_header_map,
-    network::mojom::FetchCredentialsMode request_credentials_mode,
-    String* error_description) {
+    network::mojom::FetchCredentialsMode request_credentials_mode) {
   DCHECK(!origin.IsNull());
   DCHECK(!request_method.IsNull());
-  DCHECK(error_description);
 
   base::Optional<network::mojom::CORSError> error;
-  base::Optional<network::CORSErrorStatus> status;
 
   std::unique_ptr<network::cors::PreflightResult> result =
       network::cors::PreflightResult::Create(
@@ -158,37 +155,23 @@
           GetOptionalHeaderValue(response_header_map,
                                  HTTPNames::Access_Control_Max_Age),
           &error);
-  if (error) {
-    *error_description = CORS::GetErrorString(
-        CORS::ErrorParameter::CreateForPreflightResponseCheck(*error,
-                                                              String()));
-    return false;
-  }
+  if (error)
+    return network::CORSErrorStatus(*error);
 
+  base::Optional<network::CORSErrorStatus> status;
   status = result->EnsureAllowedCrossOriginMethod(
       std::string(request_method.Ascii().data()));
-  if (status) {
-    *error_description = CORS::GetErrorString(
-        CORS::ErrorParameter::CreateForPreflightResponseCheck(
-            status->cors_error, request_method));
-    return false;
-  }
+  if (status)
+    return status;
 
   status = result->EnsureAllowedCrossOriginHeaders(
       *CreateNetHttpRequestHeaders(request_header_map));
-  if (status) {
-    *error_description = CORS::GetErrorString(
-        CORS::ErrorParameter::CreateForPreflightResponseCheck(
-            status->cors_error, String(status->failed_parameter.data(),
-                                       status->failed_parameter.length())));
-    return false;
-  }
-
-  DCHECK(!error);
+  if (status)
+    return status;
 
   GetPerThreadPreflightCache().AppendEntry(std::string(origin.Ascii().data()),
                                            request_url, std::move(result));
-  return true;
+  return base::nullopt;
 }
 
 bool CheckIfRequestCanSkipPreflight(
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.h b/third_party/blink/renderer/platform/loader/cors/cors.h
index 8030442..7d25995b 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.h
+++ b/third_party/blink/renderer/platform/loader/cors/cors.h
@@ -49,14 +49,14 @@
 
 PLATFORM_EXPORT bool IsCORSEnabledRequestMode(network::mojom::FetchRequestMode);
 
-PLATFORM_EXPORT bool EnsurePreflightResultAndCacheOnSuccess(
+PLATFORM_EXPORT base::Optional<network::CORSErrorStatus>
+EnsurePreflightResultAndCacheOnSuccess(
     const HTTPHeaderMap& response_header_map,
     const String& origin,
     const KURL& request_url,
     const String& request_method,
     const HTTPHeaderMap& request_header_map,
-    network::mojom::FetchCredentialsMode request_credentials_mode,
-    String* error_description);
+    network::mojom::FetchCredentialsMode request_credentials_mode);
 
 PLATFORM_EXPORT bool CheckIfRequestCanSkipPreflight(
     const String& origin,
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
index e25acfc7..dbc2740fa 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors_error_string.cc
@@ -4,9 +4,15 @@
 
 #include "third_party/blink/renderer/platform/loader/cors/cors_error_string.h"
 
+#include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+#include "third_party/blink/renderer/platform/wtf/ascii_ctype.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
 
 namespace blink {
 
@@ -14,360 +20,195 @@
 
 namespace {
 
-const KURL& GetInvalidURL() {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(KURL, invalid_url, ());
-  return invalid_url;
+template <size_t N>
+void Append(StringBuilder& builder, const StringView (&views)[N]) {
+  for (size_t i = 0; i < N; ++i)
+    builder.Append(views[i]);
 }
 
-bool IsInterestingStatusCode(int status_code) {
-  // Predicate that gates what status codes should be included in console error
-  // messages for responses containing no access control headers.
-  return status_code >= 400;
-}
-
-ErrorParameter CreateWrongParameter(network::mojom::CORSError error) {
-  return ErrorParameter(
-      error, GetInvalidURL(), GetInvalidURL(), 0 /* status_code */,
-      *SecurityOrigin::CreateUniqueOpaque(),
-      WebURLRequest::kRequestContextUnspecified, String(), true);
-}
-
-}  // namespace
-
-// static
-ErrorParameter ErrorParameter::Create(
-    const network::CORSErrorStatus& error_status,
-    const KURL& first_url,
-    const KURL& second_url,
-    const int status_code,
-    const SecurityOrigin& origin,
-    const WebURLRequest::RequestContext context) {
-  return ErrorParameter(error_status.cors_error, first_url, second_url,
-                        status_code, origin, context,
-                        String(error_status.failed_parameter.c_str()), false);
-}
-
-// static
-ErrorParameter ErrorParameter::CreateForDisallowedByMode(
-    const KURL& request_url) {
-  return ErrorParameter(network::mojom::CORSError::kDisallowedByMode,
-                        request_url, GetInvalidURL(), 0 /* status_code */,
-                        *SecurityOrigin::CreateUniqueOpaque(),
-                        WebURLRequest::kRequestContextUnspecified, String(),
-                        false);
-}
-
-// static
-ErrorParameter ErrorParameter::CreateForInvalidResponse(
-    const KURL& request_url,
-    const SecurityOrigin& origin) {
-  return ErrorParameter(network::mojom::CORSError::kInvalidResponse,
-                        request_url, GetInvalidURL(), 0 /* status_code */,
-                        origin, WebURLRequest::kRequestContextUnspecified,
-                        String(), false);
-}
-
-// static
-ErrorParameter ErrorParameter::CreateForAccessCheck(
-    const network::CORSErrorStatus& error_status,
-    const KURL& request_url,
-    int response_status_code,
-    const SecurityOrigin& origin,
-    const WebURLRequest::RequestContext context,
-    const KURL& redirect_url) {
-  switch (error_status.cors_error) {
-    case network::mojom::CORSError::kInvalidResponse:
-    case network::mojom::CORSError::kWildcardOriginNotAllowed:
-    case network::mojom::CORSError::kMissingAllowOriginHeader:
-    case network::mojom::CORSError::kMultipleAllowOriginValues:
-    case network::mojom::CORSError::kInvalidAllowOriginValue:
-    case network::mojom::CORSError::kAllowOriginMismatch:
-    case network::mojom::CORSError::kInvalidAllowCredentials:
-    case network::mojom::CORSError::kCORSDisabledScheme:
+bool IsPreflightError(network::mojom::CORSError error_code) {
+  switch (error_code) {
     case network::mojom::CORSError::kPreflightWildcardOriginNotAllowed:
     case network::mojom::CORSError::kPreflightMissingAllowOriginHeader:
     case network::mojom::CORSError::kPreflightMultipleAllowOriginValues:
     case network::mojom::CORSError::kPreflightInvalidAllowOriginValue:
     case network::mojom::CORSError::kPreflightAllowOriginMismatch:
     case network::mojom::CORSError::kPreflightInvalidAllowCredentials:
-      return ErrorParameter(error_status.cors_error, request_url, redirect_url,
-                            response_status_code, origin, context,
-                            String(error_status.failed_parameter.c_str()),
-                            false);
-    default:
-      NOTREACHED();
-  }
-  return CreateWrongParameter(error_status.cors_error);
-}
-
-// static
-ErrorParameter ErrorParameter::CreateForPreflightStatusCheck(
-    int response_status_code) {
-  return ErrorParameter(network::mojom::CORSError::kPreflightInvalidStatus,
-                        GetInvalidURL(), GetInvalidURL(), response_status_code,
-                        *SecurityOrigin::CreateUniqueOpaque(),
-                        WebURLRequest::kRequestContextUnspecified, String(),
-                        false);
-}
-
-// static
-ErrorParameter ErrorParameter::CreateForDisallowedRedirect() {
-  return ErrorParameter(
-      network::mojom::CORSError::kPreflightDisallowedRedirect, GetInvalidURL(),
-      GetInvalidURL(), 0, *SecurityOrigin::CreateUniqueOpaque(),
-      WebURLRequest::kRequestContextUnspecified, String(), false);
-}
-
-// static
-ErrorParameter ErrorParameter::CreateForExternalPreflightCheck(
-    const network::CORSErrorStatus& error) {
-  switch (error.cors_error) {
+    case network::mojom::CORSError::kPreflightInvalidStatus:
+    case network::mojom::CORSError::kPreflightDisallowedRedirect:
     case network::mojom::CORSError::kPreflightMissingAllowExternal:
     case network::mojom::CORSError::kPreflightInvalidAllowExternal:
-      return ErrorParameter(error.cors_error, GetInvalidURL(), GetInvalidURL(),
-                            0 /* status_code */,
-                            *SecurityOrigin::CreateUniqueOpaque(),
-                            WebURLRequest::kRequestContextUnspecified,
-                            error.failed_parameter.c_str(), false);
+      return true;
     default:
-      NOTREACHED();
+      return false;
   }
-  return CreateWrongParameter(error.cors_error);
 }
 
-// static
-ErrorParameter ErrorParameter::CreateForPreflightResponseCheck(
-    const network::mojom::CORSError error,
-    const String& hint) {
-  switch (error) {
-    case network::mojom::CORSError::kInvalidAllowMethodsPreflightResponse:
-    case network::mojom::CORSError::kInvalidAllowHeadersPreflightResponse:
-    case network::mojom::CORSError::kMethodDisallowedByPreflightResponse:
-    case network::mojom::CORSError::kHeaderDisallowedByPreflightResponse:
-      return ErrorParameter(
-          error, GetInvalidURL(), GetInvalidURL(), 0 /* status_code */,
-          *SecurityOrigin::CreateUniqueOpaque(),
-          WebURLRequest::kRequestContextUnspecified, hint, false);
-    default:
-      NOTREACHED();
-  }
-  return CreateWrongParameter(error);
-}
+}  // namespace
 
-// static
-ErrorParameter ErrorParameter::CreateForRedirectCheck(
-    network::mojom::CORSError error,
-    const KURL& request_url,
-    const KURL& redirect_url) {
-  switch (error) {
-    case network::mojom::CORSError::kRedirectDisallowedScheme:
-    case network::mojom::CORSError::kRedirectContainsCredentials:
-      return ErrorParameter(
-          error, request_url, redirect_url, 0 /* status_code */,
-          *SecurityOrigin::CreateUniqueOpaque(),
-          WebURLRequest::kRequestContextUnspecified, String(), false);
-    default:
-      NOTREACHED();
-  }
-  return CreateWrongParameter(error);
-}
-
-ErrorParameter::ErrorParameter(const network::mojom::CORSError error,
-                               const KURL& first_url,
-                               const KURL& second_url,
-                               const int status_code,
-                               const SecurityOrigin& origin,
-                               const WebURLRequest::RequestContext context,
-                               const String& hint,
-                               bool unknown)
-    : error(error),
-      first_url(first_url),
-      second_url(second_url),
-      status_code(status_code),
-      origin(origin),
-      context(context),
-      hint(hint),
-      unknown(unknown) {}
-
-String GetErrorString(const ErrorParameter& param) {
-  static const char kNoCorsInformation[] =
+String GetErrorString(const network::CORSErrorStatus& status,
+                      const KURL& initial_request_url,
+                      const KURL& last_request_url,
+                      const SecurityOrigin& origin,
+                      Resource::Type resource_type,
+                      const AtomicString& initiator_name) {
+  StringBuilder builder;
+  static constexpr char kNoCorsInformation[] =
       " Have the server send the header with a valid value, or, if an opaque "
       "response serves your needs, set the request's mode to 'no-cors' to "
       "fetch the resource with CORS disabled.";
-  static const char kPreflightInformation[] =
-      "Response to preflight request doesn't pass access control check: ";
 
   using CORSError = network::mojom::CORSError;
-  const auto& hint = param.hint;
+  const StringView hint(status.failed_parameter.data(),
+                        status.failed_parameter.size());
 
-  if (param.unknown)
-    return String::Format("CORS error, code %d", static_cast<int>(param.error));
+  const char* resource_kind_raw =
+      Resource::ResourceTypeToString(resource_type, initiator_name);
+  String resource_kind(resource_kind_raw);
+  if (strlen(resource_kind_raw) >= 2 && IsASCIILower(resource_kind_raw[1]))
+    resource_kind = resource_kind.LowerASCII();
 
-  String redirect_denied =
-      param.second_url.IsValid()
-          ? String::Format(
-                "Redirect from '%s' to '%s' has been blocked by CORS policy: ",
-                param.first_url.GetString().Utf8().data(),
-                param.second_url.GetString().Utf8().data())
-          : String();
+  Append(builder, {"Access to ", resource_kind, " at '",
+                   last_request_url.GetString(), "' "});
+  if (initial_request_url != last_request_url) {
+    Append(builder,
+           {"(redirected from '", initial_request_url.GetString(), "') "});
+  }
+  Append(builder, {"from origin '", origin.ToString(),
+                   "' has been blocked by CORS policy: "});
 
-  switch (param.error) {
+  if (IsPreflightError(status.cors_error)) {
+    builder.Append(
+        "Response to preflight request doesn't pass access control check: ");
+  }
+
+  switch (status.cors_error) {
     case CORSError::kDisallowedByMode:
-      return String::Format(
-          "Failed to load '%s': Cross origin requests are not allowed by "
-          "request mode.",
-          param.first_url.GetString().Utf8().data());
+      builder.Append("Cross origin requests are not allowed by request mode.");
+      break;
     case CORSError::kInvalidResponse:
-      return String::Format(
-          "%sInvalid response. Origin '%s' is therefore not allowed access.",
-          redirect_denied.Utf8().data(), param.origin.ToString().Utf8().data());
+      builder.Append("The response is invalid.");
+      break;
     case CORSError::kWildcardOriginNotAllowed:
     case CORSError::kPreflightWildcardOriginNotAllowed:
-      return String::Format(
-          "%s%sThe value of the 'Access-Control-Allow-Origin' header in the "
+      builder.Append(
+          "The value of the 'Access-Control-Allow-Origin' header in the "
           "response must not be the wildcard '*' when the request's "
-          "credentials mode is 'include'. Origin '%s' is therefore not allowed "
-          "access.%s",
-          param.error == CORSError::kPreflightWildcardOriginNotAllowed
-              ? kPreflightInformation
-              : "",
-          redirect_denied.Utf8().data(), param.origin.ToString().Utf8().data(),
-          param.context == WebURLRequest::kRequestContextXMLHttpRequest
-              ? " The credentials mode of requests initiated by the "
-                "XMLHttpRequest is controlled by the withCredentials attribute."
-              : "");
+          "credentials mode is 'include'.");
+      if (initiator_name == FetchInitiatorTypeNames::xmlhttprequest) {
+        builder.Append(
+            " The credentials mode of requests initiated by the "
+            "XMLHttpRequest is controlled by the withCredentials attribute.");
+      }
+      break;
     case CORSError::kMissingAllowOriginHeader:
     case CORSError::kPreflightMissingAllowOriginHeader:
-      return String::Format(
-          "%s%sNo 'Access-Control-Allow-Origin' header is present on the "
-          "requested resource. Origin '%s' is therefore not allowed access."
-          "%s%s",
-          param.error == CORSError::kPreflightMissingAllowOriginHeader
-              ? kPreflightInformation
-              : "",
-          redirect_denied.Utf8().data(), param.origin.ToString().Utf8().data(),
-          IsInterestingStatusCode(param.status_code)
-              ? String::Format(" The response had HTTP status code %d.",
-                               param.status_code)
-                    .Utf8()
-                    .data()
-              : "",
-          param.context == WebURLRequest::kRequestContextFetch
-              ? " If an opaque response serves your needs, set the request's "
-                "mode to 'no-cors' to fetch the resource with CORS disabled."
-              : "");
+      builder.Append(
+          "No 'Access-Control-Allow-Origin' header is present on the "
+          "requested resource.");
+      if (initiator_name == FetchInitiatorTypeNames::fetch) {
+        builder.Append(
+            " If an opaque response serves your needs, set the request's "
+            "mode to 'no-cors' to fetch the resource with CORS disabled.");
+      }
+      break;
     case CORSError::kMultipleAllowOriginValues:
     case CORSError::kPreflightMultipleAllowOriginValues:
-      return String::Format(
-          "%s%sThe 'Access-Control-Allow-Origin' header contains multiple "
-          "values '%s', but only one is allowed. Origin '%s' is therefore not "
-          "allowed access.%s",
-          param.error == CORSError::kPreflightMultipleAllowOriginValues
-              ? kPreflightInformation
-              : "",
-          redirect_denied.Utf8().data(), hint.Utf8().data(),
-          param.origin.ToString().Utf8().data(),
-          param.context == WebURLRequest::kRequestContextFetch
-              ? kNoCorsInformation
-              : "");
+      Append(builder,
+             {"The 'Access-Control-Allow-Origin' header contains multiple "
+              "values '",
+              hint, "', but only one is allowed."});
+      if (initiator_name == FetchInitiatorTypeNames::fetch)
+        builder.Append(kNoCorsInformation);
+      break;
     case CORSError::kInvalidAllowOriginValue:
     case CORSError::kPreflightInvalidAllowOriginValue:
-      return String::Format(
-          "%s%sThe 'Access-Control-Allow-Origin' header contains the invalid "
-          "value '%s'. Origin '%s' is therefore not allowed access.%s",
-          param.error == CORSError::kPreflightInvalidAllowOriginValue
-              ? kPreflightInformation
-              : "",
-          redirect_denied.Utf8().data(), hint.Utf8().data(),
-          param.origin.ToString().Utf8().data(),
-          param.context == WebURLRequest::kRequestContextFetch
-              ? kNoCorsInformation
-              : "");
+      Append(builder, {"The 'Access-Control-Allow-Origin' header contains the "
+                       "invalid value '",
+                       hint, "'."});
+      if (initiator_name == FetchInitiatorTypeNames::fetch)
+        builder.Append(kNoCorsInformation);
+      break;
     case CORSError::kAllowOriginMismatch:
     case CORSError::kPreflightAllowOriginMismatch:
-      return String::Format(
-          "%s%sThe 'Access-Control-Allow-Origin' header has a value '%s' that "
-          "is not equal to the supplied origin. Origin '%s' is therefore not "
-          "allowed access.%s",
-          param.error == CORSError::kPreflightAllowOriginMismatch
-              ? kPreflightInformation
-              : "",
-          redirect_denied.Utf8().data(), hint.Utf8().data(),
-          param.origin.ToString().Utf8().data(),
-          param.context == WebURLRequest::kRequestContextFetch
-              ? kNoCorsInformation
-              : "");
+      Append(builder, {"The 'Access-Control-Allow-Origin' header has a value '",
+                       hint, "' that is not equal to the supplied origin."});
+      if (initiator_name == FetchInitiatorTypeNames::fetch)
+        builder.Append(kNoCorsInformation);
+      break;
     case CORSError::kInvalidAllowCredentials:
     case CORSError::kPreflightInvalidAllowCredentials:
-      return String::Format(
-          "%s%sThe value of the 'Access-Control-Allow-Credentials' header in "
-          "the response is '%s' which must be 'true' when the request's "
-          "credentials mode is 'include'. Origin '%s' is therefore not allowed "
-          "access.%s",
-          param.error == CORSError::kPreflightInvalidAllowCredentials
-              ? kPreflightInformation
-              : "",
-          redirect_denied.Utf8().data(), hint.Utf8().data(),
-          param.origin.ToString().Utf8().data(),
-          (param.context == WebURLRequest::kRequestContextXMLHttpRequest
-               ? " The credentials mode of requests initiated by the "
-                 "XMLHttpRequest is controlled by the withCredentials "
-                 "attribute."
-               : ""));
+      Append(builder,
+             {"The value of the 'Access-Control-Allow-Credentials' header in "
+              "the response is '",
+              hint,
+              "' which must be 'true' when the request's credentials mode is "
+              "'include'."});
+      if (initiator_name == FetchInitiatorTypeNames::xmlhttprequest) {
+        builder.Append(
+            " The credentials mode of requests initiated by the "
+            "XMLHttpRequest is controlled by the withCredentials "
+            "attribute.");
+      }
+      break;
     case CORSError::kCORSDisabledScheme:
-      return String::Format(
-          "Cross origin requests are only supported for protocol schemes: %s.",
-          SchemeRegistry::ListOfCORSEnabledURLSchemes().Ascii().data());
+      Append(builder,
+             {"Cross origin requests are only supported for protocol schemes: ",
+              SchemeRegistry::ListOfCORSEnabledURLSchemes(), "."});
+      break;
     case CORSError::kPreflightInvalidStatus:
-      return String("Response for preflight does not have HTTP ok status.");
+      builder.Append("It does not have HTTP ok status.");
+      break;
     case CORSError::kPreflightDisallowedRedirect:
-      return String("Response for preflight is invalid (redirect)");
+      builder.Append("Redirect is not allowed for a preflight request.");
+      break;
     case CORSError::kPreflightMissingAllowExternal:
-      return String(
+      builder.Append(
           "No 'Access-Control-Allow-External' header was present in the "
           "preflight response for this external request (This is an "
           "experimental header which is defined in "
           "'https://wicg.github.io/cors-rfc1918/').");
+      break;
     case CORSError::kPreflightInvalidAllowExternal:
-      return String::Format(
-          "The 'Access-Control-Allow-External' header in the preflight "
-          "response for this external request had a value of '%s',  not 'true' "
-          "(This is an experimental header which is defined in "
-          "'https://wicg.github.io/cors-rfc1918/').",
-          hint.Utf8().data());
+      Append(builder,
+             {"The 'Access-Control-Allow-External' header in the preflight "
+              "response for this external request had a value of '",
+              hint,
+              "',  not 'true' (This is an experimental header which is defined "
+              "in 'https://wicg.github.io/cors-rfc1918/')."});
+      break;
     case CORSError::kInvalidAllowMethodsPreflightResponse:
-      return String(
+      builder.Append(
           "Cannot parse Access-Control-Allow-Methods response header field in "
           "preflight response.");
+      break;
     case CORSError::kInvalidAllowHeadersPreflightResponse:
-      return String(
+      builder.Append(
           "Cannot parse Access-Control-Allow-Headers response header field in "
           "preflight response.");
+      break;
     case CORSError::kMethodDisallowedByPreflightResponse:
-      return String::Format(
-          "Method %s is not allowed by Access-Control-Allow-Methods in "
-          "preflight response.",
-          hint.Utf8().data());
+      Append(builder, {"Method ", hint,
+                       " is not allowed by Access-Control-Allow-Methods in "
+                       "preflight response."});
+      break;
     case CORSError::kHeaderDisallowedByPreflightResponse:
-      return String::Format(
-          "Request header field %s is not allowed by "
-          "Access-Control-Allow-Headers in preflight response.",
-          hint.Utf8().data());
+      Append(builder, {"Request header field ", hint,
+                       " is not allowed by "
+                       "Access-Control-Allow-Headers in preflight response."});
+      break;
     case CORSError::kRedirectDisallowedScheme:
-      return String::Format(
-          "%sRedirect location '%s' has a disallowed scheme for cross-origin "
-          "requests.",
-          redirect_denied.Utf8().data(),
-          param.second_url.GetString().Utf8().data());
+      Append(builder, {"Redirect location '", hint,
+                       "' has a disallowed scheme for cross-origin "
+                       "requests."});
+      break;
     case CORSError::kRedirectContainsCredentials:
-      return String::Format(
-          "%sRedirect location '%s' contains a username and password, which is "
-          "disallowed for cross-origin requests.",
-          redirect_denied.Utf8().data(),
-          param.second_url.GetString().Utf8().data());
+      Append(builder, {"Redirect location '", hint,
+                       "' contains a username and password, which is "
+                       "disallowed for cross-origin requests."});
+      break;
   }
-  NOTREACHED();
-  return String();
+  return builder.ToString();
 }
 
 }  // namespace CORS
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_error_string.h b/third_party/blink/renderer/platform/loader/cors/cors_error_string.h
index 6f6396b..5a01980 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors_error_string.h
+++ b/third_party/blink/renderer/platform/loader/cors/cors_error_string.h
@@ -9,100 +9,26 @@
 #include "services/network/public/cpp/cors/cors_error_status.h"
 #include "services/network/public/mojom/cors.mojom-shared.h"
 #include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/renderer/platform/loader/fetch/resource.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/forward.h"
 
 namespace blink {
 
+class KURL;
 class SecurityOrigin;
 
 // CORS error strings related utility functions.
 namespace CORS {
 
-// A struct to pass error dependent arguments for |GetErrorString|.
-struct PLATFORM_EXPORT ErrorParameter {
-  // Creates an ErrorParameter for generic cases. Use this function if |error|
-  // can contain any.
-  static ErrorParameter Create(const network::CORSErrorStatus&,
-                               const KURL& first_url,
-                               const KURL& second_url,
-                               const int status_code,
-                               const SecurityOrigin&,
-                               const WebURLRequest::RequestContext);
-
-  // Creates an ErrorParameter for kDisallowedByMode.
-  static ErrorParameter CreateForDisallowedByMode(const KURL& request_url);
-
-  // Creates an ErrorParameter for kInvalidResponse.
-  static ErrorParameter CreateForInvalidResponse(const KURL& request_url,
-                                                 const SecurityOrigin&);
-
-  // Creates an ErrorParameter for an error that CORS::CheckAccess() returns.
-  // |error| for redirect check needs to specify a valid |redirect_url|. The
-  // |redirect_url| can be omitted not to include redirect related information.
-  static ErrorParameter CreateForAccessCheck(
-      const network::CORSErrorStatus&,
-      const KURL& request_url,
-      int response_status_code,
-      const SecurityOrigin&,
-      const WebURLRequest::RequestContext,
-      const KURL& redirect_url = KURL());
-
-  // Creates an ErrorParameter for kPreflightInvalidStatus that
-  // CORS::CheckPreflight() returns.
-  static ErrorParameter CreateForPreflightStatusCheck(int response_status_code);
-
-  // Creates an ErrorParameter for kPreflightDisallowedRedirect.
-  static ErrorParameter CreateForDisallowedRedirect();
-
-  // Creates an ErrorParameter for an error that CORS::CheckExternalPreflight()
-  // returns.
-  static ErrorParameter CreateForExternalPreflightCheck(
-      const network::CORSErrorStatus&);
-
-  // Creates an ErrorParameter for an error that is related to CORS-preflight
-  // response checks.
-  // |hint| should contain a banned request method for
-  // kMethodDisallowedByPreflightResponse, a banned request header name for
-  // kHeaderDisallowedByPreflightResponse, or can be omitted for others.
-  static ErrorParameter CreateForPreflightResponseCheck(
-      const network::mojom::CORSError,
-      const String& hint);
-
-  // Creates an ErrorParameter for CORS::CheckRedirectLocation() returns.
-  static ErrorParameter CreateForRedirectCheck(network::mojom::CORSError,
-                                               const KURL& request_url,
-                                               const KURL& redirect_url);
-
-  // Should not be used directly by external callers. Use Create functions
-  // above.
-  ErrorParameter(const network::mojom::CORSError,
-                 const KURL& first_url,
-                 const KURL& second_url,
-                 const int status_code,
-                 const SecurityOrigin&,
-                 const WebURLRequest::RequestContext,
-                 const String& hint,
-                 bool unknown);
-
-  // Members that this struct carries.
-  const network::mojom::CORSError error;
-  const KURL& first_url;
-  const KURL& second_url;
-  const int status_code;
-  const SecurityOrigin& origin;
-  const WebURLRequest::RequestContext context;
-  // Do not use a reference here. See https://crbug.com/851419.
-  const String hint;
-
-  // Set to true when an ErrorParameter was created in a wrong way. Used in
-  // GetErrorString() to be robust for coding errors.
-  const bool unknown;
-};
-
 // Stringify CORSError mainly for inspector messages. Generated string should
 // not be exposed to JavaScript for security reasons.
-PLATFORM_EXPORT String GetErrorString(const ErrorParameter&);
+PLATFORM_EXPORT String GetErrorString(const network::CORSErrorStatus& status,
+                                      const KURL& initial_request_url,
+                                      const KURL& last_request_url,
+                                      const SecurityOrigin& origin,
+                                      Resource::Type resource_type,
+                                      const AtomicString& initiator_name);
 
 }  // namespace CORS
 
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
index e0fbcb3..1670ba04 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_error.cc
@@ -87,6 +87,7 @@
     base::Optional<network::CORSErrorStatus> cors_error_status)
     : error_code_(error_code),
       failing_url_(url),
+      is_access_check_(cors_error_status.has_value()),
       cors_error_status_(cors_error_status) {
   DCHECK_NE(error_code_, 0);
   InitializeDescription();
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index 8911e7f7..ba4068d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -334,10 +334,10 @@
 
         if (!unused_preload) {
           Context().AddErrorConsoleMessage(
-              CORS::GetErrorString(CORS::ErrorParameter::Create(
-                  *cors_error, redirect_response.Url(), new_url,
-                  redirect_response.HttpStatusCode(), *source_origin.get(),
-                  resource_->LastResourceRequest().GetRequestContext())),
+              CORS::GetErrorString(*cors_error, initial_request.Url(),
+                                   redirect_response.Url(),
+                                   *source_origin.get(), resource_->GetType(),
+                                   resource_->Options().initiator_info.name),
               FetchContext::kJSSource);
         }
 
@@ -505,18 +505,10 @@
 
   String resource_type = Resource::ResourceTypeToString(
       resource_->GetType(), resource_->Options().initiator_info.name);
-  error_msg.Append("Access to ");
-  error_msg.Append(resource_type);
-  error_msg.Append(" at '");
-  error_msg.Append(response.Url().GetString());
-  error_msg.Append("' from origin '");
-  error_msg.Append(source_origin->ToString());
-  error_msg.Append("' has been blocked by CORS policy: ");
-  error_msg.Append(CORS::GetErrorString(CORS::ErrorParameter::Create(
-      *cors_error, initial_request.Url(), KURL(),
-      response_for_access_control.HttpStatusCode(), *source_origin,
-      initial_request.GetRequestContext())));
-
+  error_msg.Append(CORS::GetErrorString(
+      *cors_error, initial_request.Url(),
+      resource_->LastResourceRequest().Url(), *source_origin,
+      resource_->GetType(), resource_->Options().initiator_info.name));
   return CORSStatus::kFailed;
 }
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 5a7e167..234112b 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -626,6 +626,10 @@
       status: "stable",
     },
     {
+      name: "IsolatedCodeCache",
+      status: "experimental",
+    },
+    {
       // Tracks "jank" from layout objects changing their visual location
       // between animation frames (see crbug.com/581518).
       name: "JankTracking",
diff --git a/third_party/blink/renderer/platform/scheduler/BUILD.gn b/third_party/blink/renderer/platform/scheduler/BUILD.gn
index eb78599..731d87e 100644
--- a/third_party/blink/renderer/platform/scheduler/BUILD.gn
+++ b/third_party/blink/renderer/platform/scheduler/BUILD.gn
@@ -15,8 +15,6 @@
     "child/process_state.cc",
     "child/process_state.h",
     "child/single_thread_idle_task_runner.cc",
-    "child/task_queue_with_task_type.cc",
-    "child/task_queue_with_task_type.h",
     "child/webthread_base.cc",
     "child/webthread_impl_for_worker_scheduler.cc",
     "child/webthread_impl_for_worker_scheduler.h",
@@ -44,8 +42,6 @@
     "common/throttling/throttled_time_domain.h",
     "common/throttling/wake_up_budget_pool.cc",
     "common/throttling/wake_up_budget_pool.h",
-    "common/total_duration_metric_reporter.cc",
-    "common/total_duration_metric_reporter.h",
     "common/unprioritized_resource_loading_task_runner_handle.cc",
     "common/unprioritized_resource_loading_task_runner_handle.h",
     "common/web_resource_loading_task_runner_handle.cc",
@@ -102,7 +98,6 @@
     "renderer/webthread_impl_for_renderer_scheduler.cc",
     "renderer/webthread_impl_for_renderer_scheduler.h",
     "util/aggregated_metric_reporter.h",
-    "util/task_duration_metric_reporter.h",
     "util/thread_cpu_throttler.cc",
     "util/thread_cpu_throttler.h",
     "util/thread_load_tracker.cc",
@@ -134,6 +129,7 @@
   deps = [
     "//base",
     "//cc",
+    "//components/scheduling_metrics",
     "//device/base/synchronization",
     "//services/metrics/public/cpp:ukm_builders",
     "//third_party/blink/renderer/platform:make_platform_generated",
@@ -176,7 +172,6 @@
     "common/scheduler_helper_unittest.cc",
     "common/throttling/budget_pool_unittest.cc",
     "common/throttling/task_queue_throttler_unittest.cc",
-    "common/total_duration_metric_reporter_unittest.cc",
     "main_thread/auto_advancing_virtual_time_domain_unittest.cc",
     "main_thread/deadline_task_runner_unittest.cc",
     "main_thread/frame_scheduler_impl_unittest.cc",
diff --git a/third_party/blink/renderer/platform/scheduler/DEPS b/third_party/blink/renderer/platform/scheduler/DEPS
index 749a0a1..24efe4a 100644
--- a/third_party/blink/renderer/platform/scheduler/DEPS
+++ b/third_party/blink/renderer/platform/scheduler/DEPS
@@ -44,6 +44,7 @@
   "+base/threading/sequenced_task_runner_handle.h",
   "+base/threading/thread.h",
   "+base/threading/thread_checker.h",
+  "+components/scheduling_metrics",
   "+services/metrics",
 
   "+third_party/blink/renderer/platform/cross_thread_functional.h",
diff --git a/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc b/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc
deleted file mode 100644
index 8e672dc..0000000
--- a/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.cc
+++ /dev/null
@@ -1,54 +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 "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/task/sequence_manager/task_queue.h"
-
-namespace blink {
-namespace scheduler {
-
-scoped_refptr<TaskQueueWithTaskType> TaskQueueWithTaskType::Create(
-    scoped_refptr<base::sequence_manager::TaskQueue> task_queue,
-    TaskType task_type) {
-  return base::WrapRefCounted(
-      new TaskQueueWithTaskType(std::move(task_queue), task_type));
-}
-
-bool TaskQueueWithTaskType::RunsTasksInCurrentSequence() const {
-  return task_queue_->RunsTasksInCurrentSequence();
-}
-
-TaskQueueWithTaskType::TaskQueueWithTaskType(
-    scoped_refptr<base::sequence_manager::TaskQueue> task_queue,
-    TaskType task_type)
-    : task_queue_(std::move(task_queue)), task_type_(task_type) {}
-
-TaskQueueWithTaskType::~TaskQueueWithTaskType() = default;
-
-bool TaskQueueWithTaskType::PostDelayedTask(const base::Location& location,
-                                            base::OnceClosure task,
-                                            base::TimeDelta delay) {
-  return task_queue_->PostTaskWithMetadata(
-      base::sequence_manager::TaskQueue::PostedTask(
-          std::move(task), location, delay, base::Nestable::kNestable,
-          static_cast<int>(task_type_)));
-}
-
-bool TaskQueueWithTaskType::PostNonNestableDelayedTask(
-    const base::Location& location,
-    base::OnceClosure task,
-    base::TimeDelta delay) {
-  return task_queue_->PostTaskWithMetadata(
-      base::sequence_manager::TaskQueue::PostedTask(
-          std::move(task), location, delay, base::Nestable::kNonNestable,
-          static_cast<int>(task_type_)));
-}
-
-}  // namespace scheduler
-}  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h b/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h
deleted file mode 100644
index 4232da9..0000000
--- a/third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h
+++ /dev/null
@@ -1,60 +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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_TASK_QUEUE_WITH_TASK_TYPE_H_
-#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_TASK_QUEUE_WITH_TASK_TYPE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/time/time.h"
-#include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/platform_export.h"
-
-namespace base {
-namespace sequence_manager {
-class TaskQueue;
-}
-}  // namespace base
-
-namespace blink {
-namespace scheduler {
-
-class PLATFORM_EXPORT TaskQueueWithTaskType
-    : public base::SingleThreadTaskRunner {
- public:
-  static scoped_refptr<TaskQueueWithTaskType> Create(
-      scoped_refptr<base::sequence_manager::TaskQueue> task_queue,
-      TaskType task_type);
-
-  // base::SingleThreadTaskRunner implementation:
-  bool RunsTasksInCurrentSequence() const override;
-
- protected:
-  bool PostDelayedTask(const base::Location&,
-                       base::OnceClosure,
-                       base::TimeDelta) override;
-  bool PostNonNestableDelayedTask(const base::Location&,
-                                  base::OnceClosure,
-                                  base::TimeDelta) override;
-
- private:
-  TaskQueueWithTaskType(
-      scoped_refptr<base::sequence_manager::TaskQueue> task_queue,
-      TaskType task_type);
-  ~TaskQueueWithTaskType() override;
-
-  scoped_refptr<base::sequence_manager::TaskQueue> task_queue_;
-  TaskType task_type_;
-
-  DISALLOW_COPY_AND_ASSIGN(TaskQueueWithTaskType);
-};
-
-}  // namespace scheduler
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_CHILD_TASK_RUNNER_IMPL_H_
diff --git a/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
index 7c9a23d..1d01b3e5 100644
--- a/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.cc
@@ -12,7 +12,6 @@
 #include "base/task/sequence_manager/task_queue.h"
 #include "base/time/default_tick_clock.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h"
 
@@ -65,8 +64,8 @@
   non_main_thread_scheduler_ = CreateNonMainThreadScheduler();
   non_main_thread_scheduler_->Init();
   task_queue_ = non_main_thread_scheduler_->DefaultTaskQueue();
-  task_runner_ = TaskQueueWithTaskType::Create(
-      task_queue_, TaskType::kWorkerThreadTaskQueueDefault);
+  task_runner_ =
+      task_queue_->CreateTaskRunner(TaskType::kWorkerThreadTaskQueueDefault);
   base::MessageLoopCurrent::Get()->AddDestructionObserver(this);
   completion->Signal();
 }
diff --git a/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
index 59a9fcd..1114407 100644
--- a/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/child/webthread_impl_for_worker_scheduler.h
@@ -14,9 +14,6 @@
 #include "third_party/blink/public/platform/web_private_ptr.h"
 
 namespace base {
-namespace sequence_manager {
-class TaskQueue;
-}
 class WaitableEvent;
 }
 
@@ -28,6 +25,7 @@
 namespace scheduler {
 
 class NonMainThreadSchedulerImpl;
+class NonMainThreadTaskQueue;
 class WorkerSchedulerProxy;
 
 class PLATFORM_EXPORT WebThreadImplForWorkerScheduler
@@ -80,7 +78,7 @@
   std::unique_ptr<scheduler::WorkerSchedulerProxy> worker_scheduler_proxy_;
   std::unique_ptr<scheduler::NonMainThreadSchedulerImpl>
       non_main_thread_scheduler_;
-  scoped_refptr<base::sequence_manager::TaskQueue> task_queue_;
+  scoped_refptr<NonMainThreadTaskQueue> task_queue_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   base::AtomicFlag was_shutdown_on_thread_;
diff --git a/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc b/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
index 6929547..79b7f6b 100644
--- a/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/idle_helper.cc
@@ -10,7 +10,6 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
 
 namespace blink {
@@ -39,8 +38,8 @@
       &IdleHelper::OnIdleTaskPostedOnMainThread, weak_idle_helper_ptr_));
 
   idle_task_runner_ = base::MakeRefCounted<SingleThreadIdleTaskRunner>(
-      TaskQueueWithTaskType::Create(idle_queue_,
-                                    TaskType::kMainThreadTaskQueueIdle),
+      idle_queue_->CreateTaskRunner(
+          static_cast<int>(TaskType::kMainThreadTaskQueueIdle)),
       this);
 
   // This fence will block any idle tasks from running.
diff --git a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
index 7a802b7..3755be275 100644
--- a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.cc
@@ -17,14 +17,43 @@
 constexpr base::TimeDelta kLongTaskDiscardingThreshold =
     base::TimeDelta::FromSeconds(30);
 
+scheduling_metrics::ThreadType ConvertBlinkThreadType(
+    WebThreadType thread_type) {
+  switch (thread_type) {
+    case WebThreadType::kMainThread:
+      return scheduling_metrics::ThreadType::kRendererMainThread;
+    case WebThreadType::kCompositorThread:
+      return scheduling_metrics::ThreadType::kRendererCompositorThread;
+    case WebThreadType::kDedicatedWorkerThread:
+      return scheduling_metrics::ThreadType::kRendererDedicatedWorkerThread;
+    case WebThreadType::kServiceWorkerThread:
+      return scheduling_metrics::ThreadType::kRendererServiceWorkerThread;
+    case WebThreadType::kAnimationWorkletThread:
+    case WebThreadType::kAudioWorkletThread:
+    case WebThreadType::kDatabaseThread:
+    case WebThreadType::kFileThread:
+    case WebThreadType::kHRTFDatabaseLoaderThread:
+    case WebThreadType::kOfflineAudioRenderThread:
+    case WebThreadType::kReverbConvolutionBackgroundThread:
+    case WebThreadType::kScriptStreamerThread:
+    case WebThreadType::kSharedWorkerThread:
+    case WebThreadType::kUnspecifiedWorkerThread:
+    case WebThreadType::kWebAudioThread:
+    case WebThreadType::kTestThread:
+      return scheduling_metrics::ThreadType::kRendererOtherBlinkThread;
+    case WebThreadType::kCount:
+      NOTREACHED();
+      return scheduling_metrics::ThreadType::kCount;
+  }
+}
+
 }  // namespace
 
 MetricsHelper::MetricsHelper(WebThreadType thread_type,
                              bool has_cpu_timing_for_each_task)
     : thread_type_(thread_type),
-      has_cpu_timing_for_each_task_(has_cpu_timing_for_each_task),
-      last_known_time_(has_cpu_timing_for_each_task_ ? base::ThreadTicks::Now()
-                                                     : base::ThreadTicks()),
+      thread_metrics_(ConvertBlinkThreadType(thread_type),
+                      has_cpu_timing_for_each_task),
       thread_task_duration_reporter_(
           "RendererScheduler.TaskDurationPerThreadType2"),
       thread_task_cpu_duration_reporter_(
@@ -36,11 +65,7 @@
       background_thread_task_duration_reporter_(
           "RendererScheduler.TaskDurationPerThreadType2.Background"),
       background_thread_task_cpu_duration_reporter_(
-          "RendererScheduler.TaskCPUDurationPerThreadType2.Background"),
-      tracked_cpu_duration_reporter_(
-          "Scheduler.Experimental.Renderer.CPUTimePerThread.Tracked"),
-      non_tracked_cpu_duration_reporter_(
-          "Scheduler.Experimental.Renderer.CPUTimePerThread.Untracked") {}
+          "RendererScheduler.TaskCPUDurationPerThreadType2.Background") {}
 
 MetricsHelper::~MetricsHelper() {}
 
@@ -57,7 +82,8 @@
     base::sequence_manager::TaskQueue* queue,
     const base::sequence_manager::TaskQueue::Task& task,
     const base::sequence_manager::TaskQueue::TaskTiming& task_timing) {
-  DCHECK(!has_cpu_timing_for_each_task_ || task_timing.has_thread_time());
+  thread_metrics_.RecordTaskMetrics(queue, task, task_timing);
+
   thread_task_duration_reporter_.RecordTask(thread_type_,
                                             task_timing.wall_duration());
 
@@ -82,15 +108,6 @@
     foreground_thread_task_cpu_duration_reporter_.RecordTask(
         thread_type_, task_timing.thread_duration());
   }
-
-  if (has_cpu_timing_for_each_task_) {
-    non_tracked_cpu_duration_reporter_.RecordTask(
-        thread_type_, task_timing.start_thread_time() - last_known_time_);
-    tracked_cpu_duration_reporter_.RecordTask(thread_type_,
-                                              task_timing.thread_duration());
-
-    last_known_time_ = task_timing.end_thread_time();
-  }
 }
 
 }  // namespace scheduler
diff --git a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h
index 64352325..b38bf13 100644
--- a/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/common/metrics_helper.h
@@ -8,10 +8,11 @@
 #include "base/optional.h"
 #include "base/task/sequence_manager/task_queue.h"
 #include "base/time/time.h"
+#include "components/scheduling_metrics/task_duration_metric_reporter.h"
+#include "components/scheduling_metrics/thread_metrics.h"
+#include "components/scheduling_metrics/total_duration_metric_reporter.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h"
-#include "third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h"
 
 namespace base {
 namespace sequence_manager {
@@ -50,23 +51,22 @@
 
  protected:
   const WebThreadType thread_type_;
-  const bool has_cpu_timing_for_each_task_;
 
  private:
-  base::ThreadTicks last_known_time_;
+  scheduling_metrics::ThreadMetrics thread_metrics_;
 
-  TaskDurationMetricReporter<WebThreadType> thread_task_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType> thread_task_cpu_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType>
+  scheduling_metrics::TaskDurationMetricReporter<WebThreadType>
+      thread_task_duration_reporter_;
+  scheduling_metrics::TaskDurationMetricReporter<WebThreadType>
+      thread_task_cpu_duration_reporter_;
+  scheduling_metrics::TaskDurationMetricReporter<WebThreadType>
       foreground_thread_task_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType>
+  scheduling_metrics::TaskDurationMetricReporter<WebThreadType>
       foreground_thread_task_cpu_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType>
+  scheduling_metrics::TaskDurationMetricReporter<WebThreadType>
       background_thread_task_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType>
+  scheduling_metrics::TaskDurationMetricReporter<WebThreadType>
       background_thread_task_cpu_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType> tracked_cpu_duration_reporter_;
-  TaskDurationMetricReporter<WebThreadType> non_tracked_cpu_duration_reporter_;
 
   DISALLOW_COPY_AND_ASSIGN(MetricsHelper);
 };
diff --git a/third_party/blink/renderer/platform/scheduler/common/metrics_helper_unittest.cc b/third_party/blink/renderer/platform/scheduler/common/metrics_helper_unittest.cc
index 8fec7193..5af9e4e 100644
--- a/third_party/blink/renderer/platform/scheduler/common/metrics_helper_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/metrics_helper_unittest.cc
@@ -85,34 +85,5 @@
               static_cast<int>(WebThreadType::kUnspecifiedWorkerThread), 25)));
 }
 
-TEST(MetricsHelperTest, TrackedCPUTimeMetrics) {
-  base::HistogramTester histogram_tester;
-  base::subtle::ScopedTimeClockOverrides time_override(
-      []() { return base::Time(); }, []() { return Seconds(1); },
-      []() { return ThreadSeconds(1); });
-
-  MetricsHelperForTest main_thread_metrics(
-      WebThreadType::kMainThread, true /* has_cpu_timing_for_each_task */);
-
-  main_thread_metrics.RecordCommonTaskMetrics(
-      nullptr, FakeTask(),
-      FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(5),
-                     ThreadSeconds(15)));
-  main_thread_metrics.RecordCommonTaskMetrics(
-      nullptr, FakeTask(),
-      FakeTaskTiming(Seconds(10), Seconds(50), ThreadSeconds(20),
-                     ThreadSeconds(25)));
-
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "Scheduler.Experimental.Renderer.CPUTimePerThread.Tracked"),
-              testing::UnorderedElementsAre(base::Bucket(
-                  static_cast<int>(WebThreadType::kMainThread), 15)));
-  // 9 = 4 seconds before task 1 and 5 seconds between tasks 1 and 2.
-  EXPECT_THAT(histogram_tester.GetAllSamples(
-                  "Scheduler.Experimental.Renderer.CPUTimePerThread.Untracked"),
-              testing::UnorderedElementsAre(base::Bucket(
-                  static_cast<int>(WebThreadType::kMainThread), 9)));
-}
-
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
index dc58a367..896081b 100644
--- a/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/common/scheduler_helper.cc
@@ -10,7 +10,6 @@
 #include "base/time/default_tick_clock.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 
 namespace blink {
 namespace scheduler {
@@ -33,7 +32,7 @@
   control_task_queue->SetQueuePriority(TaskQueue::kControlPriority);
 
   default_task_runner_ =
-      TaskQueueWithTaskType::Create(default_task_queue, default_task_type);
+      default_task_queue->CreateTaskRunner(static_cast<int>(default_task_type));
 
   DCHECK(sequence_manager_);
   sequence_manager_->SetDefaultTaskRunner(default_task_runner_);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
index a2d2fee..a6687c4 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -12,7 +12,6 @@
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/scheduler/child/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/auto_advancing_virtual_time_domain.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
@@ -104,11 +103,12 @@
 
 std::unique_ptr<FrameSchedulerImpl> FrameSchedulerImpl::Create(
     PageSchedulerImpl* parent_page_scheduler,
+    FrameScheduler::Delegate* delegate,
     base::trace_event::BlameContext* blame_context,
     FrameScheduler::FrameType frame_type) {
-  std::unique_ptr<FrameSchedulerImpl> frame_scheduler(
-      new FrameSchedulerImpl(parent_page_scheduler->GetMainThreadScheduler(),
-                             parent_page_scheduler, blame_context, frame_type));
+  std::unique_ptr<FrameSchedulerImpl> frame_scheduler(new FrameSchedulerImpl(
+      parent_page_scheduler->GetMainThreadScheduler(), parent_page_scheduler,
+      delegate, blame_context, frame_type));
   parent_page_scheduler->RegisterFrameSchedulerImpl(frame_scheduler.get());
   return frame_scheduler;
 }
@@ -116,12 +116,14 @@
 FrameSchedulerImpl::FrameSchedulerImpl(
     MainThreadSchedulerImpl* main_thread_scheduler,
     PageSchedulerImpl* parent_page_scheduler,
+    FrameScheduler::Delegate* delegate,
     base::trace_event::BlameContext* blame_context,
     FrameScheduler::FrameType frame_type)
     : frame_type_(frame_type),
       is_ad_frame_(false),
       main_thread_scheduler_(main_thread_scheduler),
       parent_page_scheduler_(parent_page_scheduler),
+      delegate_(delegate),
       blame_context_(blame_context),
       throttling_state_(SchedulingLifecycleState::kNotThrottled),
       frame_visible_(true,
@@ -182,7 +184,11 @@
       weak_factory_(this) {}
 
 FrameSchedulerImpl::FrameSchedulerImpl()
-    : FrameSchedulerImpl(nullptr, nullptr, nullptr, FrameType::kSubframe) {}
+    : FrameSchedulerImpl(nullptr,
+                         nullptr,
+                         nullptr,
+                         nullptr,
+                         FrameType::kSubframe) {}
 
 namespace {
 
@@ -299,13 +305,13 @@
   // TODO(haraken): Optimize the mapping from TaskTypes to task runners.
   switch (type) {
     case TaskType::kJavascriptTimer:
-      return TaskQueueWithTaskType::Create(ThrottleableTaskQueue(), type);
+      return ThrottleableTaskQueue()->CreateTaskRunner(type);
     case TaskType::kInternalLoading:
     case TaskType::kNetworking:
     case TaskType::kNetworkingWithURLLoaderAnnotation:
-      return TaskQueueWithTaskType::Create(LoadingTaskQueue(), type);
+      return LoadingTaskQueue()->CreateTaskRunner(type);
     case TaskType::kNetworkingControl:
-      return TaskQueueWithTaskType::Create(LoadingControlTaskQueue(), type);
+      return LoadingControlTaskQueue()->CreateTaskRunner(type);
     // Throttling following tasks may break existing web pages, so tentatively
     // these are unthrottled.
     // TODO(nhiroki): Throttle them again after we're convinced that it's safe
@@ -329,7 +335,7 @@
     case TaskType::kInternalDefault:
     case TaskType::kMiscPlatformAPI:
       // TODO(altimin): Move appropriate tasks to throttleable task queue.
-      return TaskQueueWithTaskType::Create(DeferrableTaskQueue(), type);
+      return DeferrableTaskQueue()->CreateTaskRunner(type);
     // PostedMessage can be used for navigation, so we shouldn't defer it
     // when expecting a user gesture.
     case TaskType::kPostedMessage:
@@ -346,7 +352,7 @@
     case TaskType::kInternalMediaRealTime:
     case TaskType::kInternalUserInteraction:
     case TaskType::kInternalIntersectionObserver:
-      return TaskQueueWithTaskType::Create(PausableTaskQueue(), type);
+      return PausableTaskQueue()->CreateTaskRunner(type);
     case TaskType::kInternalIPC:
     // The TaskType of Inspector tasks needs to be unpausable because they need
     // to run even on a paused page.
@@ -355,7 +361,7 @@
     // unthrottled and undeferred) not to prevent service workers that may
     // control browser navigation on multiple tabs.
     case TaskType::kInternalWorker:
-      return TaskQueueWithTaskType::Create(UnpausableTaskQueue(), type);
+      return UnpausableTaskQueue()->CreateTaskRunner(type);
     case TaskType::kDeprecatedNone:
     case TaskType::kMainThreadTaskQueueV8:
     case TaskType::kMainThreadTaskQueueCompositor:
@@ -391,7 +397,7 @@
   return std::make_pair(loading_task_queue, std::move(voter));
 }
 
-scoped_refptr<TaskQueue> FrameSchedulerImpl::LoadingTaskQueue() {
+scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::LoadingTaskQueue() {
   DCHECK(parent_page_scheduler_);
   if (!loading_task_queue_) {
     auto queue_voter_pair = CreateNewLoadingTaskQueue();
@@ -455,7 +461,8 @@
   }
 }
 
-scoped_refptr<TaskQueue> FrameSchedulerImpl::LoadingControlTaskQueue() {
+scoped_refptr<MainThreadTaskQueue>
+FrameSchedulerImpl::LoadingControlTaskQueue() {
   DCHECK(parent_page_scheduler_);
   if (!loading_control_task_queue_) {
     loading_control_task_queue_ = main_thread_scheduler_->NewLoadingTaskQueue(
@@ -468,7 +475,7 @@
   return loading_control_task_queue_;
 }
 
-scoped_refptr<TaskQueue> FrameSchedulerImpl::ThrottleableTaskQueue() {
+scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::ThrottleableTaskQueue() {
   DCHECK(parent_page_scheduler_);
   if (!throttleable_task_queue_) {
     // TODO(panicker): Avoid adding this queue in RS task_runners_.
@@ -498,7 +505,7 @@
   return throttleable_task_queue_;
 }
 
-scoped_refptr<TaskQueue> FrameSchedulerImpl::DeferrableTaskQueue() {
+scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::DeferrableTaskQueue() {
   DCHECK(parent_page_scheduler_);
   if (!deferrable_task_queue_) {
     deferrable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
@@ -517,7 +524,7 @@
   return deferrable_task_queue_;
 }
 
-scoped_refptr<TaskQueue> FrameSchedulerImpl::PausableTaskQueue() {
+scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::PausableTaskQueue() {
   DCHECK(parent_page_scheduler_);
   if (!pausable_task_queue_) {
     pausable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
@@ -535,7 +542,7 @@
   return pausable_task_queue_;
 }
 
-scoped_refptr<TaskQueue> FrameSchedulerImpl::UnpausableTaskQueue() {
+scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::UnpausableTaskQueue() {
   DCHECK(parent_page_scheduler_);
   if (!unpausable_task_queue_) {
     unpausable_task_queue_ = main_thread_scheduler_->NewTaskQueue(
@@ -900,5 +907,17 @@
   }
 }
 
+ukm::UkmRecorder* FrameSchedulerImpl::GetUkmRecorder() {
+  if (!delegate_)
+    return nullptr;
+  return delegate_->GetUkmRecorder();
+}
+
+ukm::SourceId FrameSchedulerImpl::GetUkmSourceId() {
+  if (!delegate_)
+    return ukm::kInvalidSourceId;
+  return delegate_->GetUkmSourceId();
+}
+
 }  // namespace scheduler
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
index 1f5cb1c..bed1670 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h
@@ -15,6 +15,7 @@
 #include "base/task/sequence_manager/task_queue.h"
 #include "base/trace_event/trace_event.h"
 #include "net/base/request_priority.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_origin_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
@@ -33,6 +34,10 @@
 }  // namespace trace_event
 }  // namespace base
 
+namespace ukm {
+class UkmRecorder;
+}
+
 namespace blink {
 namespace scheduler {
 
@@ -57,6 +62,7 @@
  public:
   static std::unique_ptr<FrameSchedulerImpl> Create(
       PageSchedulerImpl* page_scheduler,
+      FrameScheduler::Delegate* delegate,
       base::trace_event::BlameContext* blame_context,
       FrameScheduler::FrameType frame_type);
   ~FrameSchedulerImpl() override;
@@ -120,9 +126,13 @@
   base::sequence_manager::TaskQueue::QueuePriority ComputePriority(
       MainThreadTaskQueue* task_queue) const;
 
+  ukm::UkmRecorder* GetUkmRecorder();
+  ukm::SourceId GetUkmSourceId();
+
  protected:
   FrameSchedulerImpl(MainThreadSchedulerImpl* main_thread_scheduler,
                      PageSchedulerImpl* parent_page_scheduler,
+                     FrameScheduler::Delegate* delegate,
                      base::trace_event::BlameContext* blame_context,
                      FrameScheduler::FrameType frame_type);
 
@@ -210,12 +220,12 @@
       std::unique_ptr<base::sequence_manager::TaskQueue::QueueEnabledVoter>>
   CreateNewLoadingTaskQueue();
 
-  scoped_refptr<base::sequence_manager::TaskQueue> LoadingTaskQueue();
-  scoped_refptr<base::sequence_manager::TaskQueue> LoadingControlTaskQueue();
-  scoped_refptr<base::sequence_manager::TaskQueue> ThrottleableTaskQueue();
-  scoped_refptr<base::sequence_manager::TaskQueue> DeferrableTaskQueue();
-  scoped_refptr<base::sequence_manager::TaskQueue> PausableTaskQueue();
-  scoped_refptr<base::sequence_manager::TaskQueue> UnpausableTaskQueue();
+  scoped_refptr<MainThreadTaskQueue> LoadingTaskQueue();
+  scoped_refptr<MainThreadTaskQueue> LoadingControlTaskQueue();
+  scoped_refptr<MainThreadTaskQueue> ThrottleableTaskQueue();
+  scoped_refptr<MainThreadTaskQueue> DeferrableTaskQueue();
+  scoped_refptr<MainThreadTaskQueue> PausableTaskQueue();
+  scoped_refptr<MainThreadTaskQueue> UnpausableTaskQueue();
 
   const FrameScheduler::FrameType frame_type_;
 
@@ -248,6 +258,7 @@
 
   MainThreadSchedulerImpl* main_thread_scheduler_;  // NOT OWNED
   PageSchedulerImpl* parent_page_scheduler_;        // NOT OWNED
+  FrameScheduler::Delegate* delegate_;              // NOT OWNED
   base::trace_event::BlameContext* blame_context_;  // NOT OWNED
   SchedulingLifecycleState throttling_state_;
   TraceableState<bool, kTracingCategoryNameInfo> frame_visible_;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
index 86834b2..06991f23 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -56,8 +56,9 @@
             task_environment_.GetMockTickClock()),
         base::nullopt));
     page_scheduler_.reset(new PageSchedulerImpl(nullptr, scheduler_.get()));
-    frame_scheduler_ = FrameSchedulerImpl::Create(
-        page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kSubframe);
+    frame_scheduler_ =
+        FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                   FrameScheduler::FrameType::kSubframe);
   }
 
   void TearDown() override {
@@ -864,8 +865,9 @@
   EXPECT_EQ(UnpausableTaskQueue()->GetQueuePriority(),
             TaskQueue::QueuePriority::kLowPriority);
 
-  frame_scheduler_ = FrameSchedulerImpl::Create(
-      page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kMainFrame);
+  frame_scheduler_ =
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                 FrameScheduler::FrameType::kMainFrame);
 
   // Main Frame Task Queues.
   EXPECT_EQ(LoadingTaskQueue()->GetQueuePriority(),
@@ -953,8 +955,9 @@
   EXPECT_EQ(UnpausableTaskQueue()->GetQueuePriority(),
             TaskQueue::QueuePriority::kNormalPriority);
 
-  frame_scheduler_ = FrameSchedulerImpl::Create(
-      page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kMainFrame);
+  frame_scheduler_ =
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                 FrameScheduler::FrameType::kMainFrame);
 
   // Main Frame Task Queues.
   EXPECT_EQ(LoadingTaskQueue()->GetQueuePriority(),
@@ -1042,8 +1045,9 @@
   EXPECT_EQ(UnpausableTaskQueue()->GetQueuePriority(),
             TaskQueue::QueuePriority::kNormalPriority);
 
-  frame_scheduler_ = FrameSchedulerImpl::Create(
-      page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kMainFrame);
+  frame_scheduler_ =
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                 FrameScheduler::FrameType::kMainFrame);
 
   // Main Frame Task Queues.
   EXPECT_EQ(LoadingTaskQueue()->GetQueuePriority(),
@@ -1108,8 +1112,9 @@
 
 TEST_F(LowPriorityThrottleableTaskDuringLoadingExperimentTest,
        MainFrameQueuesPriorities) {
-  frame_scheduler_ = FrameSchedulerImpl::Create(
-      page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kMainFrame);
+  frame_scheduler_ =
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                 FrameScheduler::FrameType::kMainFrame);
 
   // Main thread is in the loading use case.
   scheduler_->DidStartProvisionalLoad(true);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
index 2f862a9..8bf141e 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
@@ -48,8 +48,9 @@
             task_environment_.GetMockTickClock()),
         base::nullopt));
     page_scheduler_.reset(new PageSchedulerImpl(nullptr, scheduler_.get()));
-    frame_scheduler_ = FrameSchedulerImpl::Create(
-        page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kSubframe);
+    frame_scheduler_ =
+        FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                   FrameScheduler::FrameType::kSubframe);
     frame_task_queue_controller_.reset(new FrameTaskQueueController(
         scheduler_.get(), frame_scheduler_.get(), this));
   }
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h
index 88d0e58..d1d9582 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_metrics_helper.h
@@ -8,15 +8,15 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/time/time.h"
+#include "components/scheduling_metrics/task_duration_metric_reporter.h"
+#include "components/scheduling_metrics/total_duration_metric_reporter.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/common/metrics_helper.h"
-#include "third_party/blink/renderer/platform/scheduler/common/total_duration_metric_reporter.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/use_case.h"
 #include "third_party/blink/renderer/platform/scheduler/renderer/frame_status.h"
-#include "third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h"
 #include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
 
 namespace blink {
@@ -52,6 +52,10 @@
   void ResetForTest(base::TimeTicks now);
 
  private:
+  using TaskDurationPerQueueTypeMetricReporter =
+      scheduling_metrics::TaskDurationMetricReporter<
+          MainThreadTaskQueue::QueueType>;
+
   void ReportLowThreadLoadForPageAlmostIdleSignal(int load_percentage);
 
   MainThreadSchedulerImpl* main_thread_scheduler_;  // NOT OWNED
@@ -69,9 +73,6 @@
   ThreadLoadTracker background_main_thread_load_tracker_;
   ThreadLoadTracker foreground_main_thread_load_tracker_;
 
-  using TaskDurationPerQueueTypeMetricReporter =
-      TaskDurationMetricReporter<MainThreadTaskQueue::QueueType>;
-
   struct PerQueueTypeDurationReporters {
     PerQueueTypeDurationReporters();
 
@@ -100,10 +101,11 @@
 
   PerQueueTypeDurationReporters per_queue_type_reporters_;
 
-  TaskDurationMetricReporter<FrameStatus> per_frame_status_duration_reporter_;
+  scheduling_metrics::TaskDurationMetricReporter<FrameStatus>
+      per_frame_status_duration_reporter_;
 
   using TaskDurationPerTaskTypeMetricReporter =
-      TaskDurationMetricReporter<TaskType>;
+      scheduling_metrics::TaskDurationMetricReporter<TaskType>;
 
   TaskDurationPerTaskTypeMetricReporter per_task_type_duration_reporter_;
 
@@ -127,9 +129,10 @@
   TaskDurationPerTaskTypeMetricReporter
       background_after_tenth_minute_per_task_type_duration_reporter_;
 
-  TaskDurationMetricReporter<UseCase> per_task_use_case_duration_reporter_;
+  scheduling_metrics::TaskDurationMetricReporter<UseCase>
+      per_task_use_case_duration_reporter_;
 
-  TotalDurationMetricReporter total_task_time_reporter_;
+  scheduling_metrics::TotalDurationMetricReporter total_task_time_reporter_;
 
   MainThreadTaskLoadState main_thread_task_load_state_;
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc
index bd4d984..6222ae6 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_helper.h"
 
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 4644a9d..aa8829b 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -321,8 +321,8 @@
       delayed_update_policy_runner_(
           base::BindRepeating(&MainThreadSchedulerImpl::UpdatePolicy,
                               base::Unretained(this)),
-          TaskQueueWithTaskType::Create(helper_.ControlMainThreadTaskQueue(),
-                                        TaskType::kMainThreadTaskQueueControl)),
+          helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
+              TaskType::kMainThreadTaskQueueControl)),
       queueing_time_estimator_(this, kQueueingTimeWindowDuration, 20),
       main_thread_only_(this,
                         compositor_task_queue_,
@@ -346,17 +346,16 @@
   ipc_task_queue_ = NewTaskQueue(MainThreadTaskQueue::QueueCreationParams(
       MainThreadTaskQueue::QueueType::kIPC));
 
-  v8_task_runner_ = TaskQueueWithTaskType::Create(
-      v8_task_queue_, TaskType::kMainThreadTaskQueueV8);
-  compositor_task_runner_ = TaskQueueWithTaskType::Create(
-      compositor_task_queue_, TaskType::kMainThreadTaskQueueCompositor);
-  control_task_runner_ =
-      TaskQueueWithTaskType::Create(helper_.ControlMainThreadTaskQueue(),
-                                    TaskType::kMainThreadTaskQueueControl);
-  input_task_runner_ = TaskQueueWithTaskType::Create(
-      input_task_queue_, TaskType::kMainThreadTaskQueueInput);
-  ipc_task_runner_ = TaskQueueWithTaskType::Create(
-      ipc_task_queue_, TaskType::kMainThreadTaskQueueIPC);
+  v8_task_runner_ =
+      v8_task_queue_->CreateTaskRunner(TaskType::kMainThreadTaskQueueV8);
+  compositor_task_runner_ = compositor_task_queue_->CreateTaskRunner(
+      TaskType::kMainThreadTaskQueueCompositor);
+  control_task_runner_ = helper_.ControlMainThreadTaskQueue()->CreateTaskRunner(
+      TaskType::kMainThreadTaskQueueControl);
+  input_task_runner_ =
+      input_task_queue_->CreateTaskRunner(TaskType::kMainThreadTaskQueueInput);
+  ipc_task_runner_ =
+      ipc_task_queue_->CreateTaskRunner(TaskType::kMainThreadTaskQueueIPC);
 
   // TaskQueueThrottler requires some task runners, then initialize
   // TaskQueueThrottler after task queues/runners are initialized.
@@ -2612,16 +2611,14 @@
     return;
 
   if (queue && queue->GetFrameScheduler()) {
-    RecordTaskUkmImpl(queue, task, task_timing,
-                      static_cast<PageSchedulerImpl*>(
-                          queue->GetFrameScheduler()->GetPageScheduler()),
-                      1);
+    RecordTaskUkmImpl(queue, task, task_timing, queue->GetFrameScheduler(),
+                      true);
     return;
   }
 
   for (PageSchedulerImpl* page_scheduler : main_thread_only().page_schedulers) {
-    RecordTaskUkmImpl(queue, task, task_timing, page_scheduler,
-                      main_thread_only().page_schedulers.size());
+    RecordTaskUkmImpl(queue, task, task_timing,
+                      page_scheduler->SelectFrameForUkmAttribution(), false);
   }
 }
 
@@ -2629,21 +2626,22 @@
     MainThreadTaskQueue* queue,
     const TaskQueue::Task& task,
     const TaskQueue::TaskTiming& task_timing,
-    PageSchedulerImpl* page_scheduler,
-    size_t page_schedulers_to_attribute) {
-  // Skip tasks which have deleted the page scheduler.
-  if (!page_scheduler)
+    FrameSchedulerImpl* frame_scheduler,
+    bool precise_attribution) {
+  // Skip tasks which have deleted the frame or the page scheduler.
+  if (!frame_scheduler || !frame_scheduler->GetPageScheduler())
     return;
 
-  ukm::UkmRecorder* ukm_recorder = page_scheduler->GetUkmRecorder();
+  ukm::UkmRecorder* ukm_recorder = frame_scheduler->GetUkmRecorder();
   // OOPIFs are not supported.
   if (!ukm_recorder)
     return;
 
   ukm::builders::RendererSchedulerTask builder(
-      page_scheduler->GetUkmSourceId());
+      frame_scheduler->GetUkmSourceId());
 
-  builder.SetPageSchedulers(page_schedulers_to_attribute);
+  builder.SetPageSchedulers(main_thread_only().page_schedulers.size());
+
   builder.SetRendererBackgrounded(main_thread_only().renderer_backgrounded);
   builder.SetRendererHidden(main_thread_only().renderer_hidden);
   builder.SetRendererAudible(main_thread_only().is_audio_playing);
@@ -2655,6 +2653,7 @@
   builder.SetFrameStatus(static_cast<int>(
       GetFrameStatus(queue ? queue->GetFrameScheduler() : nullptr)));
   builder.SetTaskDuration(task_timing.wall_duration().InMicroseconds());
+  builder.SetIsOOPIF(!frame_scheduler->GetPageScheduler()->IsMainFrameLocal());
 
   if (main_thread_only().renderer_backgrounded) {
     base::TimeDelta time_since_backgrounded =
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 7ed8f8b..47d9434 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -26,7 +26,6 @@
 #include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/scheduler/child/pollable_thread_safe_flag.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/common/thread_scheduler_impl.h"
@@ -721,8 +720,8 @@
       MainThreadTaskQueue* queue,
       const base::sequence_manager::TaskQueue::Task& task,
       const base::sequence_manager::TaskQueue::TaskTiming& task_timing,
-      PageSchedulerImpl* page_scheduler,
-      size_t page_schedulers_to_attribute);
+      FrameSchedulerImpl* frame_scheduler,
+      bool precise_attribution);
 
   void InitWakeUpBudgetPoolIfNeeded();
 
@@ -770,11 +769,11 @@
   scoped_refptr<MainThreadTaskQueue> v8_task_queue_;
   scoped_refptr<MainThreadTaskQueue> ipc_task_queue_;
 
-  scoped_refptr<TaskQueueWithTaskType> v8_task_runner_;
-  scoped_refptr<TaskQueueWithTaskType> compositor_task_runner_;
-  scoped_refptr<TaskQueueWithTaskType> control_task_runner_;
-  scoped_refptr<TaskQueueWithTaskType> input_task_runner_;
-  scoped_refptr<TaskQueueWithTaskType> ipc_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> v8_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> control_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> input_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner_;
 
   // Note |virtual_time_domain_| is lazily created.
   std::unique_ptr<AutoAdvancingVirtualTimeDomain> virtual_time_domain_;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
index b5ab62a..ccbe3bc 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl_unittest.cc
@@ -350,8 +350,9 @@
 
     page_scheduler_ =
         std::make_unique<PageSchedulerImpl>(nullptr, scheduler_.get());
-    main_frame_scheduler_ = FrameSchedulerImpl::Create(
-        page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kMainFrame);
+    main_frame_scheduler_ =
+        FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                   FrameScheduler::FrameType::kMainFrame);
 
     loading_task_runner_ = main_frame_scheduler_->LoadingTaskQueue();
     loading_control_task_runner_ =
@@ -3558,7 +3559,7 @@
   scheduler_->AddPageScheduler(page_scheduler.get());
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   TaskQueue* timer_tq = ThrottleableTaskQueue(frame_scheduler.get()).get();
@@ -3647,7 +3648,7 @@
   scheduler_->AddPageScheduler(page_scheduler1.get());
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler1.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler1.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   std::unique_ptr<PageSchedulerImpl> page_scheduler2 =
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
index f3e0800..efda9508 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -255,6 +255,11 @@
   FrameSchedulerImpl* GetFrameScheduler() const;
   void DetachFromFrameScheduler();
 
+  scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner(
+      TaskType task_type) {
+    return TaskQueue::CreateTaskRunner(static_cast<int>(task_type));
+  }
+
  protected:
   void SetFrameSchedulerForTest(FrameSchedulerImpl* frame_scheduler);
 
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
index ffd8d540..2a1cd8a 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.cc
@@ -273,9 +273,10 @@
 }
 
 std::unique_ptr<blink::FrameScheduler> PageSchedulerImpl::CreateFrameScheduler(
+    FrameScheduler::Delegate* delegate,
     blink::BlameContext* blame_context,
     FrameScheduler::FrameType frame_type) {
-  return FrameSchedulerImpl::Create(this, blame_context, frame_type);
+  return FrameSchedulerImpl::Create(this, delegate, blame_context, frame_type);
 }
 
 void PageSchedulerImpl::Unregister(FrameSchedulerImpl* frame_scheduler) {
@@ -562,18 +563,6 @@
   return main_thread_scheduler_;
 }
 
-ukm::UkmRecorder* PageSchedulerImpl::GetUkmRecorder() {
-  if (!delegate_)
-    return nullptr;
-  return delegate_->GetUkmRecorder();
-}
-
-int64_t PageSchedulerImpl::GetUkmSourceId() {
-  if (!delegate_)
-    return 0;
-  return delegate_->GetUkmSourceId();
-}
-
 bool PageSchedulerImpl::IsBackgrounded() const {
   return page_visibility_ == PageVisibilityState::kHidden && !IsAudioPlaying();
 }
@@ -673,6 +662,14 @@
   }
 }
 
+FrameSchedulerImpl* PageSchedulerImpl::SelectFrameForUkmAttribution() {
+  for (FrameSchedulerImpl* frame_scheduler : frame_schedulers_) {
+    if (frame_scheduler->GetUkmRecorder())
+      return frame_scheduler;
+  }
+  return nullptr;
+}
+
 // static
 const char PageSchedulerImpl::kHistogramPageLifecycleStateTransition[] =
     "PageScheduler.PageLifecycleStateTransition";
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
index 1d4d6db..175131de 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl.h
@@ -57,6 +57,7 @@
   void SetIsMainFrameLocal(bool is_local) override;
 
   std::unique_ptr<FrameScheduler> CreateFrameScheduler(
+      FrameScheduler::Delegate* delegate,
       BlameContext*,
       FrameScheduler::FrameType) override;
   base::TimeTicks EnableVirtualTime() override;
@@ -107,10 +108,15 @@
   // Return a number of child web frame schedulers for this PageScheduler.
   size_t FrameCount() const;
 
-  void AsValueInto(base::trace_event::TracedValue* state) const;
+  // Generally UKMs are asssociated with the main frame of a page, but the
+  // implementation allows to request a recorder from any local frame with
+  // the same result (e.g. for OOPIF support), therefore we need to select
+  // any frame here.
+  // Note that selecting main frame doesn't work for OOPIFs where the main
+  // frame it not a local one.
+  FrameSchedulerImpl* SelectFrameForUkmAttribution();
 
-  ukm::UkmRecorder* GetUkmRecorder();
-  int64_t GetUkmSourceId();
+  void AsValueInto(base::trace_event::TracedValue* state) const;
 
   base::WeakPtr<PageSchedulerImpl> GetWeakPtr() {
     return weak_factory_.GetWeakPtr();
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
index e17810b3..23032f4 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/page_scheduler_impl_unittest.cc
@@ -20,7 +20,6 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/page_visibility_state.h"
@@ -63,8 +62,9 @@
             nullptr, test_task_runner_, test_task_runner_->GetMockTickClock()),
         base::nullopt));
     page_scheduler_.reset(new PageSchedulerImpl(nullptr, scheduler_.get()));
-    frame_scheduler_ = FrameSchedulerImpl::Create(
-        page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kSubframe);
+    frame_scheduler_ =
+        FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                   FrameScheduler::FrameType::kSubframe);
   }
 
   void TearDown() override {
@@ -94,32 +94,30 @@
   }
 
   scoped_refptr<base::SingleThreadTaskRunner> ThrottleableTaskRunner() {
-    return TaskQueueWithTaskType::Create(ThrottleableTaskQueue(),
-                                         TaskType::kInternalTest);
+    return ThrottleableTaskQueue()->CreateTaskRunner(TaskType::kInternalTest);
   }
 
   scoped_refptr<base::SingleThreadTaskRunner> LoadingTaskRunner() {
-    return TaskQueueWithTaskType::Create(LoadingTaskQueue(),
-                                         TaskType::kInternalTest);
+    return LoadingTaskQueue()->CreateTaskRunner(TaskType::kInternalTest);
   }
 
-  scoped_refptr<TaskQueue> ThrottleableTaskQueue() {
+  scoped_refptr<MainThreadTaskQueue> ThrottleableTaskQueue() {
     return frame_scheduler_->ThrottleableTaskQueue();
   }
 
-  scoped_refptr<TaskQueue> LoadingTaskQueue() {
+  scoped_refptr<MainThreadTaskQueue> LoadingTaskQueue() {
     return frame_scheduler_->LoadingTaskQueue();
   }
 
-  scoped_refptr<TaskQueue> DeferrableTaskQueue() {
+  scoped_refptr<MainThreadTaskQueue> DeferrableTaskQueue() {
     return frame_scheduler_->DeferrableTaskQueue();
   }
 
-  scoped_refptr<TaskQueue> PausableTaskQueue() {
+  scoped_refptr<MainThreadTaskQueue> PausableTaskQueue() {
     return frame_scheduler_->PausableTaskQueue();
   }
 
-  scoped_refptr<TaskQueue> UnpausableTaskQueue() {
+  scoped_refptr<MainThreadTaskQueue> UnpausableTaskQueue() {
     return frame_scheduler_->UnpausableTaskQueue();
   }
 
@@ -200,19 +198,19 @@
 TEST_F(PageSchedulerImplTest, TestDestructionOfFrameSchedulersBefore) {
   std::unique_ptr<blink::FrameScheduler> frame1(
       page_scheduler_->CreateFrameScheduler(
-          nullptr, FrameScheduler::FrameType::kSubframe));
+          nullptr, nullptr, FrameScheduler::FrameType::kSubframe));
   std::unique_ptr<blink::FrameScheduler> frame2(
       page_scheduler_->CreateFrameScheduler(
-          nullptr, FrameScheduler::FrameType::kSubframe));
+          nullptr, nullptr, FrameScheduler::FrameType::kSubframe));
 }
 
 TEST_F(PageSchedulerImplTest, TestDestructionOfFrameSchedulersAfter) {
   std::unique_ptr<blink::FrameScheduler> frame1(
       page_scheduler_->CreateFrameScheduler(
-          nullptr, FrameScheduler::FrameType::kSubframe));
+          nullptr, nullptr, FrameScheduler::FrameType::kSubframe));
   std::unique_ptr<blink::FrameScheduler> frame2(
       page_scheduler_->CreateFrameScheduler(
-          nullptr, FrameScheduler::FrameType::kSubframe));
+          nullptr, nullptr, FrameScheduler::FrameType::kSubframe));
   page_scheduler_.reset();
 }
 
@@ -298,7 +296,7 @@
   std::unique_ptr<PageSchedulerImpl> page_scheduler2(
       new PageSchedulerImpl(nullptr, scheduler_.get()));
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler2 =
-      FrameSchedulerImpl::Create(page_scheduler2.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler2.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   page_scheduler_->SetPageVisible(true);
@@ -550,7 +548,7 @@
   page_scheduler_->EnableVirtualTime();
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   ThrottleableTaskQueueForScheduler(frame_scheduler.get())
@@ -580,7 +578,7 @@
 TEST_F(PageSchedulerImplTest, DeleteFrameSchedulers_InTask) {
   for (int i = 0; i < 10; i++) {
     FrameSchedulerImpl* frame_scheduler =
-        FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+        FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                    FrameScheduler::FrameType::kSubframe)
             .release();
     ThrottleableTaskQueueForScheduler(frame_scheduler)
@@ -600,7 +598,7 @@
   page_scheduler_->SetPageVisible(false);
 
   FrameSchedulerImpl* frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe)
           .release();
   scoped_refptr<TaskQueue> timer_task_queue =
@@ -653,7 +651,7 @@
       VirtualTimePolicy::kDeterministicLoading);
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   {
@@ -720,7 +718,7 @@
   base::TimeTicks time_second_task;
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   // Pauses and unpauses virtual time, thereby advancing virtual time by an
@@ -756,7 +754,7 @@
       VirtualTimePolicy::kDeterministicLoading);
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   WebScopedVirtualTimePauser virtual_time_pauser1 =
@@ -801,7 +799,7 @@
   std::vector<int> run_order;
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler =
-      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
   page_scheduler_->SetVirtualTimePolicy(VirtualTimePolicy::kPause);
   page_scheduler_->EnableVirtualTime();
@@ -1087,8 +1085,9 @@
   EXPECT_FALSE(page_scheduler_->IsThrottled());
 
   std::vector<base::TimeTicks> run_times;
-  frame_scheduler_ = FrameSchedulerImpl::Create(
-      page_scheduler_.get(), nullptr, FrameScheduler::FrameType::kSubframe);
+  frame_scheduler_ =
+      FrameSchedulerImpl::Create(page_scheduler_.get(), nullptr, nullptr,
+                                 FrameScheduler::FrameType::kSubframe);
   page_scheduler_->SetPageVisible(true);
   EXPECT_FALSE(page_scheduler_->IsThrottled());
 
@@ -1153,10 +1152,10 @@
   std::vector<base::TimeTicks> run_times;
 
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler1 =
-      FrameSchedulerImpl::Create(page_scheduler.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
   std::unique_ptr<FrameSchedulerImpl> frame_scheduler2 =
-      FrameSchedulerImpl::Create(page_scheduler.get(), nullptr,
+      FrameSchedulerImpl::Create(page_scheduler.get(), nullptr, nullptr,
                                  FrameScheduler::FrameType::kSubframe);
 
   page_scheduler->SetPageVisible(false);
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc
index 685fd6a..967f2d7 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/resource_loading_task_runner_handle_impl.cc
@@ -5,7 +5,6 @@
 #include "base/memory/ptr_util.h"
 #include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.h"
 
 namespace blink {
@@ -24,8 +23,7 @@
 ResourceLoadingTaskRunnerHandleImpl::ResourceLoadingTaskRunnerHandleImpl(
     scoped_refptr<MainThreadTaskQueue> task_queue)
     : task_queue_(std::move(task_queue)),
-      task_runner_(TaskQueueWithTaskType::Create(
-          task_queue_,
+      task_runner_(task_queue_->CreateTaskRunner(
           TaskType::kNetworkingWithURLLoaderAnnotation)){};
 
 ResourceLoadingTaskRunnerHandleImpl::~ResourceLoadingTaskRunnerHandleImpl() {
diff --git a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
index d82659b7..15dd03b7 100644
--- a/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h
@@ -9,6 +9,7 @@
 
 #include "base/memory/scoped_refptr.h"
 #include "base/single_thread_task_runner.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
 #include "third_party/blink/public/mojom/loader/pause_subresource_loading_handle.mojom-blink.h"
 #include "third_party/blink/public/platform/scheduler/web_resource_loading_task_runner_handle.h"
 #include "third_party/blink/public/platform/task_type.h"
@@ -17,12 +18,24 @@
 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
+namespace ukm {
+class UkmRecorder;
+}
+
 namespace blink {
 
 class PageScheduler;
 
 class FrameScheduler : public FrameOrWorkerScheduler {
  public:
+  class PLATFORM_EXPORT Delegate {
+   public:
+    virtual ~Delegate() = default;
+
+    virtual ukm::UkmRecorder* GetUkmRecorder() = 0;
+    virtual int64_t GetUkmSourceId() = 0;
+  };
+
   ~FrameScheduler() override = default;
 
   // Represents the type of frame: main (top-level) vs not.
diff --git a/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h
index 603595002..e32f97c 100644
--- a/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/page_scheduler.h
@@ -13,10 +13,6 @@
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-namespace ukm {
-class UkmRecorder;
-}
-
 namespace blink {
 
 class PLATFORM_EXPORT PageScheduler {
@@ -30,8 +26,6 @@
     // compositor.
     virtual bool RequestBeginMainFrameNotExpected(bool new_state) = 0;
     virtual void SetLifecycleState(PageLifecycleState) = 0;
-    virtual ukm::UkmRecorder* GetUkmRecorder() = 0;
-    virtual int64_t GetUkmSourceId() = 0;
   };
 
   virtual ~PageScheduler() = default;
@@ -52,6 +46,7 @@
   // it. All tasks executed by the frame scheduler will be attributed to
   // |blame_context|.
   virtual std::unique_ptr<FrameScheduler> CreateFrameScheduler(
+      FrameScheduler::Delegate* delegate,
       BlameContext*,
       FrameScheduler::FrameType) = 0;
 
diff --git a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
index 63873ee..528963ce 100644
--- a/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h
@@ -7,15 +7,14 @@
 
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
-#include "base/task/sequence_manager/task_queue.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
 
 namespace blink {
-
 namespace scheduler {
 
+class NonMainThreadTaskQueue;
 class WorkerSchedulerProxy;
 class WorkerThreadScheduler;
 
@@ -49,16 +48,16 @@
   SchedulingLifecycleState CalculateLifecycleState(ObserverType) const override;
 
  protected:
-  scoped_refptr<base::sequence_manager::TaskQueue> ThrottleableTaskQueue();
-  scoped_refptr<base::sequence_manager::TaskQueue> UnthrottleableTaskQueue();
+  scoped_refptr<NonMainThreadTaskQueue> ThrottleableTaskQueue();
+  scoped_refptr<NonMainThreadTaskQueue> UnthrottleableTaskQueue();
 
  private:
   void SetUpThrottling();
 
   base::WeakPtr<WorkerScheduler> GetWeakPtr();
 
-  scoped_refptr<base::sequence_manager::TaskQueue> throttleable_task_queue_;
-  scoped_refptr<base::sequence_manager::TaskQueue> unthrottleable_task_queue_;
+  scoped_refptr<NonMainThreadTaskQueue> throttleable_task_queue_;
+  scoped_refptr<NonMainThreadTaskQueue> unthrottleable_task_queue_;
 
   SchedulingLifecycleState lifecycle_state_ =
       SchedulingLifecycleState::kNotThrottled;
diff --git a/third_party/blink/renderer/platform/scheduler/test/fake_page_scheduler.h b/third_party/blink/renderer/platform/scheduler/test/fake_page_scheduler.h
index 8e18065..029081f 100644
--- a/third_party/blink/renderer/platform/scheduler/test/fake_page_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/test/fake_page_scheduler.h
@@ -56,6 +56,7 @@
   void SetIsMainFrameLocal(bool is_local) override {}
 
   std::unique_ptr<FrameScheduler> CreateFrameScheduler(
+      FrameScheduler::Delegate* delegate,
       BlameContext* blame_context,
       FrameScheduler::FrameType frame_type) override {
     return nullptr;
diff --git a/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc b/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc
index f31853b7..e1027b1 100644
--- a/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc
+++ b/third_party/blink/renderer/platform/scheduler/test/renderer_scheduler_test_support.cc
@@ -18,7 +18,7 @@
 
 std::unique_ptr<WebThreadScheduler> CreateWebMainThreadSchedulerForTests() {
   return std::make_unique<scheduler::MainThreadSchedulerImpl>(
-      std::make_unique<base::sequence_manager::SequenceManagerForTest>(
+      base::sequence_manager::SequenceManagerForTest::Create(
           std::make_unique<
               base::sequence_manager::LazyThreadControllerForTest>()),
       base::nullopt);
diff --git a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
index 9063c89..60813ca 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.cc
@@ -14,7 +14,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/child/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/scheduler_helper.h"
 
 namespace blink {
@@ -44,8 +43,7 @@
                         .SetShouldMonitorQuiescence(true))
               : nullptr),
       input_task_runner_(input_task_queue_
-                             ? TaskQueueWithTaskType::Create(
-                                   input_task_queue_,
+                             ? input_task_queue_->CreateTaskRunner(
                                    TaskType::kCompositorThreadTaskQueueInput)
                              : nullptr),
       compositor_metrics_helper_(helper()->HasCPUTimingForEachTask()) {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h
index 9f7de2e..739f8c01 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/compositor_thread_scheduler.h
@@ -8,10 +8,10 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
+#include "components/scheduling_metrics/task_duration_metric_reporter.h"
 #include "third_party/blink/public/platform/scheduler/single_thread_idle_task_runner.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
-#include "third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/compositor_metrics_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h"
 
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.cc b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.cc
index a63fae8..85b34bd 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.h"
 
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
index ccfd7cb..690ef4e 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h"
 
 namespace blink {
@@ -33,7 +32,7 @@
 }
 
 scoped_refptr<NonMainThreadTaskQueue>
-NonMainThreadSchedulerImpl::CreateTaskRunner(const char* name) {
+NonMainThreadSchedulerImpl::CreateTaskQueue(const char* name) {
   helper_->CheckOnValidThread();
   return helper_->NewTaskQueue(base::sequence_manager::TaskQueue::Spec(name)
                                    .SetShouldMonitorQuiescence(true)
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
index f6b0dc6..a818ef8 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h
@@ -83,7 +83,7 @@
   //
   // virtual void Shutdown();
 
-  scoped_refptr<NonMainThreadTaskQueue> CreateTaskRunner(const char* name);
+  scoped_refptr<NonMainThreadTaskQueue> CreateTaskQueue(const char* name);
 
  protected:
   static void RunIdleTask(WebThread::IdleTask task, base::TimeTicks deadline);
diff --git a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
index ac48631..7667c54 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/non_main_thread_task_queue.h
@@ -6,6 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_WORKER_NON_MAIN_THREAD_TASK_QUEUE_H_
 
 #include "base/task/sequence_manager/task_queue_impl.h"
+#include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 
 namespace blink {
@@ -27,6 +28,11 @@
       const base::sequence_manager::TaskQueue::Task& task,
       const base::sequence_manager::TaskQueue::TaskTiming& task_timing);
 
+  scoped_refptr<base::SingleThreadTaskRunner> CreateTaskRunner(
+      TaskType task_type) {
+    return TaskQueue::CreateTaskRunner(static_cast<int>(task_type));
+  }
+
  private:
   // Not owned.
   NonMainThreadSchedulerImpl* non_main_thread_scheduler_;
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h b/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h
index b4dd2ca..9b1fb018 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h
@@ -28,13 +28,13 @@
   void SetParentFrameType(FrameOriginType frame_type);
 
  private:
-  TaskDurationMetricReporter<TaskType>
+  scheduling_metrics::TaskDurationMetricReporter<TaskType>
       dedicated_worker_per_task_type_duration_reporter_;
-  TaskDurationMetricReporter<TaskType>
+  scheduling_metrics::TaskDurationMetricReporter<TaskType>
       dedicated_worker_per_task_type_cpu_duration_reporter_;
-  TaskDurationMetricReporter<FrameOriginType>
+  scheduling_metrics::TaskDurationMetricReporter<FrameOriginType>
       dedicated_worker_per_parent_frame_status_duration_reporter_;
-  TaskDurationMetricReporter<FrameOriginType>
+  scheduling_metrics::TaskDurationMetricReporter<FrameOriginType>
       background_dedicated_worker_per_parent_frame_status_duration_reporter_;
 
   base::Optional<FrameOriginType> parent_frame_type_;
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
index 61bb507f..4cf15b6 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h"
 
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/wake_up_budget_pool.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy.h"
@@ -16,9 +15,9 @@
 WorkerScheduler::WorkerScheduler(WorkerThreadScheduler* worker_thread_scheduler,
                                  WorkerSchedulerProxy* proxy)
     : throttleable_task_queue_(
-          worker_thread_scheduler->CreateTaskRunner("worker_throttleable_tq")),
-      unthrottleable_task_queue_(worker_thread_scheduler->CreateTaskRunner(
-          "worker_unthrottleable_tq")),
+          worker_thread_scheduler->CreateTaskQueue("worker_throttleable_tq")),
+      unthrottleable_task_queue_(
+          worker_thread_scheduler->CreateTaskQueue("worker_unthrottleable_tq")),
       thread_scheduler_(worker_thread_scheduler),
       weak_factory_(this) {
   thread_scheduler_->RegisterWorkerScheduler(this);
@@ -93,7 +92,7 @@
     case TaskType::kJavascriptTimer:
     case TaskType::kPostedMessage:
     case TaskType::kWorkerAnimation:
-      return TaskQueueWithTaskType::Create(throttleable_task_queue_, type);
+      return throttleable_task_queue_->CreateTaskRunner(type);
     case TaskType::kDeprecatedNone:
     case TaskType::kDOMManipulation:
     case TaskType::kUserInteraction:
@@ -132,7 +131,7 @@
       // TODO(nhiroki): Identify which tasks can be throttled / suspendable and
       // move them into other task runners. See also comments in
       // Get(LocalFrame). (https://crbug.com/670534)
-      return TaskQueueWithTaskType::Create(unthrottleable_task_queue_, type);
+      return unthrottleable_task_queue_->CreateTaskRunner(type);
     case TaskType::kMainThreadTaskQueueV8:
     case TaskType::kMainThreadTaskQueueCompositor:
     case TaskType::kMainThreadTaskQueueDefault:
@@ -171,13 +170,12 @@
   NotifyLifecycleObservers();
 }
 
-scoped_refptr<base::sequence_manager::TaskQueue>
+scoped_refptr<NonMainThreadTaskQueue>
 WorkerScheduler::UnthrottleableTaskQueue() {
   return unthrottleable_task_queue_.get();
 }
 
-scoped_refptr<base::sequence_manager::TaskQueue>
-WorkerScheduler::ThrottleableTaskQueue() {
+scoped_refptr<NonMainThreadTaskQueue> WorkerScheduler::ThrottleableTaskQueue() {
   return throttleable_task_queue_.get();
 }
 
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
index 6d8438a..bbb555d9 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_scheduler_proxy_unittest.cc
@@ -124,6 +124,7 @@
         frame_scheduler_(
             FrameSchedulerImpl::Create(page_scheduler_.get(),
                                        nullptr,
+                                       nullptr,
                                        FrameScheduler::FrameType::kMainFrame)) {
     // Null clock triggers some assertions.
     task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
index cfbe041..ce441dc 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.cc
@@ -17,7 +17,6 @@
 #include "base/trace_event/trace_event_argument.h"
 #include "third_party/blink/renderer/platform/histogram.h"
 #include "third_party/blink/renderer/platform/scheduler/child/features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/throttling/task_queue_throttler.h"
 #include "third_party/blink/renderer/platform/scheduler/public/worker_scheduler.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_helper.h"
@@ -205,10 +204,10 @@
   initialized_ = true;
   idle_helper_.EnableLongIdlePeriod();
 
-  v8_task_runner_ = TaskQueueWithTaskType::Create(
-      DefaultTaskQueue(), TaskType::kWorkerThreadTaskQueueV8);
-  compositor_task_runner_ = TaskQueueWithTaskType::Create(
-      DefaultTaskQueue(), TaskType::kWorkerThreadTaskQueueCompositor);
+  v8_task_runner_ =
+      DefaultTaskQueue()->CreateTaskRunner(TaskType::kWorkerThreadTaskQueueV8);
+  compositor_task_runner_ = DefaultTaskQueue()->CreateTaskRunner(
+      TaskType::kWorkerThreadTaskQueueCompositor);
 }
 
 void WorkerThreadScheduler::OnTaskCompleted(
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
index 2cc9102..e1f6590 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler.h
@@ -9,11 +9,11 @@
 #include "base/message_loop/message_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "base/task/sequence_manager/task_time_observer.h"
+#include "components/scheduling_metrics/task_duration_metric_reporter.h"
 #include "third_party/blink/public/platform/web_thread_type.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_canceled_delayed_task_sweeper.h"
 #include "third_party/blink/renderer/platform/scheduler/common/idle_helper.h"
 #include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
-#include "third_party/blink/renderer/platform/scheduler/util/task_duration_metric_reporter.h"
 #include "third_party/blink/renderer/platform/scheduler/util/thread_load_tracker.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/non_main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/worker/worker_metrics_helper.h"
diff --git a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
index 7144c35..67979a0 100644
--- a/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
+++ b/third_party/blink/renderer/platform/scheduler/worker/worker_thread_scheduler_unittest.cc
@@ -101,7 +101,7 @@
     // Null clock might trigger some assertions.
     task_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(5));
     scheduler_->Init();
-    default_task_runner_ = scheduler_->CreateTaskRunner("test_tq");
+    default_task_runner_ = scheduler_->CreateTaskQueue("test_tq");
     idle_task_runner_ = scheduler_->IdleTaskRunner();
   }
 
diff --git a/third_party/blink/renderer/platform/timer_test.cc b/third_party/blink/renderer/platform/timer_test.cc
index 3ba86fa..e60defe1 100644
--- a/third_party/blink/renderer/platform/timer_test.cc
+++ b/third_party/blink/renderer/platform/timer_test.cc
@@ -12,7 +12,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_thread.h"
-#include "third_party/blink/renderer/platform/scheduler/child/task_queue_with_task_type.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h"
 #include "third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h"
 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
@@ -21,6 +20,7 @@
 #include "third_party/blink/renderer/platform/wtf/time.h"
 
 using base::sequence_manager::TaskQueue;
+using blink::scheduler::MainThreadTaskQueue;
 using testing::ElementsAre;
 
 namespace blink {
@@ -618,19 +618,17 @@
 };
 
 TEST_F(TimerTest, UserSuppliedTaskRunner) {
-  scoped_refptr<TaskQueue> task_runner(
+  scoped_refptr<MainThreadTaskQueue> task_queue(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type =
-      scheduler::TaskQueueWithTaskType::Create(task_runner,
-                                               TaskType::kInternalTest);
-  TimerForTest<TimerTest> timer(task_queue_with_task_type, this,
-                                &TimerTest::CountingTask);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      task_queue->CreateTaskRunner(TaskType::kInternalTest);
+  TimerForTest<TimerTest> timer(task_runner, this, &TimerTest::CountingTask);
   timer.StartOneShot(TimeDelta(), FROM_HERE);
 
   // Make sure the task was posted on taskRunner.
-  EXPECT_FALSE(task_runner->IsEmpty());
+  EXPECT_FALSE(task_queue->IsEmpty());
 }
 
 TEST_F(TimerTest, RunOnHeapTimer) {
@@ -715,28 +713,25 @@
 TEST_F(TimerTest, MoveToNewTaskRunnerOneShot) {
   std::vector<scoped_refptr<base::SingleThreadTaskRunner>> run_order;
 
-  scoped_refptr<TaskQueue> task_runner1(
+  scoped_refptr<MainThreadTaskQueue> task_queue1(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type1 =
-      scheduler::TaskQueueWithTaskType::Create(task_runner1,
-                                               TaskType::kInternalTest);
-  TaskObserver task_observer1(task_queue_with_task_type1, &run_order);
-  task_runner1->AddTaskObserver(&task_observer1);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner1 =
+      task_queue1->CreateTaskRunner(TaskType::kInternalTest);
+  TaskObserver task_observer1(task_runner1, &run_order);
+  task_queue1->AddTaskObserver(&task_observer1);
 
-  scoped_refptr<TaskQueue> task_runner2(
+  scoped_refptr<MainThreadTaskQueue> task_queue2(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type2 =
-      scheduler::TaskQueueWithTaskType::Create(task_runner2,
-                                               TaskType::kInternalTest);
-  TaskObserver task_observer2(task_queue_with_task_type2, &run_order);
-  task_runner2->AddTaskObserver(&task_observer2);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner2 =
+      task_queue2->CreateTaskRunner(TaskType::kInternalTest);
+  TaskObserver task_observer2(task_runner2, &run_order);
+  task_queue2->AddTaskObserver(&task_observer2);
 
-  TimerForTest<TimerTest> timer(task_queue_with_task_type1, this,
-                                &TimerTest::CountingTask);
+  TimerForTest<TimerTest> timer(task_runner1, this, &TimerTest::CountingTask);
 
   TimeTicks start_time = CurrentTimeTicks();
 
@@ -744,43 +739,40 @@
 
   platform_->RunForPeriod(TimeDelta::FromMilliseconds(500));
 
-  timer.MoveToNewTaskRunner(task_queue_with_task_type2);
+  timer.MoveToNewTaskRunner(task_runner2);
 
   platform_->RunUntilIdle();
 
   EXPECT_THAT(run_times_, ElementsAre(start_time + TimeDelta::FromSeconds(1)));
 
-  EXPECT_THAT(run_order, ElementsAre(task_queue_with_task_type2));
+  EXPECT_THAT(run_order, ElementsAre(task_runner2));
 
-  EXPECT_TRUE(task_runner1->IsEmpty());
-  EXPECT_TRUE(task_runner2->IsEmpty());
+  EXPECT_TRUE(task_queue1->IsEmpty());
+  EXPECT_TRUE(task_queue2->IsEmpty());
 }
 
 TEST_F(TimerTest, MoveToNewTaskRunnerRepeating) {
   std::vector<scoped_refptr<base::SingleThreadTaskRunner>> run_order;
 
-  scoped_refptr<TaskQueue> task_runner1(
+  scoped_refptr<MainThreadTaskQueue> task_queue1(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type1 =
-      scheduler::TaskQueueWithTaskType::Create(task_runner1,
-                                               TaskType::kInternalTest);
-  TaskObserver task_observer1(task_queue_with_task_type1, &run_order);
-  task_runner1->AddTaskObserver(&task_observer1);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner1 =
+      task_queue1->CreateTaskRunner(TaskType::kInternalTest);
+  TaskObserver task_observer1(task_runner1, &run_order);
+  task_queue1->AddTaskObserver(&task_observer1);
 
-  scoped_refptr<TaskQueue> task_runner2(
+  scoped_refptr<MainThreadTaskQueue> task_queue2(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type2 =
-      scheduler::TaskQueueWithTaskType::Create(task_runner2,
-                                               TaskType::kInternalTest);
-  TaskObserver task_observer2(task_queue_with_task_type2, &run_order);
-  task_runner2->AddTaskObserver(&task_observer2);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner2 =
+      task_queue2->CreateTaskRunner(TaskType::kInternalTest);
+  TaskObserver task_observer2(task_runner2, &run_order);
+  task_queue2->AddTaskObserver(&task_observer2);
 
-  TimerForTest<TimerTest> timer(task_queue_with_task_type1, this,
-                                &TimerTest::CountingTask);
+  TimerForTest<TimerTest> timer(task_runner1, this, &TimerTest::CountingTask);
 
   TimeTicks start_time = CurrentTimeTicks();
 
@@ -788,7 +780,7 @@
 
   platform_->RunForPeriod(TimeDelta::FromMilliseconds(2500));
 
-  timer.MoveToNewTaskRunner(task_queue_with_task_type2);
+  timer.MoveToNewTaskRunner(task_runner2);
 
   platform_->RunForPeriod(TimeDelta::FromSeconds(2));
 
@@ -797,41 +789,36 @@
                                       start_time + TimeDelta::FromSeconds(3),
                                       start_time + TimeDelta::FromSeconds(4)));
 
-  EXPECT_THAT(
-      run_order,
-      ElementsAre(task_queue_with_task_type1, task_queue_with_task_type1,
-                  task_queue_with_task_type2, task_queue_with_task_type2));
+  EXPECT_THAT(run_order, ElementsAre(task_runner1, task_runner1, task_runner2,
+                                     task_runner2));
 
-  EXPECT_TRUE(task_runner1->IsEmpty());
-  EXPECT_FALSE(task_runner2->IsEmpty());
+  EXPECT_TRUE(task_queue1->IsEmpty());
+  EXPECT_FALSE(task_queue2->IsEmpty());
 }
 
 // This test checks that when inactive timer is moved to a different task
 // runner it isn't activated.
 TEST_F(TimerTest, MoveToNewTaskRunnerWithoutTasks) {
-  scoped_refptr<TaskQueue> task_runner1(
+  scoped_refptr<MainThreadTaskQueue> task_queue1(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type1 =
-      scheduler::TaskQueueWithTaskType::Create(task_runner1,
-                                               TaskType::kInternalTest);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner1 =
+      task_queue1->CreateTaskRunner(TaskType::kInternalTest);
 
-  scoped_refptr<TaskQueue> task_runner2(
+  scoped_refptr<MainThreadTaskQueue> task_queue2(
       platform_->GetMainThreadScheduler()->NewTimerTaskQueue(
           scheduler::MainThreadTaskQueue::QueueType::kFrameThrottleable,
           nullptr));
-  scoped_refptr<scheduler::TaskQueueWithTaskType> task_queue_with_task_type2 =
-      scheduler::TaskQueueWithTaskType::Create(task_runner2,
-                                               TaskType::kInternalTest);
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner2 =
+      task_queue2->CreateTaskRunner(TaskType::kInternalTest);
 
-  TimerForTest<TimerTest> timer(task_queue_with_task_type1, this,
-                                &TimerTest::CountingTask);
+  TimerForTest<TimerTest> timer(task_runner1, this, &TimerTest::CountingTask);
 
   platform_->RunUntilIdle();
   EXPECT_TRUE(!run_times_.size());
-  EXPECT_TRUE(task_runner1->IsEmpty());
-  EXPECT_TRUE(task_runner2->IsEmpty());
+  EXPECT_TRUE(task_queue1->IsEmpty());
+  EXPECT_TRUE(task_queue2->IsEmpty());
 }
 
 }  // namespace
diff --git a/third_party/pywebsocket/OWNERS b/third_party/pywebsocket/OWNERS
index d1ce751..d5f5069 100644
--- a/third_party/pywebsocket/OWNERS
+++ b/third_party/pywebsocket/OWNERS
@@ -1,4 +1,4 @@
-tyoshino@chromium.org
+ricea@chromium.org
 yhirano@chromium.org
 
 # TEAM: blink-network-dev@chromium.org
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ccbba2f..51d788f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -42088,6 +42088,16 @@
   <int value="11" label="(gesture) ScheduledPageBlock"/>
 </enum>
 
+<enum name="SchedulerThreadType">
+  <int value="0" label="BrowserUIThread"/>
+  <int value="1" label="BrowserIOThread"/>
+  <int value="2" label="RendererMainThread"/>
+  <int value="3" label="RendererCompositorThread"/>
+  <int value="4" label="RendererDedicatedWorkerThread"/>
+  <int value="5" label="RendererServiceWorkerThread"/>
+  <int value="6" label="RendererOtherBlinkThread"/>
+</enum>
+
 <enum name="ScoutActiveExtendedReportingPref">
   <int value="0" label="Active pref is the legacy SBER pref"/>
   <int value="1" label="Active pref is the new Scout pref"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0b9c0e6..b980b28b 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -86556,6 +86556,18 @@
   </summary>
 </histogram>
 
+<histogram name="Scheduler.Experimental.CPUTimePerThread"
+    enum="SchedulerThreadType">
+  <owner>altimin@chromium.org</owner>
+  <summary>
+    Total wall time of all tasks in scheduler-managed threads split per thread.
+
+    The bucket value is the sum of thread durations of all tasks in this thread
+    across all browsing instances. This metric is reported each time we execute
+    a task which has cpu time measurement.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Scheduler.Experimental.Renderer.CPUTimePerThread"
     enum="RendererSchedulerThreadType">
   <owner>altimin@chromium.org</owner>
@@ -86587,6 +86599,18 @@
   </summary>
 </histogram>
 
+<histogram name="Scheduler.Experimental.WallTimePerThread"
+    enum="SchedulerThreadType">
+  <owner>altimin@chromium.org</owner>
+  <summary>
+    Total wall time of all tasks in scheduler-managed threads split per thread.
+
+    The bucket value is the sum of thread durations of all tasks in this thread
+    across all browsing instances. This metric is reported each time we execute
+    a task which has wall time measurement.
+  </summary>
+</histogram>
+
 <histogram name="Scheduling.ActivateDuration" units="microseconds">
   <obsolete>
     Replaced by ActivateDuration2, due to inefficient bucketing scheme.
@@ -99786,6 +99810,10 @@
 </histogram>
 
 <histogram name="Sync.ExtraSyncDataCount" units="entries">
+  <obsolete>
+    Deprecated as of 07/2018. No longer tracked (because it is
+    directory-specific and related to now obsolete metrics Sync.ModelTypeCount).
+  </obsolete>
   <owner>gangwu@chromium.org</owner>
   <summary>
     Counts the total number of extra copies of sync data in memory. This count
@@ -100203,12 +100231,27 @@
 </histogram>
 
 <histogram name="Sync.ModelTypeCount" units="entries">
+  <obsolete>
+    Deprecated as of 7/2018. Replaced by Sync.ModelTypeCount2 which does record
+    data consistently for both directory data types and USS data types.
+  </obsolete>
   <owner>gangwu@chromium.org</owner>
   <summary>
     Counts the number of entries for each model type in sync DB at startup.
   </summary>
 </histogram>
 
+<histogram base="true" name="Sync.ModelTypeCount2" units="entries"
+    expires_after="2020-02-01">
+  <owner>gangwu@chromium.org</owner>
+  <summary>
+    Counts the number of entries for each model type. For directory types, the
+    count is based on the directory contents, for USS types, the count is based
+    on metadata entries for the type. Recorded after sync configuration. This
+    metric is used for monitoring general health of sync client-side code.
+  </summary>
+</histogram>
+
 <histogram base="true" name="Sync.ModelTypeEntityChange"
     enum="SyncEntityChange" expires_after="2020-02-01">
   <owner>jkrcal@chromium.org</owner>
@@ -100220,11 +100263,13 @@
   </summary>
 </histogram>
 
-<histogram name="Sync.ModelTypeMemoryKB" units="KB">
+<histogram base="true" name="Sync.ModelTypeMemoryKB" units="KB"
+    expires_after="2020-02-01">
   <owner>pavely@chromium.org</owner>
   <summary>
     Estimated memory usage by sync datatype in kilobytes. Recorded after sync
-    configuration.
+    configuration. This metric is used for monitoring general health of sync
+    client-side code.
   </summary>
 </histogram>
 
@@ -125588,11 +125633,15 @@
 
 <histogram_suffixes name="SchedulerDarkMatterMetrics" separator=".">
   <suffix name="Tracked"
-      label="Total duration of all tasks managed by the scheduler."/>
+      label="Total duration of all tasks managed by the scheduler. This
+             histogram is similar to the plain .CPUTimePerThread, but it
+             ensures that the number of samples matches the .Untracked
+             version of the same histogram."/>
   <suffix name="Untracked"
       label="Total execution time unaccounted for by the scheduler.
              Calculated as the difference between total thread time and the
              sum of all tasks managed by the scheduler."/>
+  <affected-histogram name="Scheduler.Experimental.CPUTimePerThread"/>
   <affected-histogram name="Scheduler.Experimental.Renderer.CPUTimePerThread"/>
 </histogram_suffixes>
 
@@ -126647,7 +126696,12 @@
   <suffix name="USER_CONSENT" label="USER_CONSENT"/>
   <suffix name="USER_EVENT" label="USER_EVENT"/>
   <suffix name="WIFI_CREDENTIAL" label="WIFI_CREDENTIAL"/>
-  <affected-histogram name="Sync.ModelTypeCount"/>
+  <affected-histogram name="Sync.ModelTypeCount">
+    <obsolete>
+      Deprecated 7/2018. Replaced by Sync.ModelTypeCount2.
+    </obsolete>
+  </affected-histogram>
+  <affected-histogram name="Sync.ModelTypeCount2"/>
   <affected-histogram name="Sync.ModelTypeEntityChange"/>
   <affected-histogram name="Sync.ModelTypeMemoryKB"/>
 </histogram_suffixes>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml
index c7d83bfd..eb56b65b 100644
--- a/tools/metrics/ukm/ukm.xml
+++ b/tools/metrics/ukm/ukm.xml
@@ -3109,10 +3109,16 @@
       blink::scheduler::FrameStatus for the values of this enum.
     </summary>
   </metric>
+  <metric name="IsOOPIF">
+    <summary>
+      Whether the frame which the task is associated with is an out-of-process
+      iframe. Boolean encoded as an integer (0/1).
+    </summary>
+  </metric>
   <metric name="PageSchedulers">
     <summary>
-      Number of pages this task should be attributed to. One if there is a hard
-      attribution, number of pages in the process otherwise.
+      Number of page schedulers in this process. If the value equals one, global
+      per-process tasks can be attributed to the URL.
     </summary>
   </metric>
   <metric name="QueueType">
diff --git a/tools/perf/core/perf_benchmark.py b/tools/perf/core/perf_benchmark.py
index c0714266..b04418c 100644
--- a/tools/perf/core/perf_benchmark.py
+++ b/tools/perf/core/perf_benchmark.py
@@ -97,6 +97,12 @@
       options.profile_files_to_copy.extend(
           GetAdTaggingProfileFiles(self._GetOutDirectoryEstimate(options)))
 
+    # A non-sandboxed, 15-seconds-delayed gpu process is currently running in
+    # the browser to collect gpu info. A command line switch is added here to
+    # skip this gpu process for all perf tests to prevent any interference
+    # with the test results.
+    options.AppendExtraBrowserArgs(
+        '--disable-gpu-process-for-dx12-vulkan-info-collection')
     self.SetExtraBrowserOptions(options)
 
   @staticmethod
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index b0ea4b3..07294346 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -121,27 +121,6 @@
       },
       'testing': True,
     },
-    'Android Go': {
-      'tests': [
-        {
-          'name': 'performance_test_suite',
-          'isolate': 'performance_test_suite',
-          'extra_args': [
-            '--run-ref-build',
-            '--test-shard-map-filename=android_go_shard_map.json',
-          ],
-          'num_shards': 19
-        }
-      ],
-      'platform': 'android',
-      'dimension': {
-        'device_os': 'O',
-        'device_type': 'gobo',
-        'device_os_flavor': 'google',
-        'pool': 'chrome.tests.perf-fyi',
-        'os': 'Android',
-      },
-    },
     'android-pixel2_webview-perf': {
       'tests': [
         {
@@ -189,6 +168,27 @@
 # to generate the correct json for each tester
 NEW_PERF_RECIPE_MIGRATED_TESTERS = {
   'testers' : {
+    'android-go-perf': {
+      'tests': [
+        {
+          'name': 'performance_test_suite',
+          'isolate': 'performance_test_suite',
+          'extra_args': [
+            '--run-ref-build',
+            '--test-shard-map-filename=android_go_shard_map.json',
+          ],
+          'num_shards': 19
+        }
+      ],
+      'platform': 'android',
+      'dimension': {
+        'device_os': 'O',
+        'device_type': 'gobo',
+        'device_os_flavor': 'google',
+        'pool': 'chrome.tests.perf',
+        'os': 'Android',
+      },
+    },
     'android-nexus5x-perf': {
       'tests': [
         {
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index 85790f2..a1d3de6 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -289,6 +289,7 @@
 crbug.com/714650 [ Android ] system_health.memory_mobile/browse:news:globo [ Skip ]
 [ Android_Webview ] system_health.memory_mobile/browse:chrome:omnibox [ Skip ]
 crbug.com/819552 [ Nexus_5X ] system_health.memory_mobile/browse:chrome:omnibox [ Skip ]
+crbug.com/867853 [ Nexus_5X ] system_health.memory_mobile/browse:chrome:newtab [ Skip ]
 crbug.com/657433 [ Android ] system_health.memory_mobile/load:tools:gmail [ Skip ]
 crbug.com/777355 [ Android_Low_End ] system_health.memory_mobile/long_running:tools:gmail-background [ Skip ]
 crbug.com/777355 [ Android_Webview ] system_health.memory_mobile/long_running:tools:gmail-foreground [ Skip ]
diff --git a/ui/file_manager/integration_tests/file_manager/zip_files.js b/ui/file_manager/integration_tests/file_manager/zip_files.js
index 248e3fb..b4ea25b9 100644
--- a/ui/file_manager/integration_tests/file_manager/zip_files.js
+++ b/ui/file_manager/integration_tests/file_manager/zip_files.js
@@ -5,9 +5,9 @@
 'use strict';
 
 /**
- * Returns the file ENTRIES.zipArchive content (2 files) as row entries.
+ * Returns the ENTRIES.zipArchive content (2 files) as row entries.
  */
-function getZipArchiveFileRowEntries() {
+function getUnzippedFileRowEntries() {
   return [
     ['image.png', '272 bytes', 'PNG image', 'Sep 2, 2013, 10:01 PM'],
     ['text.txt', '51 bytes', 'Plain text', 'Sep 2, 2013, 10:01 PM']
@@ -41,7 +41,7 @@
     // Check: the zip file content should be shown (unzip).
     function(result) {
       chrome.test.assertTrue(!!result, 'fakeKeyDown failed');
-      const files = getZipArchiveFileRowEntries();
+      const files = getUnzippedFileRowEntries();
       remoteCall.waitForFiles(appId, files).then(this.next);
     },
   ]);
@@ -74,7 +74,7 @@
     // Check: the zip file content should be shown (unzip).
     function(result) {
       chrome.test.assertTrue(!!result, 'fakeKeyDown failed');
-      const files = getZipArchiveFileRowEntries();
+      const files = getUnzippedFileRowEntries();
       remoteCall.waitForFiles(appId, files).then(this.next);
     },
   ]);
@@ -132,7 +132,7 @@
     // Check: the zip file content should be shown (unzip).
     function(result) {
       chrome.test.assertTrue(!!result, 'fakeKeyDown failed');
-      const files = getZipArchiveFileRowEntries();
+      const files = getUnzippedFileRowEntries();
       remoteCall.waitForFiles(appId, files).then(this.next);
     },
   ]);
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index 32f88a2..ab5bcab 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -426,7 +426,8 @@
   matrix.setTranslate(SkIntToScalar(x), SkIntToScalar(y));
   cc::PaintFlags flags(original_flags);
   flags.setShader(
-      CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode, matrix));
+      CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode,
+                           SkShader::kRepeat_TileMode, matrix));
   canvas_->drawPath(path, flags);
 }
 
@@ -454,6 +455,8 @@
                           int w,
                           int h,
                           float tile_scale,
+                          SkShader::TileMode tile_mode_x,
+                          SkShader::TileMode tile_mode_y,
                           cc::PaintFlags* flags) {
   SkRect dest_rect = { SkIntToScalar(dest_x),
                        SkIntToScalar(dest_y),
@@ -467,7 +470,7 @@
     flags = &paint_flags;
 
   if (InitPaintFlagsForTiling(image, src_x, src_y, tile_scale, tile_scale,
-                              dest_x, dest_y, flags))
+                              dest_x, dest_y, tile_mode_x, tile_mode_y, flags))
     canvas_->drawRect(dest_rect, *flags);
 }
 
@@ -478,6 +481,8 @@
                                      float tile_scale_y,
                                      int dest_x,
                                      int dest_y,
+                                     SkShader::TileMode tile_mode_x,
+                                     SkShader::TileMode tile_mode_y,
                                      cc::PaintFlags* flags) {
   const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
   if (image_rep.is_null())
@@ -489,7 +494,7 @@
   shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
   shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
 
-  flags->setShader(CreateImageRepShader(image_rep, SkShader::kRepeat_TileMode,
+  flags->setShader(CreateImageRepShader(image_rep, tile_mode_x, tile_mode_y,
                                         shader_scale));
   return true;
 }
@@ -550,8 +555,8 @@
   cc::PaintFlags flags(original_flags);
   flags.setFilterQuality(filter ? kLow_SkFilterQuality : kNone_SkFilterQuality);
   flags.setShader(CreateImageRepShaderForScale(
-      image_rep, SkShader::kRepeat_TileMode, shader_scale,
-      remove_image_scale ? image_rep.scale() : 1.f));
+      image_rep, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
+      shader_scale, remove_image_scale ? image_rep.scale() : 1.f));
 
   // The rect will be filled by the bitmap.
   canvas_->drawRect(dest_rect, flags);
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index a34b6cba..06de8f2 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -406,6 +406,8 @@
                     int w,
                     int h,
                     float tile_scale = 1.0f,
+                    SkShader::TileMode tile_mode_x = SkShader::kRepeat_TileMode,
+                    SkShader::TileMode tile_mode_y = SkShader::kRepeat_TileMode,
                     cc::PaintFlags* flags = nullptr);
 
   // Helper for TileImageInt().  Initializes |flags| for tiling |image| with the
@@ -418,6 +420,8 @@
                                float tile_scale_y,
                                int dest_x,
                                int dest_y,
+                               SkShader::TileMode tile_mode_x,
+                               SkShader::TileMode tile_mode_y,
                                cc::PaintFlags* flags);
 
   // Apply transformation on the canvas.
diff --git a/ui/gfx/skia_paint_util.cc b/ui/gfx/skia_paint_util.cc
index 38ee87e..3ca09ee 100644
--- a/ui/gfx/skia_paint_util.cc
+++ b/ui/gfx/skia_paint_util.cc
@@ -14,15 +14,17 @@
 namespace gfx {
 
 sk_sp<cc::PaintShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
-                                            SkShader::TileMode tile_mode,
+                                            SkShader::TileMode tile_mode_x,
+                                            SkShader::TileMode tile_mode_y,
                                             const SkMatrix& local_matrix) {
-  return CreateImageRepShaderForScale(image_rep, tile_mode, local_matrix,
-                                      image_rep.scale());
+  return CreateImageRepShaderForScale(image_rep, tile_mode_x, tile_mode_y,
+                                      local_matrix, image_rep.scale());
 }
 
 sk_sp<cc::PaintShader> CreateImageRepShaderForScale(
     const gfx::ImageSkiaRep& image_rep,
-    SkShader::TileMode tile_mode,
+    SkShader::TileMode tile_mode_x,
+    SkShader::TileMode tile_mode_y,
     const SkMatrix& local_matrix,
     SkScalar scale) {
   // Unscale matrix by |scale| such that the bitmap is drawn at the
@@ -37,8 +39,8 @@
   shader_scale.setScaleX(local_matrix.getScaleX() / scale);
   shader_scale.setScaleY(local_matrix.getScaleY() / scale);
 
-  return cc::PaintShader::MakeImage(image_rep.paint_image(), tile_mode,
-                                    tile_mode, &shader_scale);
+  return cc::PaintShader::MakeImage(image_rep.paint_image(), tile_mode_x,
+                                    tile_mode_y, &shader_scale);
 }
 
 sk_sp<cc::PaintShader> CreateGradientShader(int start_point,
diff --git a/ui/gfx/skia_paint_util.h b/ui/gfx/skia_paint_util.h
index f76fc23..273e95b 100644
--- a/ui/gfx/skia_paint_util.h
+++ b/ui/gfx/skia_paint_util.h
@@ -28,13 +28,15 @@
 //
 GFX_EXPORT sk_sp<cc::PaintShader> CreateImageRepShader(
     const gfx::ImageSkiaRep& image_rep,
-    SkShader::TileMode tile_mode,
+    SkShader::TileMode tile_mode_x,
+    SkShader::TileMode tile_mode_y,
     const SkMatrix& local_matrix);
 
 // Creates a bitmap shader for the image rep with the passed in scale factor.
 GFX_EXPORT sk_sp<cc::PaintShader> CreateImageRepShaderForScale(
     const gfx::ImageSkiaRep& image_rep,
-    SkShader::TileMode tile_mode,
+    SkShader::TileMode tile_mode_x,
+    SkShader::TileMode tile_mode_y,
     const SkMatrix& local_matrix,
     SkScalar scale);
 
diff --git a/ui/keyboard/container_behavior.h b/ui/keyboard/container_behavior.h
index 60fe8250..3d5eee9 100644
--- a/ui/keyboard/container_behavior.h
+++ b/ui/keyboard/container_behavior.h
@@ -72,14 +72,20 @@
   // Removing focus from a text field should cause the keyboard to be dismissed.
   virtual bool TextBlurHidesKeyboard() const = 0;
 
-  // Gets the region of the screen that is occluded by the keyboard, or an empty
-  // rectangle if nothing is occluded. The occluded region is considered to be
-  // 'unusable', so the window manager or other system UI should respond to the
-  // occluded bounds (e.g. by moving windows out of the occluded region).
+  // Sets a region of the keyboard window that is occluded by the keyboard.
+  // This is called by the IME extension code. By default, this call is ignored.
+  // Container behaviors that listen for this call should override this method.
+  virtual void SetOccludedBounds(const gfx::Rect& occluded_bounds_in_window) {}
+
+  // Gets the region of the keyboard window that is occluded by the keyboard, or
+  // an empty rectangle if nothing is occluded. The occluded region is
+  // considered to be 'unusable', so the window manager or other system UI
+  // should respond to the occluded bounds (e.g. by moving windows out of the
+  // occluded region).
   //
   // The occluded bounds must be completely contained in the visual bounds.
   virtual gfx::Rect GetOccludedBounds(
-      const gfx::Rect& visual_bounds_in_screen) const = 0;
+      const gfx::Rect& visual_bounds_in_window) const = 0;
 
   // Any region of the screen that is occluded by the keyboard should cause the
   // workspace to change its layout.
diff --git a/ui/keyboard/container_full_width_behavior.cc b/ui/keyboard/container_full_width_behavior.cc
index 22543e5..63e42bf 100644
--- a/ui/keyboard/container_full_width_behavior.cc
+++ b/ui/keyboard/container_full_width_behavior.cc
@@ -112,9 +112,16 @@
   return !controller_->keyboard_locked();
 }
 
+void ContainerFullWidthBehavior::SetOccludedBounds(
+    const gfx::Rect& occluded_bounds_in_window) {
+  occluded_bounds_in_window_ = occluded_bounds_in_window;
+}
+
 gfx::Rect ContainerFullWidthBehavior::GetOccludedBounds(
-    const gfx::Rect& visual_bounds_in_screen) const {
-  return visual_bounds_in_screen;
+    const gfx::Rect& visual_bounds_in_window) const {
+  DCHECK(visual_bounds_in_window.Contains(occluded_bounds_in_window_));
+  return occluded_bounds_in_window_.IsEmpty() ? visual_bounds_in_window
+                                              : occluded_bounds_in_window_;
 }
 
 bool ContainerFullWidthBehavior::OccludedBoundsAffectWorkspaceLayout() const {
diff --git a/ui/keyboard/container_full_width_behavior.h b/ui/keyboard/container_full_width_behavior.h
index ecc6bccc..b11e487 100644
--- a/ui/keyboard/container_full_width_behavior.h
+++ b/ui/keyboard/container_full_width_behavior.h
@@ -47,12 +47,14 @@
                           const gfx::Rect& display_bounds) override;
   ContainerType GetType() const override;
   bool TextBlurHidesKeyboard() const override;
+  void SetOccludedBounds(const gfx::Rect& occluded_bounds_in_window) override;
   gfx::Rect GetOccludedBounds(
       const gfx::Rect& visual_bounds_in_screen) const override;
   bool OccludedBoundsAffectWorkspaceLayout() const override;
   bool SetDraggableArea(const gfx::Rect& rect) override;
 
  private:
+  gfx::Rect occluded_bounds_in_window_;
   KeyboardController* controller_;
 };
 
diff --git a/ui/keyboard/container_fullscreen_behavior.h b/ui/keyboard/container_fullscreen_behavior.h
index e314443..7383043 100644
--- a/ui/keyboard/container_fullscreen_behavior.h
+++ b/ui/keyboard/container_fullscreen_behavior.h
@@ -25,12 +25,10 @@
   void SetCanonicalBounds(aura::Window* container,
                           const gfx::Rect& display_bounds) override;
   ContainerType GetType() const override;
+  void SetOccludedBounds(const gfx::Rect& occluded_bounds_in_window) override;
   gfx::Rect GetOccludedBounds(
       const gfx::Rect& visual_bounds_in_screen) const override;
 
-  // Sets the occluded bounds that is returned by |GetOccludedBounds|.
-  void SetOccludedBounds(const gfx::Rect& occluded_bounds);
-
  private:
   // The occluded bounds for fullscreen behavior is determined on the IME
   // extension side, so it has to be passed here via the extension API.
diff --git a/ui/keyboard/keyboard_controller.cc b/ui/keyboard/keyboard_controller.cc
index 298e41f..cb23705 100644
--- a/ui/keyboard/keyboard_controller.cc
+++ b/ui/keyboard/keyboard_controller.cc
@@ -259,7 +259,7 @@
   return g_keyboard_controller;
 }
 
-aura::Window* KeyboardController::GetKeyboardWindow() {
+aura::Window* KeyboardController::GetKeyboardWindow() const {
   return ui_ && ui_->HasKeyboardWindow() ? ui_->GetKeyboardWindow() : nullptr;
 }
 
@@ -271,14 +271,14 @@
     const gfx::Rect& new_bounds) {
   visual_bounds_in_screen_ = new_bounds;
   if (ui_->HasKeyboardWindow() && ui_->GetKeyboardWindow()->IsVisible()) {
-    const gfx::Rect occluded_bounds =
-        container_behavior_->GetOccludedBounds(new_bounds);
+    const gfx::Rect occluded_bounds_in_screen = GetWorkspaceOccludedBounds();
     notification_manager_.SendNotifications(
         container_behavior_->OccludedBoundsAffectWorkspaceLayout(),
-        keyboard_locked(), new_bounds, occluded_bounds, observer_list_);
+        keyboard_locked(), new_bounds, occluded_bounds_in_screen,
+        observer_list_);
 
     if (keyboard::IsKeyboardOverscrollEnabled())
-      ui_->InitInsets(occluded_bounds);
+      ui_->InitInsets(occluded_bounds_in_screen);
     else
       ui_->ResetInsets();
   } else {
@@ -478,8 +478,7 @@
   // Notify observers after animation finished to prevent reveal desktop
   // background during animation.
   NotifyKeyboardBoundsChanging(GetKeyboardWindow()->bounds());
-  ui_->EnsureCaretInWorkArea(
-      container_behavior_->GetOccludedBounds(GetKeyboardWindow()->bounds()));
+  ui_->EnsureCaretInWorkArea(GetWorkspaceOccludedBounds());
 }
 
 void KeyboardController::SetContainerBehaviorInternal(
@@ -766,7 +765,12 @@
 }
 
 gfx::Rect KeyboardController::GetWorkspaceOccludedBounds() const {
-  return container_behavior_->GetOccludedBounds(visual_bounds_in_screen_);
+  const gfx::Rect visual_bounds_in_window(visual_bounds_in_screen_.size());
+  const gfx::Rect occluded_bounds_in_window =
+      container_behavior_->GetOccludedBounds(visual_bounds_in_window);
+  // Return occluded bounds that are relative to the screen.
+  return occluded_bounds_in_window +
+         visual_bounds_in_screen_.OffsetFromOrigin();
 }
 
 gfx::Rect KeyboardController::GetKeyboardLockScreenOffsetBounds() const {
@@ -781,12 +785,8 @@
   return gfx::Rect();
 }
 
-void KeyboardController::SetOccludedBounds(const gfx::Rect& bounds) {
-  if (container_behavior_->GetType() != ContainerType::FULLSCREEN)
-    return;
-
-  static_cast<ContainerFullscreenBehavior&>(*container_behavior_)
-      .SetOccludedBounds(bounds);
+void KeyboardController::SetOccludedBounds(const gfx::Rect& bounds_in_window) {
+  container_behavior_->SetOccludedBounds(bounds_in_window);
 
   // Notify that only the occluded bounds have changed.
   if (IsKeyboardVisible())
diff --git a/ui/keyboard/keyboard_controller.h b/ui/keyboard/keyboard_controller.h
index 7c72a927..a6660e8 100644
--- a/ui/keyboard/keyboard_controller.h
+++ b/ui/keyboard/keyboard_controller.h
@@ -97,7 +97,7 @@
 
   // Returns the keyboard window, or null if the keyboard window has not been
   // created yet.
-  aura::Window* GetKeyboardWindow();
+  aura::Window* GetKeyboardWindow() const;
 
   // Returns the root window that this keyboard controller is attached to, or
   // null if the keyboard has not been attached to any root window.
@@ -179,8 +179,8 @@
   // lock screens.
   gfx::Rect GetKeyboardLockScreenOffsetBounds() const;
 
-  // Set the area on the screen that are occluded by the keyboard.
-  void SetOccludedBounds(const gfx::Rect& bounds);
+  // Set the area on the keyboard window that occlude whatever is behind it.
+  void SetOccludedBounds(const gfx::Rect& bounds_in_window);
 
   // Set the areas on the keyboard window where events should be handled.
   // Does not do anything if there is no keyboard window.
diff --git a/ui/ozone/platform/wayland/wayland_window.cc b/ui/ozone/platform/wayland/wayland_window.cc
index e1ec8fa6..c2dc242 100644
--- a/ui/ozone/platform/wayland/wayland_window.cc
+++ b/ui/ozone/platform/wayland/wayland_window.cc
@@ -98,8 +98,7 @@
   DCHECK(xdg_shell_objects_factory_);
 
   bounds_ = properties.bounds;
-  if (properties.parent_widget != gfx::kNullAcceleratedWidget)
-    parent_window_ = GetParentWindow(properties.parent_widget);
+  parent_window_ = GetParentWindow(properties.parent_widget);
 
   surface_.reset(wl_compositor_create_surface(connection_->compositor()));
   if (!surface_) {
diff --git a/ui/ozone/platform/wayland/wayland_window_unittest.cc b/ui/ozone/platform/wayland/wayland_window_unittest.cc
index 9fa0138..11c80b0c 100644
--- a/ui/ozone/platform/wayland/wayland_window_unittest.cc
+++ b/ui/ozone/platform/wayland/wayland_window_unittest.cc
@@ -516,6 +516,25 @@
   Sync();
 }
 
+TEST_P(WaylandWindowTest, CreateAndDestroyMenuWindowWithFocusedParent) {
+  MockPlatformWindowDelegate menu_window_delegate;
+  EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetDestroying()).Times(1);
+  EXPECT_CALL(menu_window_delegate, OnAcceleratedWidgetDestroyed()).Times(1);
+
+  // set_pointer_focus(true) requires a WaylandPointer.
+  wl_seat_send_capabilities(server_.seat()->resource(),
+                            WL_SEAT_CAPABILITY_POINTER);
+  Sync();
+  ASSERT_TRUE(connection_->pointer());
+  window_->set_pointer_focus(true);
+
+  std::unique_ptr<WaylandWindow> menu_window = CreateWaylandWindowWithParams(
+      PlatformWindowType::kMenu, gfx::kNullAcceleratedWidget,
+      gfx::Rect(0, 0, 10, 10), &menu_window_delegate);
+
+  Sync();
+}
+
 TEST_P(WaylandWindowTest, CreateAndDestroyNestedMenuWindow) {
   MockPlatformWindowDelegate menu_window_delegate;
   gfx::AcceleratedWidget menu_window_widget;
diff --git a/webrunner/browser/webrunner_browser_context.cc b/webrunner/browser/webrunner_browser_context.cc
index 84d6141c..6be2563 100644
--- a/webrunner/browser/webrunner_browser_context.cc
+++ b/webrunner/browser/webrunner_browser_context.cc
@@ -76,6 +76,11 @@
   return base::FilePath();
 }
 
+base::FilePath WebRunnerBrowserContext::GetCachePath() const {
+  NOTIMPLEMENTED();
+  return base::FilePath();
+}
+
 bool WebRunnerBrowserContext::IsOffTheRecord() const {
   return false;
 }
diff --git a/webrunner/browser/webrunner_browser_context.h b/webrunner/browser/webrunner_browser_context.h
index 121ac29..b247dc09 100644
--- a/webrunner/browser/webrunner_browser_context.h
+++ b/webrunner/browser/webrunner_browser_context.h
@@ -22,6 +22,7 @@
   std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
       const base::FilePath& partition_path) override;
   base::FilePath GetPath() const override;
+  base::FilePath GetCachePath() const override;
   bool IsOffTheRecord() const override;
   content::ResourceContext* GetResourceContext() override;
   content::DownloadManagerDelegate* GetDownloadManagerDelegate() override;