diff --git a/DEPS b/DEPS
index d0ae8b8..7e7aec5 100644
--- a/DEPS
+++ b/DEPS
@@ -121,11 +121,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': '6f27489c650284c9488d0a82ab03b31dc48656cc',
+  'skia_revision': '6d7f9d6f289944332986c2534d5a5ff1028897fb',
   # 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': 'd1b761f2f6d5db7ffabdc82a534fcd8f43472c8a',
+  'v8_revision': '414f4dc3f8876dbe57ffaff5e861bbc25589b5bb',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -145,7 +145,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': 'ff027cee9d6d7a5ead772229d6c1538b66d243d8',
+  'pdfium_revision': '5a6d70c82d6a2b4617265b2e3d5cac339cd04246',
   # 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.
@@ -169,7 +169,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': 'af5947d13e6794eac489365ff58fd45c0dd4ca2a',
+  'nacl_revision': 'df9028d670fe6f66e56b74d27d65e1fa7a440569',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype
   # and whatever else without interference from each other.
@@ -181,7 +181,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': '6bd7a3c6d7ab1da47d9ae537f2e5dcc1f1f81451',
+  'catapult_revision': '7d95d86a652fb83e619f1861708d19f938bf32de',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -229,7 +229,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '7f57887e05f6da754880e19f4bf1232086f9a49a',
+  'spv_tools_revision': '5ec2d1a8cdafdcabbc081da58f847e3c0c6f77f2',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -245,7 +245,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': 'd23fdd3624d16665a68ab5d0af3efd61bff21260',
+  'dawn_revision': '292c0c31f25cf7c5c9adbdf04dd6be2adfa5e0b0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -679,7 +679,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '6641ba11c3d3c1bfa35b4f84363408fd593ac2e9',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b2c827c6440e0c07397673af44403c63423d32ed',
       'condition': 'checkout_linux',
   },
 
@@ -694,7 +694,7 @@
 
   # For Linux and Chromium OS.
   'src/third_party/cros_system_api': {
-      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '5b955bc9a56817c072582c41f9af5dab518bca7b',
+      'url': Var('chromium_git') + '/chromiumos/platform2/system_api.git' + '@' + '633fc031bece7e388014a17ebc006526f9d29081',
       'condition': 'checkout_linux',
   },
 
@@ -704,7 +704,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + 'f18aaf4f57453ecd2ab9983bf47d3d4f85ab0d35',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0a8ce8ee8b273bab0b36e5b0f9b981884813c247',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1036,7 +1036,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '8438dc662858c3a0cf117a3370f9d2f28c76b352',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'c041278576ce175bfe12688eddf6c6abf3405cae',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1196,7 +1196,7 @@
     Var('chromium_git') + '/external/selenium/py.git' + '@' + '5fd78261a75fe08d27ca4835fb6c5ce4b42275bd',
 
   'src/third_party/webgl/src':
-    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '5b6cbd789b9b91b4e46dde883c9f2ecb31eddade',
+    Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a2b35635aaef3e9301d69f77f9a0a3fd99291b08',
 
   'src/third_party/webrtc':
     Var('webrtc_git') + '/src.git' + '@' + '503da9435084305869cda5bfe861bcb103c93d71',
@@ -1230,7 +1230,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@dc2dbca012cd7b5d7756e01457b7b32b2c4d0eb8',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@61b9ca0657a3527fffb66c45d3d15a506593a095',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_feature_list_creator.cc b/android_webview/browser/aw_feature_list_creator.cc
index 3979e05..6af0f30 100644
--- a/android_webview/browser/aw_feature_list_creator.cc
+++ b/android_webview/browser/aw_feature_list_creator.cc
@@ -47,10 +47,11 @@
 // These prefs go in the JsonPrefStore, and will persist across runs. Other
 // prefs go in the InMemoryPrefStore, and will be lost when the process ends.
 const char* const kPersistentPrefsWhitelist[] = {
-    // Random seed value for variation's entropy providers, used to assign
+    // Random seed values for variation's entropy providers, used to assign
     // experiment groups.
     metrics::prefs::kMetricsLowEntropySource,
     // Used by CachingPermutedEntropyProvider to cache generated values.
+    // TODO(crbug/912368): Remove this.
     variations::prefs::kVariationsPermutedEntropyCache,
 };
 
@@ -156,9 +157,7 @@
 
   // Populate FieldTrialList. Since low_entropy_provider is null, it will fall
   // back to the provider we previously gave to FieldTrialList, which is a low
-  // entropy provider. We only want one low entropy provider, because multiple
-  // CachingPermutedEntropyProvider objects would all try to cache their values
-  // in the same pref store, overwriting each other's.
+  // entropy provider.
   variations_field_trial_creator_->SetupFieldTrials(
       cc::switches::kEnableGpuBenchmarking, switches::kEnableFeatures,
       switches::kDisableFeatures, unforceable_field_trials,
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn
index 63930be..54619ede 100644
--- a/ash/app_list/BUILD.gn
+++ b/ash/app_list/BUILD.gn
@@ -53,8 +53,6 @@
     "views/horizontal_page.h",
     "views/horizontal_page_container.cc",
     "views/horizontal_page_container.h",
-    "views/image_shadow_animator.cc",
-    "views/image_shadow_animator.h",
     "views/page_switcher.cc",
     "views/page_switcher.h",
     "views/pulsing_block_view.cc",
@@ -202,7 +200,6 @@
     "views/app_list_view_unittest.cc",
     "views/apps_grid_view_unittest.cc",
     "views/folder_header_view_unittest.cc",
-    "views/image_shadow_animator_unittest.cc",
     "views/search_box_view_unittest.cc",
     "views/search_result_answer_card_view_unittest.cc",
     "views/search_result_list_view_unittest.cc",
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 11417be6..c1bfb52 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -276,11 +276,7 @@
       icon, skia::ImageOperations::RESIZE_BEST,
       is_folder_ ? AppListConfig::instance().folder_unclipped_icon_size()
                  : AppListConfig::instance().grid_icon_size());
-
-  if (shadow_animator_)
-    shadow_animator_->SetOriginalImage(resized);
-  else
-    icon_->SetImage(resized);
+  icon_->SetImage(resized);
 
   if (icon_shadow_) {
     // Create a shadow for the shown icon.
@@ -516,15 +512,11 @@
 
 void AppListItemView::StateChanged(ButtonState old_state) {
   if (state() == STATE_HOVERED || state() == STATE_PRESSED) {
-    if (shadow_animator_)
-      shadow_animator_->animation()->Show();
     // Show the hover/tap highlight: for tap, lighter highlight replaces darker
     // keyboard selection; for mouse hover, keyboard selection takes precedence.
     if (!apps_grid_view_->IsSelectedView(this) || state() == STATE_PRESSED)
       SetItemIsHighlighted(true);
   } else {
-    if (shadow_animator_)
-      shadow_animator_->animation()->Hide();
     SetItemIsHighlighted(false);
     if (item_weak_)
       item_weak_->set_highlighted(false);
@@ -751,12 +743,6 @@
   return handled;
 }
 
-void AppListItemView::ImageShadowAnimationProgressed(
-    ImageShadowAnimator* animator) {
-  icon_->SetImage(animator->shadow_image());
-  Layout();
-}
-
 void AppListItemView::OnDraggedViewEnter() {
   CreateDraggedViewHoverAnimation();
   dragged_view_hover_animation_->Show();
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h
index 82302225..a1336cc 100644
--- a/ash/app_list/views/app_list_item_view.h
+++ b/ash/app_list/views/app_list_item_view.h
@@ -13,7 +13,6 @@
 #include "ash/app_list/app_list_export.h"
 #include "ash/app_list/model/app_list_item_observer.h"
 #include "ash/app_list/views/app_list_menu_model_adapter.h"
-#include "ash/app_list/views/image_shadow_animator.h"
 #include "ash/public/interfaces/menu.mojom.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -38,7 +37,6 @@
     : public views::Button,
       public views::ContextMenuController,
       public AppListItemObserver,
-      public ImageShadowAnimator::Delegate,
       public AppListMenuModelAdapter::Delegate {
  public:
   // Internal class name.
@@ -122,9 +120,6 @@
   bool GetTooltipText(const gfx::Point& p,
                       base::string16* tooltip) const override;
 
-  // ImageShadowAnimator::Delegate overrides:
-  void ImageShadowAnimationProgressed(ImageShadowAnimator* animator) override;
-
   // When a dragged view enters this view, a preview circle is shown for
   // non-folder item while the icon is enlarged for folder item. When a
   // dragged view exits this view, the reverse animation will be performed.
@@ -249,8 +244,6 @@
   // True if the drag host proxy is crated for mouse dragging.
   bool mouse_drag_proxy_created_ = false;
 
-  std::unique_ptr<ImageShadowAnimator> shadow_animator_;
-
   // The animation that runs when dragged view enters or exits this view.
   std::unique_ptr<gfx::SlideAnimation> dragged_view_hover_animation_;
 
diff --git a/ash/app_list/views/image_shadow_animator.cc b/ash/app_list/views/image_shadow_animator.cc
deleted file mode 100644
index 2f5832f..0000000
--- a/ash/app_list/views/image_shadow_animator.cc
+++ /dev/null
@@ -1,83 +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 "ash/app_list/views/image_shadow_animator.h"
-
-#include <stddef.h>
-
-#include "ui/gfx/animation/animation_delegate.h"
-#include "ui/gfx/animation/slide_animation.h"
-#include "ui/gfx/image/image_skia_operations.h"
-
-using gfx::Tween;
-
-namespace {
-
-// Tweens between two ShadowValues.
-gfx::ShadowValue LinearShadowValueBetween(double progress,
-                                          const gfx::ShadowValue& start,
-                                          const gfx::ShadowValue& end) {
-  gfx::Vector2d offset(
-      Tween::LinearIntValueBetween(progress, start.x(), end.x()),
-      Tween::LinearIntValueBetween(progress, start.y(), end.y()));
-
-  // The blur must be clamped to even values in order to avoid offsets being
-  // incorrect when there are uneven margins.
-  int blur =
-      Tween::LinearIntValueBetween(progress, start.blur() / 2, end.blur() / 2) *
-      2;
-
-  return gfx::ShadowValue(
-      offset, blur,
-      Tween::ColorValueBetween(progress, start.color(), end.color()));
-}
-
-}  // namespace
-
-namespace app_list {
-
-ImageShadowAnimator::ImageShadowAnimator(Delegate* delegate)
-    : delegate_(delegate), animation_(this) {}
-
-ImageShadowAnimator::~ImageShadowAnimator() = default;
-
-void ImageShadowAnimator::SetOriginalImage(const gfx::ImageSkia& image) {
-  original_image_ = image;
-  animation_.Reset();
-  UpdateShadowImageForProgress(0);
-}
-
-void ImageShadowAnimator::SetStartAndEndShadows(
-    const gfx::ShadowValues& start_shadow,
-    const gfx::ShadowValues& end_shadow) {
-  start_shadow_ = start_shadow;
-  end_shadow_ = end_shadow;
-}
-
-void ImageShadowAnimator::AnimationProgressed(const gfx::Animation* animation) {
-  UpdateShadowImageForProgress(animation->GetCurrentValue());
-}
-
-gfx::ShadowValues ImageShadowAnimator::GetShadowValuesForProgress(
-    double progress) const {
-  DCHECK_EQ(start_shadow_.size(), end_shadow_.size())
-      << "Only equally sized ShadowValues are supported";
-
-  gfx::ShadowValues shadows;
-  for (size_t i = 0; i < start_shadow_.size(); ++i) {
-    shadows.push_back(
-        LinearShadowValueBetween(progress, start_shadow_[i], end_shadow_[i]));
-  }
-  return shadows;
-}
-
-void ImageShadowAnimator::UpdateShadowImageForProgress(double progress) {
-  shadow_image_ = gfx::ImageSkiaOperations::CreateImageWithDropShadow(
-      original_image_, GetShadowValuesForProgress(progress));
-
-  if (delegate_)
-    delegate_->ImageShadowAnimationProgressed(this);
-}
-
-}  // namespace app_list
diff --git a/ash/app_list/views/image_shadow_animator.h b/ash/app_list/views/image_shadow_animator.h
deleted file mode 100644
index 49c5718e..0000000
--- a/ash/app_list/views/image_shadow_animator.h
+++ /dev/null
@@ -1,82 +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 ASH_APP_LIST_VIEWS_IMAGE_SHADOW_ANIMATOR_H_
-#define ASH_APP_LIST_VIEWS_IMAGE_SHADOW_ANIMATOR_H_
-
-#include "ash/app_list/app_list_export.h"
-#include "base/macros.h"
-#include "ui/gfx/animation/animation_delegate.h"
-#include "ui/gfx/animation/slide_animation.h"
-#include "ui/gfx/image/image_skia.h"
-#include "ui/gfx/shadow_value.h"
-
-namespace app_list {
-
-namespace test {
-class ImageShadowAnimatorTest;
-}  // namespace test
-
-// A helper class that animates an image's shadow between two shadow values.
-class APP_LIST_EXPORT ImageShadowAnimator : public gfx::AnimationDelegate {
- public:
-  class Delegate {
-   public:
-    // Called when |shadow_image_| is updated.
-    virtual void ImageShadowAnimationProgressed(
-        ImageShadowAnimator* animator) = 0;
-  };
-
-  explicit ImageShadowAnimator(Delegate* delegate);
-  ~ImageShadowAnimator() override;
-
-  // Sets the image that will have its shadow animated. Synchronously calls the
-  // Delegate's ImageShadowAnimationProgressed() method.
-  void SetOriginalImage(const gfx::ImageSkia& image);
-
-  // Sets the shadow values to animate between.
-  void SetStartAndEndShadows(const gfx::ShadowValues& start_shadow,
-                             const gfx::ShadowValues& end_shadow);
-
-  gfx::SlideAnimation* animation() { return &animation_; }
-
-  const gfx::ImageSkia& shadow_image() const { return shadow_image_; }
-
-  // Overridden from gfx::AnimationDelegate:
-  void AnimationProgressed(const gfx::Animation* animation) override;
-
- private:
-  friend test::ImageShadowAnimatorTest;
-
-  // Returns shadow values for a tween between |start_shadow_| and |end_shadow_|
-  // at |progress|.
-  gfx::ShadowValues GetShadowValuesForProgress(double progress) const;
-
-  // Updates |shadow_image_| and notifies the delegate.
-  void UpdateShadowImageForProgress(double progress);
-
-  Delegate* const delegate_;
-
-  // The image to paint a drop shadow for.
-  gfx::ImageSkia original_image_;
-
-  // The image with a drop shadow painted. This stays current with the progress
-  // of |animation_|.
-  gfx::ImageSkia shadow_image_;
-
-  // The animation that controls the progress of the shadow tween.
-  gfx::SlideAnimation animation_;
-
-  // The shadow value to tween from.
-  gfx::ShadowValues start_shadow_;
-
-  // The shadow value to tween to.
-  gfx::ShadowValues end_shadow_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImageShadowAnimator);
-};
-
-}  // namespace app_list
-
-#endif  // ASH_APP_LIST_VIEWS_IMAGE_SHADOW_ANIMATOR_H_
diff --git a/ash/app_list/views/image_shadow_animator_unittest.cc b/ash/app_list/views/image_shadow_animator_unittest.cc
deleted file mode 100644
index 8c68a80a..0000000
--- a/ash/app_list/views/image_shadow_animator_unittest.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ash/app_list/views/image_shadow_animator.h"
-
-#include "base/macros.h"
-#include "ui/views/test/views_test_base.h"
-
-namespace {
-
-bool ShadowsEqual(const gfx::ShadowValue& a, const gfx::ShadowValue& b) {
-  return a.blur() == b.blur() && a.color() == b.color() &&
-         a.offset() == b.offset();
-}
-
-}  // namespace
-
-namespace app_list {
-namespace test {
-
-class ImageShadowAnimatorTest : public views::ViewsTestBase,
-                                public ImageShadowAnimator::Delegate {
- public:
-  ImageShadowAnimatorTest()
-      : shadow_animator_(this), animation_updated_(false) {}
-  ~ImageShadowAnimatorTest() override {}
-
-  bool animation_updated() { return animation_updated_; }
-  void reset_animation_updated() { animation_updated_ = false; }
-  ImageShadowAnimator* shadow_animator() { return &shadow_animator_; }
-
-  // ImageShadowAnimator::Delegate overrides:
-  void ImageShadowAnimationProgressed(ImageShadowAnimator* animator) override {
-    animation_updated_ = true;
-  }
-
-  void UpdateShadowImageForProgress(double progress) {
-    shadow_animator_.UpdateShadowImageForProgress(progress);
-  }
-
-  gfx::ShadowValues GetShadowValuesForProgress(double progress) {
-    return shadow_animator_.GetShadowValuesForProgress(progress);
-  }
-
- private:
-  ImageShadowAnimator shadow_animator_;
-  bool animation_updated_;
-
-  DISALLOW_COPY_AND_ASSIGN(ImageShadowAnimatorTest);
-};
-
-TEST_F(ImageShadowAnimatorTest, TweenShadow) {
-  gfx::ShadowValues start;
-  start.push_back(gfx::ShadowValue(gfx::Vector2d(0, 1), 2,
-                                   SkColorSetA(SK_ColorBLACK, 0xA0)));
-  start.push_back(gfx::ShadowValue(gfx::Vector2d(0, 2), 4,
-                                   SkColorSetA(SK_ColorBLACK, 0x80)));
-
-  gfx::ShadowValues end;
-  end.push_back(gfx::ShadowValue(gfx::Vector2d(-2, 3), 4,
-                                 SkColorSetA(SK_ColorBLACK, 0xC0)));
-  end.push_back(gfx::ShadowValue(gfx::Vector2d(4, 4), 8,
-                                 SkColorSetA(SK_ColorBLACK, 0x60)));
-
-  shadow_animator()->SetStartAndEndShadows(start, end);
-
-  gfx::ShadowValues result_shadows = GetShadowValuesForProgress(0.5);
-
-  // Although the blur value of this shadow should be 3, it is snapped to an
-  // even value to prevent offset issues in clients.
-  EXPECT_TRUE(ShadowsEqual(gfx::ShadowValue(gfx::Vector2d(-1, 2), 4,
-                                            SkColorSetA(SK_ColorBLACK, 0xB0)),
-                           result_shadows[0]));
-
-  EXPECT_TRUE(ShadowsEqual(gfx::ShadowValue(gfx::Vector2d(2, 3), 6,
-                                            SkColorSetA(SK_ColorBLACK, 0x70)),
-                           result_shadows[1]));
-}
-
-TEST_F(ImageShadowAnimatorTest, ImageSize) {
-  gfx::ShadowValues start;
-  start.push_back(gfx::ShadowValue(gfx::Vector2d(0, 2), 2, 0xA0000000));
-
-  gfx::ShadowValues end;
-  end.push_back(gfx::ShadowValue(gfx::Vector2d(0, 8), 8, 0x60000000));
-
-  shadow_animator()->SetStartAndEndShadows(start, end);
-
-  EXPECT_FALSE(animation_updated());
-
-  SkBitmap bitmap;
-  bitmap.allocN32Pixels(8, 8);
-  bitmap.eraseColor(SK_ColorBLUE);
-  shadow_animator()->SetOriginalImage(
-      gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
-  // Setting the image should notify the delegate.
-  EXPECT_TRUE(animation_updated());
-
-  // Check the shadowed image grows as it animates, due to the increasing blur
-  // and vertical offset.
-  EXPECT_EQ(gfx::Size(10, 11), shadow_animator()->shadow_image().size());
-  UpdateShadowImageForProgress(0.5);
-  EXPECT_EQ(gfx::Size(14, 16), shadow_animator()->shadow_image().size());
-  UpdateShadowImageForProgress(1);
-  EXPECT_EQ(gfx::Size(16, 20), shadow_animator()->shadow_image().size());
-}
-
-}  // namespace test
-}  // namespace app_list
diff --git a/ash/app_list/views/search_box_view.cc b/ash/app_list/views/search_box_view.cc
index 8a9b8e6..1890a33 100644
--- a/ash/app_list/views/search_box_view.cc
+++ b/ash/app_list/views/search_box_view.cc
@@ -170,10 +170,10 @@
 
 void SearchBoxView::UpdateSearchIcon() {
   const gfx::VectorIcon& google_icon =
-      is_search_box_active() ? kIcGoogleColorIcon : kIcGoogleBlackIcon;
+      is_search_box_active() ? kGoogleColorIcon : kGoogleBlackIcon;
   const gfx::VectorIcon& icon = search_model_->search_engine_is_google()
                                     ? google_icon
-                                    : kIcSearchEngineNotGoogleIcon;
+                                    : kSearchEngineNotGoogleIcon;
   SetSearchIconImage(gfx::CreateVectorIcon(icon, search_box::kSearchIconSize,
                                            search_box_color()));
 }
diff --git a/ash/app_list/views/search_box_view_unittest.cc b/ash/app_list/views/search_box_view_unittest.cc
index 523ec55..6004142 100644
--- a/ash/app_list/views/search_box_view_unittest.cc
+++ b/ash/app_list/views/search_box_view_unittest.cc
@@ -218,7 +218,7 @@
   SetSearchEngineIsGoogle(true);
   SetSearchBoxActive(false, ui::ET_UNKNOWN);
   const gfx::ImageSkia expected_icon =
-      gfx::CreateVectorIcon(kIcGoogleBlackIcon, search_box::kSearchIconSize,
+      gfx::CreateVectorIcon(kGoogleBlackIcon, search_box::kSearchIconSize,
                             search_box::kDefaultSearchboxColor);
   view()->ModelChanged();
 
@@ -234,7 +234,7 @@
   SetSearchEngineIsGoogle(true);
   SetSearchBoxActive(true, ui::ET_MOUSE_PRESSED);
   const gfx::ImageSkia expected_icon =
-      gfx::CreateVectorIcon(kIcGoogleColorIcon, search_box::kSearchIconSize,
+      gfx::CreateVectorIcon(kGoogleColorIcon, search_box::kSearchIconSize,
                             search_box::kDefaultSearchboxColor);
   view()->ModelChanged();
 
@@ -250,7 +250,7 @@
   SetSearchEngineIsGoogle(false);
   SetSearchBoxActive(false, ui::ET_UNKNOWN);
   const gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
-      kIcSearchEngineNotGoogleIcon, search_box::kSearchIconSize,
+      kSearchEngineNotGoogleIcon, search_box::kSearchIconSize,
       search_box::kDefaultSearchboxColor);
   view()->ModelChanged();
 
@@ -266,7 +266,7 @@
   SetSearchEngineIsGoogle(false);
   SetSearchBoxActive(true, ui::ET_UNKNOWN);
   const gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
-      kIcSearchEngineNotGoogleIcon, search_box::kSearchIconSize,
+      kSearchEngineNotGoogleIcon, search_box::kSearchIconSize,
       search_box::kDefaultSearchboxColor);
   view()->ModelChanged();
 
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc
index 4fb773c..5496994 100644
--- a/ash/app_list/views/search_result_tile_item_view.cc
+++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -116,7 +116,7 @@
     rating_star_->set_can_process_events_within_subtree(false);
     rating_star_->SetVerticalAlignment(views::ImageView::LEADING);
     rating_star_->SetImage(gfx::CreateVectorIcon(
-        kIcBadgeRatingIcon, kSearchRatingStarSize, kSearchRatingStarColor));
+        kBadgeRatingIcon, kSearchRatingStarSize, kSearchRatingStarColor));
     rating_star_->SetVisible(false);
     AddChildView(rating_star_);
 
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 5c7457e..e9133ec 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -32,7 +32,7 @@
 
 constexpr int kPreferredWidth = 640;
 constexpr int kPreferredHeight = 48;
-constexpr int kIconLeftRightPadding = 19;
+constexpr int kIconLeftRightPadding = 18;
 constexpr int kTextTrailPadding = 16;
 // Extra margin at the right of the rightmost action icon.
 constexpr int kActionButtonRightMargin = 8;
diff --git a/ash/public/cpp/app_list/app_list_config.cc b/ash/public/cpp/app_list/app_list_config.cc
index e5b9405b..799f45b 100644
--- a/ash/public/cpp/app_list/app_list_config.cc
+++ b/ash/public/cpp/app_list/app_list_config.cc
@@ -26,7 +26,7 @@
       search_tile_icon_dimension_(48),
       search_tile_badge_icon_dimension_(22),
       search_tile_badge_icon_offset_(5),
-      search_list_icon_dimension_(18),
+      search_list_icon_dimension_(20),
       search_list_badge_icon_dimension_(14),
       suggestion_chip_icon_dimension_(16),
       app_title_max_line_height_(20),
diff --git a/ash/public/cpp/app_list/vector_icons/BUILD.gn b/ash/public/cpp/app_list/vector_icons/BUILD.gn
index f667bec..0b1625c 100644
--- a/ash/public/cpp/app_list/vector_icons/BUILD.gn
+++ b/ash/public/cpp/app_list/vector_icons/BUILD.gn
@@ -8,19 +8,19 @@
   icon_directory = "."
 
   icons = [
-    "ic_arrow_up.icon",
-    "ic_badge_instant.icon",
-    "ic_badge_play.icon",
-    "ic_badge_rating.icon",
-    "ic_bookmark.icon",
-    "ic_domain.icon",
-    "ic_equal.icon",
-    "ic_google_black.icon",
-    "ic_google_color.icon",
-    "ic_history.icon",
-    "ic_mic_black.icon",
-    "ic_search.icon",
-    "ic_search_engine_not_google.icon",
+    "arrow_up.icon",
+    "badge_instant.icon",
+    "badge_play.icon",
+    "badge_rating.icon",
+    "bookmark.icon",
+    "domain.icon",
+    "equal.icon",
+    "google_black.icon",
+    "google_color.icon",
+    "history.icon",
+    "mic_black.icon",
+    "search.icon",
+    "search_engine_not_google.icon",
   ]
 }
 
diff --git a/ash/public/cpp/app_list/vector_icons/ic_arrow_up.icon b/ash/public/cpp/app_list/vector_icons/arrow_up.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_arrow_up.icon
rename to ash/public/cpp/app_list/vector_icons/arrow_up.icon
diff --git a/ash/public/cpp/app_list/vector_icons/ic_badge_instant.icon b/ash/public/cpp/app_list/vector_icons/badge_instant.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_badge_instant.icon
rename to ash/public/cpp/app_list/vector_icons/badge_instant.icon
diff --git a/ash/public/cpp/app_list/vector_icons/ic_badge_play.icon b/ash/public/cpp/app_list/vector_icons/badge_play.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_badge_play.icon
rename to ash/public/cpp/app_list/vector_icons/badge_play.icon
diff --git a/ash/public/cpp/app_list/vector_icons/ic_badge_rating.icon b/ash/public/cpp/app_list/vector_icons/badge_rating.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_badge_rating.icon
rename to ash/public/cpp/app_list/vector_icons/badge_rating.icon
diff --git a/ash/public/cpp/app_list/vector_icons/bookmark.icon b/ash/public/cpp/app_list/vector_icons/bookmark.icon
new file mode 100644
index 0000000..2cf9d2e5
--- /dev/null
+++ b/ash/public/cpp/app_list/vector_icons/bookmark.icon
@@ -0,0 +1,16 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 10, 14.56f,
+R_LINE_TO, 4.64f, 2.95f,
+R_LINE_TO, -1.23f, -5.55f,
+LINE_TO, 17.5f, 8.22f,
+R_LINE_TO, -5.39f, -0.48f,
+LINE_TO, 10, 2.5f,
+LINE_TO, 7.89f, 7.73f,
+LINE_TO, 2.5f, 8.22f,
+LINE_TO, 6.6f, 11.95f,
+R_LINE_TO, -1.23f, 5.55f,
+CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/domain.icon b/ash/public/cpp/app_list/vector_icons/domain.icon
new file mode 100644
index 0000000..a0694b7a
--- /dev/null
+++ b/ash/public/cpp/app_list/vector_icons/domain.icon
@@ -0,0 +1,25 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 4, 3,
+R_H_LINE_TO, 7,
+R_LINE_TO, 5, 5,
+R_V_LINE_TO, 9,
+H_LINE_TO, 4,
+V_LINE_TO, 3,
+CLOSE,
+R_MOVE_TO, 5, 2,
+H_LINE_TO, 6,
+R_V_LINE_TO, 10,
+R_H_LINE_TO, 8,
+V_LINE_TO, 10,
+H_LINE_TO, 9,
+V_LINE_TO, 5,
+CLOSE,
+R_MOVE_TO, 5, 3,
+LINE_TO, 11, 5,
+R_V_LINE_TO, 3,
+R_H_LINE_TO, 3,
+CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/equal.icon b/ash/public/cpp/app_list/vector_icons/equal.icon
new file mode 100644
index 0000000..6dcdef32
--- /dev/null
+++ b/ash/public/cpp/app_list/vector_icons/equal.icon
@@ -0,0 +1,17 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 5, 7,
+R_H_LINE_TO, 10,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5,
+V_LINE_TO, 7,
+CLOSE,
+R_MOVE_TO, 0, 4,
+R_H_LINE_TO, 10,
+R_V_LINE_TO, 2,
+H_LINE_TO, 5,
+V_LINE_TO, 11,
+CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_google_black.icon b/ash/public/cpp/app_list/vector_icons/google_black.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_google_black.icon
rename to ash/public/cpp/app_list/vector_icons/google_black.icon
diff --git a/ash/public/cpp/app_list/vector_icons/ic_google_color.icon b/ash/public/cpp/app_list/vector_icons/google_color.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_google_color.icon
rename to ash/public/cpp/app_list/vector_icons/google_color.icon
diff --git a/ash/public/cpp/app_list/vector_icons/history.icon b/ash/public/cpp/app_list/vector_icons/history.icon
new file mode 100644
index 0000000..4e86525
--- /dev/null
+++ b/ash/public/cpp/app_list/vector_icons/history.icon
@@ -0,0 +1,27 @@
+// 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.
+
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 9.99f, 2,
+CUBIC_TO, 5.58f, 2, 2, 5.58f, 2, 10,
+R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 7.99f, 8,
+CUBIC_TO, 14.42f, 18, 18, 14.42f, 18, 10,
+R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8.01f, -8,
+CLOSE,
+MOVE_TO, 10, 16,
+R_CUBIC_TO, -3.31f, 0, -6, -2.68f, -6, -6,
+R_CUBIC_TO, 0, -3.32f, 2.69f, -6, 6, -6,
+R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
+R_CUBIC_TO, 0, 3.31f, -2.68f, 6, -6, 6,
+CLOSE,
+R_MOVE_TO, 3.5f, -3.5f,
+R_LINE_TO, -1.41f, 1.41f,
+R_LINE_TO, -3.06f, -2.99f,
+LINE_TO, 9, 6,
+R_H_LINE_TO, 1.95f,
+R_V_LINE_TO, 4,
+R_LINE_TO, 2.55f, 2.5f,
+CLOSE
+
diff --git a/ash/public/cpp/app_list/vector_icons/ic_bookmark.icon b/ash/public/cpp/app_list/vector_icons/ic_bookmark.icon
deleted file mode 100644
index 06fb9551f..0000000
--- a/ash/public/cpp/app_list/vector_icons/ic_bookmark.icon
+++ /dev/null
@@ -1,29 +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.
-
-CANVAS_DIMENSIONS, 36,
-MOVE_TO, 18, 26.5f,
-LINE_TO, 27.27f, 32,
-R_LINE_TO, -2.46f, -10.36f,
-LINE_TO, 33, 14.67f,
-R_LINE_TO, -10.78f, -0.9f,
-LINE_TO, 18, 4,
-R_LINE_TO, -4.21f, 9.77f,
-LINE_TO, 3, 14.67f,
-R_LINE_TO, 8.19f, 6.97f,
-LINE_TO, 8.73f, 32,
-CLOSE
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 9, 13.25f,
-LINE_TO, 13.33f, 16,
-R_LINE_TO, -1.15f, -5.18f,
-LINE_TO, 16, 7.34f,
-R_LINE_TO, -5.03f, -0.45f,
-LINE_TO, 9, 2,
-LINE_TO, 7.03f, 6.89f,
-LINE_TO, 2, 7.34f,
-R_LINE_TO, 3.82f, 3.49f,
-LINE_TO, 4.67f, 16,
-CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_domain.icon b/ash/public/cpp/app_list/vector_icons/ic_domain.icon
deleted file mode 100644
index 99bb5f5f..0000000
--- a/ash/public/cpp/app_list/vector_icons/ic_domain.icon
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 36,
-MOVE_TO, 7, 3,
-LINE_TO, 19.8f, 3,
-LINE_TO, 29, 13,
-LINE_TO, 29, 33,
-LINE_TO, 7, 33,
-LINE_TO, 7, 3,
-CLOSE,
-MOVE_TO, 17, 6,
-LINE_TO, 10, 6,
-LINE_TO, 10, 30,
-LINE_TO, 26, 30,
-LINE_TO, 26, 16,
-LINE_TO, 17, 16,
-LINE_TO, 17, 6,
-CLOSE,
-MOVE_TO, 26, 13,
-LINE_TO, 20, 6,
-LINE_TO, 20, 13,
-LINE_TO, 26, 13,
-CLOSE
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 3, 1,
-LINE_TO, 10, 1,
-LINE_TO, 15, 6,
-LINE_TO, 15, 17,
-LINE_TO, 3, 17,
-LINE_TO, 3, 1,
-CLOSE,
-MOVE_TO, 8, 3,
-LINE_TO, 5, 3,
-LINE_TO, 5, 15,
-LINE_TO, 13, 15,
-LINE_TO, 13, 8,
-LINE_TO, 8, 8,
-LINE_TO, 8, 3,
-CLOSE,
-MOVE_TO, 13, 6,
-LINE_TO, 10, 3,
-LINE_TO, 10, 6,
-LINE_TO, 13, 6,
-CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_equal.icon b/ash/public/cpp/app_list/vector_icons/ic_equal.icon
deleted file mode 100644
index fc3f825b..0000000
--- a/ash/public/cpp/app_list/vector_icons/ic_equal.icon
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 36,
-MOVE_TO, 9, 13,
-R_H_LINE_TO, 18,
-R_V_LINE_TO, 3,
-H_LINE_TO, 9,
-R_V_LINE_TO, -3,
-CLOSE,
-R_MOVE_TO, 0, 7,
-R_H_LINE_TO, 18,
-R_V_LINE_TO, 3,
-H_LINE_TO, 9,
-R_V_LINE_TO, -3,
-CLOSE
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 4, 6,
-R_H_LINE_TO, 10,
-R_V_LINE_TO, 2,
-H_LINE_TO, 4,
-V_LINE_TO, 6,
-CLOSE,
-R_MOVE_TO, 0, 4,
-R_H_LINE_TO, 10,
-R_V_LINE_TO, 2,
-H_LINE_TO, 4,
-R_V_LINE_TO, -2,
-CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_history.icon b/ash/public/cpp/app_list/vector_icons/ic_history.icon
deleted file mode 100644
index 3d3c604..0000000
--- a/ash/public/cpp/app_list/vector_icons/ic_history.icon
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 36,
-MOVE_TO, 17.99f, 3,
-CUBIC_TO, 26.28f, 3, 33, 9.72f, 33, 18,
-CUBIC_TO, 33, 26.28f, 26.28f, 33, 17.99f, 33,
-CUBIC_TO, 9.71f, 33, 3, 26.28f, 3, 18,
-CUBIC_TO, 3, 9.72f, 9.71f, 3, 17.99f, 3,
-CLOSE,
-MOVE_TO, 18, 30,
-CUBIC_TO, 24.63f, 30, 30, 24.63f, 30, 18,
-CUBIC_TO, 30, 11.37f, 24.63f, 6, 18, 6,
-CUBIC_TO, 11.37f, 6, 6, 11.37f, 6, 18,
-CUBIC_TO, 6, 24.63f, 11.37f, 30, 18, 30,
-CLOSE,
-MOVE_TO, 18.75f, 10.5f,
-LINE_TO, 18.75f, 18.38f,
-LINE_TO, 25.5f, 22.38f,
-LINE_TO, 24.38f, 24.23f,
-LINE_TO, 16.5f, 19.5f,
-LINE_TO, 16.5f, 10.5f,
-LINE_TO, 18.75f, 10.5f,
-CLOSE
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 8.99f, 1,
-CUBIC_TO, 13.42f, 1, 17, 4.58f, 17, 9,
-CUBIC_TO, 17, 13.42f, 13.42f, 17, 8.99f, 17,
-CUBIC_TO, 4.58f, 17, 1, 13.42f, 1, 9,
-CUBIC_TO, 1, 4.58f, 4.58f, 1, 8.99f, 1,
-CLOSE,
-MOVE_TO, 9, 15.4f,
-CUBIC_TO, 12.54f, 15.4f, 15.4f, 12.54f, 15.4f, 9,
-CUBIC_TO, 15.4f, 5.46f, 12.54f, 2.6f, 9, 2.6f,
-CUBIC_TO, 5.46f, 2.6f, 2.6f, 5.46f, 2.6f, 9,
-CUBIC_TO, 2.6f, 12.54f, 5.46f, 15.4f, 9, 15.4f,
-CLOSE,
-MOVE_TO, 9.4f, 5,
-LINE_TO, 9.4f, 9.2f,
-LINE_TO, 13, 11.34f,
-LINE_TO, 12.4f, 12.32f,
-LINE_TO, 8.2f, 9.8f,
-LINE_TO, 8.2f, 5,
-LINE_TO, 9.4f, 5,
-CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_search.icon b/ash/public/cpp/app_list/vector_icons/ic_search.icon
deleted file mode 100644
index d77c2ac..0000000
--- a/ash/public/cpp/app_list/vector_icons/ic_search.icon
+++ /dev/null
@@ -1,48 +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.
-
-CANVAS_DIMENSIONS, 36,
-MOVE_TO, 23.58f, 21.35f,
-LINE_TO, 22.41f, 21.35f,
-LINE_TO, 21.99f, 20.95f,
-CUBIC_TO, 23.45f, 19.26f, 24.33f, 17.06f, 24.33f, 14.66f,
-CUBIC_TO, 24.33f, 9.33f, 20, 5, 14.66f, 5,
-CUBIC_TO, 9.33f, 5, 5, 9.33f, 5, 14.66f,
-CUBIC_TO, 5, 20, 9.33f, 24.33f, 14.66f, 24.33f,
-CUBIC_TO, 17.06f, 24.33f, 19.26f, 23.45f, 20.95f, 21.99f,
-LINE_TO, 21.35f, 22.41f,
-LINE_TO, 21.35f, 23.58f,
-LINE_TO, 28.79f, 31,
-LINE_TO, 31, 28.79f,
-LINE_TO, 23.58f, 21.35f,
-LINE_TO, 23.58f, 21.35f,
-CLOSE,
-MOVE_TO, 14.66f, 21.35f,
-CUBIC_TO, 10.96f, 21.35f, 7.97f, 18.36f, 7.97f, 14.66f,
-CUBIC_TO, 7.97f, 10.96f, 10.96f, 7.97f, 14.66f, 7.97f,
-CUBIC_TO, 18.36f, 7.97f, 21.35f, 10.96f, 21.35f, 14.66f,
-CUBIC_TO, 21.35f, 18.36f, 18.36f, 21.35f, 14.66f, 21.35f,
-CLOSE
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 11.71f, 11.06f,
-LINE_TO, 11.46f, 10.82f,
-CUBIC_TO, 12.35f, 9.77f, 12.89f, 8.42f, 12.89f, 6.95f,
-CUBIC_TO, 12.89f, 3.66f, 10.23f, 1, 6.95f, 1,
-CUBIC_TO, 3.66f, 1, 1, 3.66f, 1, 6.95f,
-CUBIC_TO, 1, 10.23f, 3.66f, 12.89f, 6.95f, 12.89f,
-CUBIC_TO, 8.42f, 12.89f, 9.77f, 12.35f, 10.82f, 11.46f,
-LINE_TO, 11.06f, 11.71f,
-LINE_TO, 11.06f, 12.44f,
-LINE_TO, 15.64f, 17,
-LINE_TO, 17, 15.64f,
-LINE_TO, 12.44f, 11.06f,
-LINE_TO, 11.71f, 11.06f,
-CLOSE,
-MOVE_TO, 6.95f, 11.06f,
-CUBIC_TO, 4.67f, 11.06f, 2.83f, 9.22f, 2.83f, 6.95f,
-CUBIC_TO, 2.83f, 4.67f, 4.67f, 2.83f, 6.95f, 2.83f,
-CUBIC_TO, 9.22f, 2.83f, 11.06f, 4.67f, 11.06f, 6.95f,
-CUBIC_TO, 11.06f, 9.22f, 9.22f, 11.06f, 6.95f, 11.06f,
-CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_mic_black.icon b/ash/public/cpp/app_list/vector_icons/mic_black.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_mic_black.icon
rename to ash/public/cpp/app_list/vector_icons/mic_black.icon
diff --git a/ash/public/cpp/app_list/vector_icons/search.icon b/ash/public/cpp/app_list/vector_icons/search.icon
new file mode 100644
index 0000000..705bc65c
--- /dev/null
+++ b/ash/public/cpp/app_list/vector_icons/search.icon
@@ -0,0 +1,19 @@
+// 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.
+
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 17.49f, 16,
+R_LINE_TO, -3.73f, -3.73f,
+CUBIC_TO, 14.53f, 11.2f, 15, 9.91f, 15, 8.5f,
+ARC_TO, 6.5f, 6.5f, 0, 1, 0, 8.5f, 15,
+R_CUBIC_TO, 1.41f, 0, 2.7f, -0.47f, 3.77f, -1.24f,
+LINE_TO, 16, 17.49f,
+LINE_TO, 17.49f, 16,
+CLOSE,
+MOVE_TO, 4, 8.5f,
+CUBIC_TO, 4, 6.01f, 6.01f, 4, 8.5f, 4,
+CUBIC_TO_SHORTHAND, 13, 6.01f, 13, 8.5f,
+CUBIC_TO_SHORTHAND, 10.99f, 13, 8.5f, 13,
+CUBIC_TO_SHORTHAND, 4, 10.99f, 4, 8.5f,
+CLOSE
diff --git a/ash/public/cpp/app_list/vector_icons/ic_search_engine_not_google.icon b/ash/public/cpp/app_list/vector_icons/search_engine_not_google.icon
similarity index 100%
rename from ash/public/cpp/app_list/vector_icons/ic_search_engine_not_google.icon
rename to ash/public/cpp/app_list/vector_icons/search_engine_not_google.icon
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 6a8aa48..d156267 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -40,16 +40,6 @@
     "network_badge_off.icon",
     "network_badge_roaming.icon",
     "network_badge_secure.icon",
-    "network_badge_technology_1x.icon",
-    "network_badge_technology_3g.icon",
-    "network_badge_technology_4g.icon",
-    "network_badge_technology_edge.icon",
-    "network_badge_technology_evdo.icon",
-    "network_badge_technology_gprs.icon",
-    "network_badge_technology_hspa.icon",
-    "network_badge_technology_hspa_plus.icon",
-    "network_badge_technology_lte.icon",
-    "network_badge_technology_lte_advanced.icon",
     "network_badge_vpn.icon",
     "network_ethernet.icon",
     "network_mobile_not_connected_x.icon",
diff --git a/ash/resources/vector_icons/network_badge_technology_1x.icon b/ash/resources/vector_icons/network_badge_technology_1x.icon
deleted file mode 100644
index 1b64bb1..0000000
--- a/ash/resources/vector_icons/network_badge_technology_1x.icon
+++ /dev/null
@@ -1,83 +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.
-
-CANVAS_DIMENSIONS, 12,
-MOVE_TO, 0, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 10,
-H_LINE_TO, 2,
-V_LINE_TO, 4,
-H_LINE_TO, 0,
-MOVE_TO, 6, 4,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 6,
-V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 2, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 8,
-V_LINE_TO, 6,
-CLOSE,
-MOVE_TO, 6, 8,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 6,
-V_LINE_TO, 8,
-CLOSE,
-R_MOVE_TO, 4, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -2,
-V_LINE_TO, 8,
-CLOSE,
-R_MOVE_TO, 0, -4,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -2,
-V_LINE_TO, 4,
-CLOSE
-
-CANVAS_DIMENSIONS, 6,
-MOVE_TO, 0, 1,
-R_H_LINE_TO, 1,
-V_LINE_TO, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 5,
-H_LINE_TO, 1,
-V_LINE_TO, 2,
-H_LINE_TO, 0,
-MOVE_TO, 3, 2,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 3,
-V_LINE_TO, 2,
-CLOSE,
-R_MOVE_TO, 1, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 4,
-V_LINE_TO, 3,
-CLOSE,
-MOVE_TO, 3, 4,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 3,
-V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 2, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 5,
-V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 0, -2,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 5,
-V_LINE_TO, 2,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_3g.icon b/ash/resources/vector_icons/network_badge_technology_3g.icon
deleted file mode 100644
index 2d71a3c..0000000
--- a/ash/resources/vector_icons/network_badge_technology_3g.icon
+++ /dev/null
@@ -1,63 +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.
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 18, 0,
-R_H_LINE_TO, -8,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 8,
-V_LINE_TO, 4,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -4,
-V_LINE_TO, 2,
-R_H_LINE_TO, 6,
-MOVE_TO, 6, 6,
-R_V_LINE_TO, 2,
-H_LINE_TO, 0,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 8,
-V_LINE_TO, 0,
-H_LINE_TO, 0,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 6,
-R_V_LINE_TO, 2,
-H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 4,
-CLOSE
-
-CANVAS_DIMENSIONS, 9,
-MOVE_TO, 9, 0,
-H_LINE_TO, 5,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 4,
-V_LINE_TO, 2,
-H_LINE_TO, 7,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 6,
-V_LINE_TO, 1,
-R_H_LINE_TO, 3,
-MOVE_TO, 3, 3,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 1,
-V_LINE_TO, 0,
-H_LINE_TO, 0,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 3,
-R_V_LINE_TO, 1,
-H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 2,
-CLOSE,
-MOVE_TO, 0, 4,
-R_H_LINE_TO, 3,
-R_V_LINE_TO, 1,
-H_LINE_TO, 0,
-V_LINE_TO, 4,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_4g.icon b/ash/resources/vector_icons/network_badge_technology_4g.icon
deleted file mode 100644
index 77c262b..0000000
--- a/ash/resources/vector_icons/network_badge_technology_4g.icon
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 6, 8,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-H_LINE_TO, 6,
-R_V_LINE_TO, 6,
-H_LINE_TO, 0,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 6,
-CLOSE,
-MOVE_TO, 0, 4,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 0,
-V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 2, -2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 2,
-V_LINE_TO, 2,
-CLOSE,
-R_MOVE_TO, 2, -2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 4,
-V_LINE_TO, 0,
-CLOSE,
-MOVE_TO, 18, 0,
-R_H_LINE_TO, -8,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 8,
-V_LINE_TO, 4,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -4,
-V_LINE_TO, 2,
-R_H_LINE_TO, 6,
-CLOSE
-
-CANVAS_DIMENSIONS, 9,
-MOVE_TO, 3, 4,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-V_LINE_TO, 0,
-H_LINE_TO, 3,
-R_V_LINE_TO, 3,
-H_LINE_TO, 0,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 3,
-CLOSE,
-MOVE_TO, 0, 2,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 0,
-V_LINE_TO, 2,
-CLOSE,
-R_MOVE_TO, 1, -1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 1,
-V_LINE_TO, 1,
-CLOSE,
-R_MOVE_TO, 1, -1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 2,
-V_LINE_TO, 0,
-CLOSE,
-MOVE_TO, 9, 0,
-H_LINE_TO, 5,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 4,
-V_LINE_TO, 2,
-H_LINE_TO, 7,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 6,
-V_LINE_TO, 1,
-R_H_LINE_TO, 3,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_edge.icon b/ash/resources/vector_icons/network_badge_technology_edge.icon
deleted file mode 100644
index 5e7b578..0000000
--- a/ash/resources/vector_icons/network_badge_technology_edge.icon
+++ /dev/null
@@ -1,33 +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.
-
-CANVAS_DIMENSIONS, 10,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 6,
-V_LINE_TO, 8,
-H_LINE_TO, 2,
-V_LINE_TO, 6,
-R_H_LINE_TO, 2,
-V_LINE_TO, 4,
-H_LINE_TO, 2,
-V_LINE_TO, 2,
-R_H_LINE_TO, 4,
-V_LINE_TO, 0,
-CLOSE
-
-CANVAS_DIMENSIONS, 5,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 4,
-H_LINE_TO, 1,
-V_LINE_TO, 3,
-R_H_LINE_TO, 1,
-V_LINE_TO, 2,
-H_LINE_TO, 1,
-V_LINE_TO, 1,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_evdo.icon b/ash/resources/vector_icons/network_badge_technology_evdo.icon
deleted file mode 100644
index e87d6f2..0000000
--- a/ash/resources/vector_icons/network_badge_technology_evdo.icon
+++ /dev/null
@@ -1,91 +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.
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 6,
-V_LINE_TO, 8,
-H_LINE_TO, 2,
-V_LINE_TO, 6,
-R_H_LINE_TO, 2,
-V_LINE_TO, 4,
-H_LINE_TO, 2,
-V_LINE_TO, 2,
-R_H_LINE_TO, 4,
-V_LINE_TO, 0,
-MOVE_TO, 8, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-H_LINE_TO, 8,
-V_LINE_TO, 0,
-CLOSE,
-R_MOVE_TO, 2, 4,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 4, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 4,
-CLOSE,
-R_MOVE_TO, 2, -4,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 0,
-CLOSE,
-R_MOVE_TO, -4, 8,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -2,
-V_LINE_TO, 8,
-CLOSE
-
-CANVAS_DIMENSIONS, 9,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 4,
-H_LINE_TO, 1,
-V_LINE_TO, 3,
-R_H_LINE_TO, 1,
-V_LINE_TO, 2,
-H_LINE_TO, 1,
-V_LINE_TO, 1,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-MOVE_TO, 4, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-H_LINE_TO, 4,
-V_LINE_TO, 0,
-CLOSE,
-R_MOVE_TO, 1, 2,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-H_LINE_TO, 5,
-V_LINE_TO, 2,
-CLOSE,
-R_MOVE_TO, 2, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-H_LINE_TO, 7,
-V_LINE_TO, 2,
-CLOSE,
-R_MOVE_TO, 1, -2,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-H_LINE_TO, 8,
-V_LINE_TO, 0,
-CLOSE,
-MOVE_TO, 6, 4,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 6,
-V_LINE_TO, 4,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_gprs.icon b/ash/resources/vector_icons/network_badge_technology_gprs.icon
deleted file mode 100644
index 29ba4ea8..0000000
--- a/ash/resources/vector_icons/network_badge_technology_gprs.icon
+++ /dev/null
@@ -1,33 +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.
-
-CANVAS_DIMENSIONS, 10,
-MOVE_TO, 8, 0,
-H_LINE_TO, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 8,
-V_LINE_TO, 4,
-H_LINE_TO, 4,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-H_LINE_TO, 2,
-V_LINE_TO, 2,
-R_H_LINE_TO, 6,
-CLOSE
-
-CANVAS_DIMENSIONS, 5,
-MOVE_TO, 4, 0,
-H_LINE_TO, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 4,
-V_LINE_TO, 2,
-H_LINE_TO, 2,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-H_LINE_TO, 1,
-V_LINE_TO, 1,
-R_H_LINE_TO, 3,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_hspa.icon b/ash/resources/vector_icons/network_badge_technology_hspa.icon
deleted file mode 100644
index 7bedb290..0000000
--- a/ash/resources/vector_icons/network_badge_technology_hspa.icon
+++ /dev/null
@@ -1,33 +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.
-
-CANVAS_DIMENSIONS, 10,
-MOVE_TO, 0, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, 4,
-V_LINE_TO, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 10,
-H_LINE_TO, 6,
-V_LINE_TO, 6,
-H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-H_LINE_TO, 0,
-CLOSE
-
-CANVAS_DIMENSIONS, 5,
-MOVE_TO, 0, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 5,
-H_LINE_TO, 3,
-V_LINE_TO, 3,
-H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-H_LINE_TO, 0,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon b/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon
deleted file mode 100644
index 7e66d873..0000000
--- a/ash/resources/vector_icons/network_badge_technology_hspa_plus.icon
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-CANVAS_DIMENSIONS, 18,
-MOVE_TO, 13, 0,
-R_V_LINE_TO, 3,
-R_H_LINE_TO, -3,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 3,
-R_V_LINE_TO, 3,
-R_H_LINE_TO, 2,
-V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 3,
-R_H_LINE_TO, -3,
-V_LINE_TO, 0,
-MOVE_TO, 0, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-R_H_LINE_TO, 4,
-V_LINE_TO, 0,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 10,
-H_LINE_TO, 6,
-V_LINE_TO, 6,
-H_LINE_TO, 2,
-R_V_LINE_TO, 4,
-H_LINE_TO, 0,
-CLOSE
-
-CANVAS_DIMENSIONS, 9,
-MOVE_TO, 0, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 5,
-H_LINE_TO, 3,
-V_LINE_TO, 3,
-H_LINE_TO, 1,
-R_V_LINE_TO, 2,
-H_LINE_TO, 0,
-MOVE_TO, 7, 1,
-V_LINE_TO, 0,
-H_LINE_TO, 6,
-R_V_LINE_TO, 1,
-H_LINE_TO, 5,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-V_LINE_TO, 2,
-R_H_LINE_TO, 1,
-V_LINE_TO, 1,
-H_LINE_TO, 7,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_lte.icon b/ash/resources/vector_icons/network_badge_technology_lte.icon
deleted file mode 100644
index eefefe74e..0000000
--- a/ash/resources/vector_icons/network_badge_technology_lte.icon
+++ /dev/null
@@ -1,61 +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.
-
-CANVAS_DIMENSIONS, 24,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 6,
-V_LINE_TO, 8,
-H_LINE_TO, 2,
-V_LINE_TO, 0,
-MOVE_TO, 6, 0,
-R_H_LINE_TO, 10,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 8,
-R_H_LINE_TO, -2,
-V_LINE_TO, 2,
-H_LINE_TO, 6,
-MOVE_TO, 18, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 6,
-V_LINE_TO, 8,
-R_H_LINE_TO, -4,
-V_LINE_TO, 6,
-R_H_LINE_TO, 2,
-V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 2,
-R_H_LINE_TO, 4,
-V_LINE_TO, 0,
-CLOSE
-
-CANVAS_DIMENSIONS, 12,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 4,
-H_LINE_TO, 1,
-V_LINE_TO, 0,
-MOVE_TO, 3, 0,
-R_H_LINE_TO, 5,
-R_V_LINE_TO, 1,
-H_LINE_TO, 6,
-R_V_LINE_TO, 4,
-H_LINE_TO, 5,
-V_LINE_TO, 1,
-H_LINE_TO, 3,
-MOVE_TO, 9, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 3,
-R_H_LINE_TO, 1,
-V_LINE_TO, 2,
-R_H_LINE_TO, -1,
-V_LINE_TO, 1,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-CLOSE
diff --git a/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon b/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon
deleted file mode 100644
index 720d622..0000000
--- a/ash/resources/vector_icons/network_badge_technology_lte_advanced.icon
+++ /dev/null
@@ -1,86 +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.
-
-CANVAS_DIMENSIONS, 34,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 6,
-V_LINE_TO, 8,
-H_LINE_TO, 2,
-V_LINE_TO, 0,
-MOVE_TO, 6, 0,
-R_H_LINE_TO, 10,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, -4,
-R_V_LINE_TO, 8,
-R_H_LINE_TO, -2,
-V_LINE_TO, 2,
-H_LINE_TO, 6,
-MOVE_TO, 18, 0,
-R_V_LINE_TO, 10,
-R_H_LINE_TO, 6,
-V_LINE_TO, 8,
-R_H_LINE_TO, -4,
-V_LINE_TO, 6,
-R_H_LINE_TO, 2,
-V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 2,
-R_H_LINE_TO, 4,
-V_LINE_TO, 0,
-MOVE_TO, 29, 0,
-R_V_LINE_TO, 3,
-R_H_LINE_TO, -3,
-R_V_LINE_TO, 2,
-R_H_LINE_TO, 3,
-R_V_LINE_TO, 3,
-R_H_LINE_TO, 2,
-V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 3,
-R_H_LINE_TO, -3,
-V_LINE_TO, 0,
-CLOSE
-
-CANVAS_DIMENSIONS, 17,
-MOVE_TO, 0, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 4,
-H_LINE_TO, 1,
-V_LINE_TO, 0,
-MOVE_TO, 3, 0,
-R_H_LINE_TO, 5,
-R_V_LINE_TO, 1,
-H_LINE_TO, 6,
-R_V_LINE_TO, 4,
-H_LINE_TO, 5,
-V_LINE_TO, 1,
-H_LINE_TO, 3,
-MOVE_TO, 9, 0,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 3,
-V_LINE_TO, 4,
-R_H_LINE_TO, -2,
-V_LINE_TO, 3,
-R_H_LINE_TO, 1,
-V_LINE_TO, 2,
-R_H_LINE_TO, -1,
-V_LINE_TO, 1,
-R_H_LINE_TO, 2,
-V_LINE_TO, 0,
-MOVE_TO, 15, 1,
-V_LINE_TO, 0,
-R_H_LINE_TO, -1,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, -1,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, 1,
-V_LINE_TO, 2,
-R_H_LINE_TO, 1,
-V_LINE_TO, 1,
-R_H_LINE_TO, -1,
-CLOSE
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc
index ae0f6c6..c70e4eba 100644
--- a/ash/system/network/network_icon.cc
+++ b/ash/system/network/network_icon.cc
@@ -85,9 +85,6 @@
   // Cached strength index of the network when the icon was last generated.
   int strength_index_;
 
-  // Cached technology badge for the network when the icon was last generated.
-  Badge technology_badge_ = {};
-
   // Cached vpn badge for the network when the icon was last generated.
   Badge vpn_badge_ = {};
 
@@ -304,35 +301,6 @@
   return zero_based_index + 1;
 }
 
-Badge BadgeForNetworkTechnology(const NetworkState* network,
-                                IconType icon_type) {
-  Badge badge = {nullptr, GetDefaultColorForIconType(icon_type)};
-  const std::string& technology = network->network_technology();
-  if (technology == shill::kNetworkTechnologyEvdo) {
-    badge.icon = &kNetworkBadgeTechnologyEvdoIcon;
-  } else if (technology == shill::kNetworkTechnology1Xrtt) {
-    badge.icon = &kNetworkBadgeTechnology1xIcon;
-  } else if (technology == shill::kNetworkTechnologyGprs ||
-             technology == shill::kNetworkTechnologyGsm) {
-    badge.icon = &kNetworkBadgeTechnologyGprsIcon;
-  } else if (technology == shill::kNetworkTechnologyEdge) {
-    badge.icon = &kNetworkBadgeTechnologyEdgeIcon;
-  } else if (technology == shill::kNetworkTechnologyUmts) {
-    badge.icon = &kNetworkBadgeTechnology3gIcon;
-  } else if (technology == shill::kNetworkTechnologyHspa) {
-    badge.icon = &kNetworkBadgeTechnologyHspaIcon;
-  } else if (technology == shill::kNetworkTechnologyHspaPlus) {
-    badge.icon = &kNetworkBadgeTechnologyHspaPlusIcon;
-  } else if (technology == shill::kNetworkTechnologyLte) {
-    badge.icon = &kNetworkBadgeTechnologyLteIcon;
-  } else if (technology == shill::kNetworkTechnologyLteAdvanced) {
-    badge.icon = &kNetworkBadgeTechnologyLteAdvancedIcon;
-  } else {
-    return {};
-  }
-  return badge;
-}
-
 gfx::ImageSkia GetIcon(const NetworkState* network,
                        IconType icon_type,
                        int strength_index) {
@@ -434,11 +402,6 @@
 
 bool NetworkIconImpl::UpdateCellularState(const NetworkState* network) {
   bool dirty = false;
-  const Badge technology_badge = BadgeForNetworkTechnology(network, icon_type_);
-  if (technology_badge != technology_badge_) {
-    technology_badge_ = technology_badge;
-    dirty = true;
-  }
   std::string roaming_state = network->roaming();
   if (roaming_state != roaming_state_) {
     roaming_state_ = roaming_state;
@@ -488,10 +451,7 @@
         !IsTrayIcon(icon_type_)) {
       badges->bottom_right = {&kUnifiedNetworkBadgeSecureIcon, icon_color};
     }
-  } else if (type == shill::kTypeWimax) {
-    technology_badge_ = {&kNetworkBadgeTechnology4gIcon, icon_color};
   } else if (type == shill::kTypeCellular) {
-    // technology_badge_ is set in UpdateCellularState.
     if (network->IsConnectedState() &&
         network->roaming() == shill::kRoamingStateRoaming) {
       // For networks that are always in roaming don't show roaming badge.
@@ -505,9 +465,8 @@
       }
     }
   }
-  // Only show technology, VPN, and captive portal badges when connected.
+  // Only show VPN, and captive portal badges when connected.
   if (network->IsConnectedState()) {
-    badges->top_left = technology_badge_;
     badges->bottom_left = vpn_badge_;
     if (behind_captive_portal_)
       badges->bottom_right = {&kUnifiedNetworkBadgeCaptivePortalIcon,
diff --git a/base/allocator/allocator_shim_unittest.cc b/base/allocator/allocator_shim_unittest.cc
index 0e1195da..bdfcc77 100644
--- a/base/allocator/allocator_shim_unittest.cc
+++ b/base/allocator/allocator_shim_unittest.cc
@@ -533,25 +533,39 @@
 TEST_F(AllocatorShimTest, ShimReplacesCRTHeapWhenEnabled) {
   ASSERT_NE(::GetProcessHeap(), reinterpret_cast<HANDLE>(_get_heap_handle()));
 }
+#endif  // defined(OS_WIN) && BUILDFLAG(USE_ALLOCATOR_SHIM)
 
-TEST_F(AllocatorShimTest, ShimReplacesMsizeWhenEnabled) {
+#if defined(OS_WIN)
+static size_t GetAllocatedSize(void* ptr) {
+  return _msize(ptr);
+}
+#elif defined(OS_MACOSX)
+static size_t GetAllocatedSize(void* ptr) {
+  return malloc_size(ptr);
+}
+#else
+#define NO_MALLOC_SIZE
+#endif
+
+#if !defined(NO_MALLOC_SIZE) && BUILDFLAG(USE_ALLOCATOR_SHIM)
+TEST_F(AllocatorShimTest, ShimReplacesMallocSizeWhenEnabled) {
   InsertAllocatorDispatch(&g_mock_dispatch);
-  EXPECT_EQ(_msize(kTestSizeEstimateAddress), kTestSizeEstimate);
+  EXPECT_EQ(GetAllocatedSize(kTestSizeEstimateAddress), kTestSizeEstimate);
   RemoveAllocatorDispatchForTesting(&g_mock_dispatch);
 }
 
-TEST_F(AllocatorShimTest, ShimDoesntChangeMsizeWhenEnabled) {
+TEST_F(AllocatorShimTest, ShimDoesntChangeMallocSizeWhenEnabled) {
   void* alloc = malloc(16);
-  size_t sz = _msize(alloc);
+  size_t sz = GetAllocatedSize(alloc);
   EXPECT_GE(sz, 16U);
 
   InsertAllocatorDispatch(&g_mock_dispatch);
-  EXPECT_EQ(_msize(alloc), sz);
+  EXPECT_EQ(GetAllocatedSize(alloc), sz);
   RemoveAllocatorDispatchForTesting(&g_mock_dispatch);
 
   free(alloc);
 }
-#endif  // defined(OS_WIN) && BUILDFLAG(USE_ALLOCATOR_SHIM)
+#endif  // !defined(NO_MALLOC_SIZE) && BUILDFLAG(USE_ALLOCATOR_SHIM)
 
 }  // namespace
 }  // namespace allocator
diff --git a/base/android/jni_generator/BUILD.gn b/base/android/jni_generator/BUILD.gn
index 2ef6386..f312977 100644
--- a/base/android/jni_generator/BUILD.gn
+++ b/base/android/jni_generator/BUILD.gn
@@ -87,7 +87,7 @@
   sources = [
     "ProcessorArgs.template",
   ]
-  defines = [ "IS_JAVA_DEBUG_VALUE=$is_java_debug" ]
+  defines = [ "HASH_JNI_NAMES_VALUE=$use_hashed_jni_names" ]
 }
 
 java_annotation_processor("jni_processor") {
diff --git a/base/android/jni_generator/ProcessorArgs.template b/base/android/jni_generator/ProcessorArgs.template
index bbd4c4b..44b24abe 100644
--- a/base/android/jni_generator/ProcessorArgs.template
+++ b/base/android/jni_generator/ProcessorArgs.template
@@ -5,5 +5,5 @@
 package org.chromium.jni_generator;
 
 class ProcessorArgs {
-    public static final boolean IS_JAVA_DEBUG = IS_JAVA_DEBUG_VALUE;
+    public static final boolean HASH_JNI_NAMES = HASH_JNI_NAMES_VALUE;
 }
diff --git a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
index 01ce5b9..f2d27fd 100644
--- a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
+++ b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
@@ -71,22 +71,12 @@
     static final String NATIVE_TEST_FIELD_NAME = "TESTING_ENABLED";
     static final String NATIVE_REQUIRE_MOCK_FIELD_NAME = "REQUIRE_MOCK";
 
-    // Lets mocks of the Native impl to be set.
-    static final boolean TESTING_ENABLED = false;
-
-    // If true, throw an exception if no mock is provided.
-    private static final boolean REQUIRE_MOCK = false;
-
     // Builder for NativeClass which will hold all our native method declarations.
     private TypeSpec.Builder mNativesBuilder;
 
     // Hash function for native method names.
     private static MessageDigest sNativeMethodHashFunction;
 
-    // If true, native methods in GEN_JNI will be named as a hash of their descriptor.
-    private static final boolean USE_HASH_FOR_METHODS = !ProcessorArgs.IS_JAVA_DEBUG;
-    private static final boolean USE_SHORTENED_NATIVE_CLASS = !ProcessorArgs.IS_JAVA_DEBUG;
-
     // Limits the number characters of the Base64 encoded hash
     // of the method descriptor used as name of the generated
     // native method in GEN_JNI (prefixed with "M")
@@ -113,7 +103,7 @@
 
     public JniProcessor() {
         // If non-debug we use shorter names to save space.
-        if (USE_SHORTENED_NATIVE_CLASS) {
+        if (ProcessorArgs.HASH_JNI_NAMES) {
             // J.N
             mNativeClassPackage = "J";
             mNativeClassStr = "N";
@@ -127,14 +117,6 @@
                 FieldSpec.builder(TypeName.BOOLEAN, NATIVE_REQUIRE_MOCK_FIELD_NAME)
                         .addModifiers(Modifier.STATIC, Modifier.PUBLIC);
 
-        // Initialize only if true to avoid NoRedundantFieldInit.
-        if (TESTING_ENABLED) {
-            testingFlagBuilder.initializer("true");
-        }
-        if (REQUIRE_MOCK) {
-            throwFlagBuilder.initializer("true");
-        }
-
         // State of mNativesBuilder needs to be preserved between processing rounds.
         mNativesBuilder = TypeSpec.classBuilder(mNativeClassName)
                                   .addAnnotation(createGeneratedAnnotation())
@@ -255,7 +237,7 @@
         String descriptor = String.format("%s.%s.%s", packageName, className, oldMethodName)
                                     .replaceAll("_", "_1")
                                     .replaceAll("\\.", "_");
-        if (USE_HASH_FOR_METHODS) {
+        if (ProcessorArgs.HASH_JNI_NAMES) {
             // Must start with a character.
             byte[] hash = sNativeMethodHashFunction.digest(descriptor.getBytes(Charsets.UTF_8));
 
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 95f646f..1aaf644 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -460,10 +460,11 @@
   // |randomization_seed| value (other than 0) should never be the same for two
   // trials, else this would result in correlated group assignments.  Note:
   // Using a custom randomization seed is only supported by the
-  // PermutedEntropyProvider (which is used when UMA is not enabled). If
-  // |override_entropy_provider| is not null, then it will be used for
-  // randomization instead of the provider given when the FieldTrialList was
-  // instantiated.
+  // NormalizedMurmurHashEntropyProvider, which is used when UMA is not enabled
+  // (and is always used in Android WebView, where UMA is enabled
+  // asyncronously). If |override_entropy_provider| is not null, then it will be
+  // used for randomization instead of the provider given when the
+  // FieldTrialList was instantiated.
   static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
       const std::string& trial_name,
       FieldTrial::Probability total_probability,
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 7b71b9db..dff4525 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -264,9 +264,8 @@
   // Joining another thread may block the current thread for a long time, since
   // the thread referred to by |thread_handle| may still be running long-lived /
   // blocking tasks.
-  // TODO(https://crbug.com/707362): Make this a
-  // ScopedBlockingCallWithBaseSyncPrimitives.
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+  base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+      base::BlockingType::MAY_BLOCK);
   CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr));
 }
 
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
index f6c63ac..67618d30 100644
--- a/base/threading/platform_thread_win.cc
+++ b/base/threading/platform_thread_win.cc
@@ -274,9 +274,8 @@
   // Record the event that this thread is blocking upon (for hang diagnosis).
   base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle);
 
-  // TODO(https://crbug.com/707362): Make this a
-  // ScopedBlockingCallWithBaseSyncPrimitives.
-  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
+  base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
+      base::BlockingType::MAY_BLOCK);
 
   // Wait for the thread to exit.  It should already have terminated but make
   // sure this assumption is valid.
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
index d4f6c94..591c420 100644
--- a/base/threading/thread_restrictions.h
+++ b/base/threading/thread_restrictions.h
@@ -96,8 +96,9 @@
 
 class BrowserProcessImpl;
 class HistogramSynchronizer;
-class NativeBackendKWallet;
 class KeyStorageLinux;
+class NativeBackendKWallet;
+class StartupTimeBomb;
 
 namespace android_webview {
 class AwFormDatabaseService;
@@ -132,10 +133,11 @@
 class CategorizedWorkerPool;
 class GpuProcessTransportFactory;
 class NestedMessagePumpAndroid;
+class SandboxHostLinux;
 class ScopedAllowWaitForDebugURL;
+class ServiceWorkerSubresourceLoader;
 class SessionStorageDatabase;
 class SoftwareOutputDeviceMus;
-class ServiceWorkerSubresourceLoader;
 class SynchronousCompositor;
 class SynchronousCompositorHost;
 class SynchronousCompositorSyncCallBridge;
@@ -175,6 +177,9 @@
 class ScopedIPCSupport;
 }
 }
+namespace printing {
+class PrinterQuery;
+}
 namespace rlz_lib {
 class FinancialPing;
 }
@@ -186,7 +191,9 @@
 }
 namespace net {
 class MultiThreadedCertVerifierScopedAllowBaseSyncPrimitives;
+class MultiThreadedProxyResolverScopedAllowJoinOnIO;
 class NetworkChangeNotifierMac;
+class NetworkConfigWatcherMacThread;
 namespace internal {
 class AddressTrackerLinux;
 }
@@ -391,15 +398,18 @@
   // Allowed usage:
   friend class ::BrowserProcessImpl;  // http://crbug.com/125207
   friend class ::KeyStorageLinux;
+  friend class ::StartupTimeBomb;
   friend class Thread;
   friend class android::JavaHandlerThread;
   friend class base::MessageLoopImpl;
   friend class base::StackSamplingProfiler;
+  friend class content::SandboxHostLinux;
   friend class content::ScopedAllowWaitForDebugURL;
   friend class content::SynchronousCompositor;
   friend class content::SynchronousCompositorHost;
   friend class content::SynchronousCompositorSyncCallBridge;
   friend class mojo::SyncCallRestrictions;
+  friend class net::NetworkConfigWatcherMacThread;
   friend class viz::HostGpuMemoryBufferManager;
 
   // Usage that should be fixed:
@@ -414,8 +424,11 @@
   friend class disk_cache::InFlightIO;              // http://crbug.com/74623
   friend class gpu::GpuChannelHost;                 // http://crbug.com/125264
   friend class midi::TaskService;                   // https://crbug.com/796830
-  friend class net::NetworkChangeNotifierMac;       // http://crbug.com/125097
   friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
+  friend class net::
+      MultiThreadedProxyResolverScopedAllowJoinOnIO;  // http://crbug.com/69710
+  friend class net::NetworkChangeNotifierMac;         // http://crbug.com/125097
+  friend class printing::PrinterQuery;                // http://crbug.com/66082
   // Not used in production yet, https://crbug.com/844078.
   friend class service_manager::ServiceProcessLauncher;
   friend class ui::WindowResizeHelperMac;  // http://crbug.com/902829
diff --git a/build/chromeos/test_runner.py b/build/chromeos/test_runner.py
index 1e6ecf7..3052dfc 100755
--- a/build/chromeos/test_runner.py
+++ b/build/chromeos/test_runner.py
@@ -162,6 +162,9 @@
     self._suite_name = args.suite_name
     self._tests = args.tests
     self._conditional = args.conditional
+    # VMs don't have the disk space for an unstripped version of Chrome, so only
+    # strip when running on VMs.
+    self._should_strip = args.use_vm
 
   @property
   def suite_name(self):
@@ -186,6 +189,9 @@
           'Tast tests should not have additional args. These will be '
           'ignored: %s', self._additional_args)
 
+    if not self._should_strip:
+      self._vm_test_cmd.append('--nostrip')
+
     self._vm_test_cmd += [
         '--deploy',
         '--build-dir', os.path.relpath(self._path_to_outdir, CHROMIUM_SRC_PATH),
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index e71d730..af4c3f5 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -231,6 +231,9 @@
 
     # Speed up dexing using dx --incremental.
     enable_incremental_dx = is_java_debug
+
+    # Use hashed symbol names to reduce JNI symbol overhead.
+    use_hashed_jni_names = !is_java_debug
   }
 
   # Neither of these should ever be used for release builds since they are
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index f15adde13..34253ae 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -444,7 +444,7 @@
         rebase_path(depfile, root_build_dir),
       ]
 
-      if (!is_java_debug) {
+      if (use_hashed_jni_names) {
         args += [ "--use_proxy_hash" ]
       }
 
@@ -1779,13 +1779,16 @@
         jar_excluded_patterns = []
       }
       jar_excluded_patterns += [
-        "*J/N.class",
-        "*/GEN_JNI.class",
         "*/R.class",
         "*/R\$*.class",
         "*/Manifest.class",
         "*/Manifest\$*.class",
       ]
+      if (use_hashed_jni_names) {
+        jar_excluded_patterns += [ "J/N.class" ]
+      } else {
+        jar_excluded_patterns += [ "*/GEN_JNI.class" ]
+      }
     }
   }
 
diff --git a/build/config/linux/libva/BUILD.gn b/build/config/linux/libva/BUILD.gn
index 9e885f56..f350a0d 100644
--- a/build/config/linux/libva/BUILD.gn
+++ b/build/config/linux/libva/BUILD.gn
@@ -8,4 +8,6 @@
 
 pkg_config("libva") {
   packages = [ "libva" ]
+  # Do not use exec_script to check the version here. It is done with a
+  # static_assert instead.
 }
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index ff36bf1..41c02b5 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-d92c3706c90ae2546ddb404debe6e3a326edda8f
\ No newline at end of file
+ea9dcf76f8c34b7bb92bf26a358530bb2f8539c0
\ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 2da1c0e6..10877275 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-3a0eeaae9029a41ea62ae89f7c2ecca17154d112
\ No newline at end of file
+ddeddaca09f7c81db6f467eb3d879b3d18fb8454
\ No newline at end of file
diff --git a/cc/trees/element_id.cc b/cc/trees/element_id.cc
index 95c79a7b1..b460a2e 100644
--- a/cc/trees/element_id.cc
+++ b/cc/trees/element_id.cc
@@ -14,22 +14,6 @@
 
 namespace cc {
 
-bool ElementId::operator==(const ElementId& o) const {
-  return id_ == o.id_;
-}
-
-bool ElementId::operator!=(const ElementId& o) const {
-  return !(*this == o);
-}
-
-bool ElementId::operator<(const ElementId& o) const {
-  return id_ < o.id_;
-}
-
-ElementId::operator bool() const {
-  return !!id_;
-}
-
 ElementId LayerIdToElementIdForTesting(int layer_id) {
   return ElementId(std::numeric_limits<int>::max() - layer_id);
 }
diff --git a/cc/trees/element_id.h b/cc/trees/element_id.h
index ad88cc6..482ed3e 100644
--- a/cc/trees/element_id.h
+++ b/cc/trees/element_id.h
@@ -50,12 +50,12 @@
   explicit ElementId(ElementIdType id) : id_(id) {}
   ElementId() : ElementId(kInvalidElementId) {}
 
-  bool operator==(const ElementId& o) const;
-  bool operator!=(const ElementId& o) const;
-  bool operator<(const ElementId& o) const;
+  bool operator==(const ElementId& o) const { return id_ == o.id_; }
+  bool operator!=(const ElementId& o) const { return !(*this == o); }
+  bool operator<(const ElementId& o) const { return id_ < o.id_; }
 
   // An ElementId's conversion to a boolean value depends only on its primaryId.
-  explicit operator bool() const;
+  explicit operator bool() const { return !!id_; }
 
   void AddToTracedValue(base::trace_event::TracedValue* res) const;
   std::unique_ptr<base::Value> AsValue() const;
diff --git a/chrome/VERSION b/chrome/VERSION
index 74cd08e..8fbf5c0 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=73
 MINOR=0
-BUILD=3645
+BUILD=3646
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarMediator.java
index c485d6d..0107238 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/bottom/BrowsingModeBottomToolbarMediator.java
@@ -40,7 +40,7 @@
                    OverlayPanelManagerObserver, OverviewModeObserver, SceneChangeObserver,
                    ThemeColorObserver {
     /** The amount of time to show the Duet help bubble for. */
-    private static final int DUET_IPH_BUBBLE_SHOW_DURATION_MS = 6000;
+    private static final int DUET_IPH_BUBBLE_SHOW_DURATION_MS = 10000;
 
     /** The transparency fraction of the IPH bubble. */
     private static final float DUET_IPH_BUBBLE_ALPHA_FRACTION = 0.9f;
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 25b04405..d47500f 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4711,6 +4711,9 @@
           Pa&amp;ste and Search
         </message>
       </if>
+      <message name="IDS_SHOW_URL" desc="The text label of the Show URL menu item when the omnibox contains an elided URL or search query terms">
+        S&amp;how URL
+      </message>
       <message name="IDS_OMNIBOX_KEYWORD_HINT" desc="Shown to the user when the url in the omnibox has a keyword associated with it. $1 is replaced with an image showing the tab key. $2 is replaced with the description of the keyword.">
         Press <ph name="SEARCH_KEY">$1<ex>Tab</ex></ph> to search <ph name="SITE_NAME">$2<ex>google.com</ex></ph>
       </message>
diff --git a/chrome/app/generated_resources_grd/IDS_SHOW_URL.png.sha1 b/chrome/app/generated_resources_grd/IDS_SHOW_URL.png.sha1
new file mode 100644
index 0000000..204357eb3
--- /dev/null
+++ b/chrome/app/generated_resources_grd/IDS_SHOW_URL.png.sha1
@@ -0,0 +1 @@
+fff77d5fa8c40d181ccb794eb6b8321ec12cb40c
\ No newline at end of file
diff --git a/chrome/app/profiles_strings.grdp b/chrome/app/profiles_strings.grdp
index 7dfa0499..914e9ac 100644
--- a/chrome/app/profiles_strings.grdp
+++ b/chrome/app/profiles_strings.grdp
@@ -525,7 +525,7 @@
       All files and local data associated with the supervised user will be permanently deleted once this supervised user is removed. Visited websites and settings for this supervised user may still be visible by the manager at <ph name="MANAGEMENT_URL">$1<ex>www.example.com</ex></ph>.
     </message>
     <message name="IDS_LOGIN_POD_NON_OWNER_USER_REMOVE_WARNING" desc="Text shown as a warning when attempting to remove non-owner user.">
-      All files and local data associated with this user will be permanently deleted once this user is removed. $1 can still sign in later.
+      All files and local data associated with this user will be permanently deleted once this user is removed. <ph name="USER_EMAIL">$1<ex>john.doe@example.com</ex></ph> can still sign in later.
     </message>
     <if expr="not chromeos">
       <message name="IDS_USER_MANAGER_GO_GUEST_PROFILES_LOCKED_ERROR" desc="Error message displayed when trying to browser as guest while all profiles are locked.">
diff --git a/chrome/browser/browser_keyevents_browsertest.cc b/chrome/browser/browser_keyevents_browsertest.cc
index 2521332..6bf93ad 100644
--- a/chrome/browser/browser_keyevents_browsertest.cc
+++ b/chrome/browser/browser_keyevents_browsertest.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/events/keycodes/keyboard_codes.h"
 
 // TODO(kbr): remove: http://crbug.com/222296
@@ -527,6 +528,14 @@
 #define MAYBE_AccessKeys AccessKeys
 #endif
 IN_PROC_BROWSER_TEST_F(BrowserKeyEventsTest, MAYBE_AccessKeys) {
+  // TODO(crbug.com/916379): this test fails in mash because of differences in
+  // timing. In particular, in classic mode an accelerator that moves focus is
+  // processed *after* text is inserted, where as now the accelerator runs
+  // first, resulting in text going to the wrong place. The right fix likely
+  // entails updating the test for mash.
+  if (features::IsSingleProcessMash())
+    return;
+
 #if defined(OS_MACOSX)
   // On Mac, access keys use ctrl+alt modifiers.
   static const KeyEventTestData kTestAccessA = {
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index e46c9e2..99249f0 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -227,6 +227,8 @@
 
         <include name="IDR_APP_MANAGEMENT_ACTIONS_HTML" file="resources\app_management\actions.html" type="BINDATA" />
         <include name="IDR_APP_MANAGEMENT_ACTIONS_JS" file="resources\app_management\actions.js" type="BINDATA" />
+        <include name="IDR_APP_MANAGEMENT_API_LISTENER_HTML" file="resources\app_management\api_listener.html" type="BINDATA"/>
+        <include name="IDR_APP_MANAGEMENT_API_LISTENER_JS" file="resources\app_management\api_listener.js" type="BINDATA"/>
         <include name="IDR_APP_MANAGEMENT_APP_HTML" file="resources\app_management\app.html" type="BINDATA" />
         <include name="IDR_APP_MANAGEMENT_APP_JS" file="resources\app_management\app.js" type="BINDATA" />
         <include name="IDR_APP_MANAGEMENT_BROWSER_PROXY_HTML" file="resources\app_management\browser_proxy.html" type="BINDATA" />
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 5bec505c..830ebaa 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1511,6 +1511,8 @@
     "policy/device_local_account_policy_store.h",
     "policy/device_network_configuration_updater.cc",
     "policy/device_network_configuration_updater.h",
+    "policy/device_policy_cloud_external_data_manager.cc",
+    "policy/device_policy_cloud_external_data_manager.h",
     "policy/device_policy_decoder_chromeos.cc",
     "policy/device_policy_decoder_chromeos.h",
     "policy/device_policy_remover.h",
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
index c9413df..d8bdc22 100644
--- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
+++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.cc
@@ -18,6 +18,19 @@
 #include "dbus/message.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
+namespace {
+
+void SendResponse(dbus::MethodCall* method_call,
+                  dbus::ExportedObject::ResponseSender response_sender,
+                  bool answer) {
+  std::unique_ptr<dbus::Response> response =
+      dbus::Response::FromMethodCall(method_call);
+  dbus::MessageWriter writer(response.get());
+  writer.AppendBool(answer);
+  response_sender.Run(std::move(response));
+}
+}  // namespace
+
 namespace chromeos {
 
 ChromeFeaturesServiceProvider::ChromeFeaturesServiceProvider()
@@ -36,6 +49,13 @@
                           weak_ptr_factory_.GetWeakPtr()));
   exported_object->ExportMethod(
       kChromeFeaturesServiceInterface,
+      kChromeFeaturesServiceIsPluginVmEnabledMethod,
+      base::BindRepeating(&ChromeFeaturesServiceProvider::IsPluginVmEnabled,
+                          weak_ptr_factory_.GetWeakPtr()),
+      base::BindRepeating(&ChromeFeaturesServiceProvider::OnExported,
+                          weak_ptr_factory_.GetWeakPtr()));
+  exported_object->ExportMethod(
+      kChromeFeaturesServiceInterface,
       kChromeFeaturesServiceIsUsbguardEnabledMethod,
       base::BindRepeating(&ChromeFeaturesServiceProvider::IsUsbguardEnabled,
                           weak_ptr_factory_.GetWeakPtr()),
@@ -79,32 +99,30 @@
           : g_browser_process->profile_manager()->GetProfileByPath(
                 ProfileHelper::GetProfilePathByUserIdHash(user_id_hash));
 
-  std::unique_ptr<dbus::Response> response =
-      dbus::Response::FromMethodCall(method_call);
-  dbus::MessageWriter writer(response.get());
-  writer.AppendBool(crostini::IsCrostiniAllowedForProfile(profile));
-  response_sender.Run(std::move(response));
+  SendResponse(method_call, response_sender,
+               crostini::IsCrostiniAllowedForProfile(profile));
 }
 
-// TODO(mortonm): Combine these functions below when adding any more flags.
+void ChromeFeaturesServiceProvider::IsPluginVmEnabled(
+    dbus::MethodCall* method_call,
+    dbus::ExportedObject::ResponseSender response_sender) {
+  // TODO(dtor): extend the check to include device capabilities
+  // and device/user policies.
+  SendResponse(method_call, response_sender,
+               base::FeatureList::IsEnabled(features::kPluginVm));
+}
+
 void ChromeFeaturesServiceProvider::IsUsbguardEnabled(
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
-  std::unique_ptr<dbus::Response> response =
-      dbus::Response::FromMethodCall(method_call);
-  dbus::MessageWriter writer(response.get());
-  writer.AppendBool(base::FeatureList::IsEnabled(features::kUsbguard));
-  response_sender.Run(std::move(response));
+  SendResponse(method_call, response_sender,
+               base::FeatureList::IsEnabled(features::kUsbguard));
 }
 
 void ChromeFeaturesServiceProvider::IsShillSandboxingEnabled(
     dbus::MethodCall* method_call,
     dbus::ExportedObject::ResponseSender response_sender) {
-  std::unique_ptr<dbus::Response> response =
-      dbus::Response::FromMethodCall(method_call);
-  dbus::MessageWriter writer(response.get());
-  writer.AppendBool(base::FeatureList::IsEnabled(features::kShillSandboxing));
-  response_sender.Run(std::move(response));
+  SendResponse(method_call, response_sender,
+               base::FeatureList::IsEnabled(features::kShillSandboxing));
 }
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/dbus/chrome_features_service_provider.h b/chrome/browser/chromeos/dbus/chrome_features_service_provider.h
index ab0d91aa..0cc5070 100644
--- a/chrome/browser/chromeos/dbus/chrome_features_service_provider.h
+++ b/chrome/browser/chromeos/dbus/chrome_features_service_provider.h
@@ -27,6 +27,15 @@
 //     org.chromium.ChromeFeaturesServiceInterface.IsCrostiniEnabled
 //
 // % (returns true if Crostini is enabled, otherwise returns false)
+//
+// IsPluginVmEnabled:
+// % dbus-send --system --type=method_call --print-reply
+//     --dest=org.chromium.ChromeFeaturesService
+//     /org/chromium/ChromeFeaturesService
+//     org.chromium.ChromeFeaturesServiceInterface.IsPluginVmEnabled
+//
+// % (returns true if Plugin VMs are enabled, otherwise returns false)
+
 class ChromeFeaturesServiceProvider
     : public CrosDBusService::ServiceProviderInterface {
  public:
@@ -46,6 +55,8 @@
   // Called on UI thread in response to a D-Bus request.
   void IsCrostiniEnabled(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);
+  void IsPluginVmEnabled(dbus::MethodCall* method_call,
+                         dbus::ExportedObject::ResponseSender response_sender);
   void IsUsbguardEnabled(dbus::MethodCall* method_call,
                          dbus::ExportedObject::ResponseSender response_sender);
   void IsShillSandboxingEnabled(
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 927f8b0..400fba6 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -296,7 +296,11 @@
                       ZipCase("zipFileOpenDownloadsShiftJIS"),
                       ZipCase("zipFileOpenDownloadsMacOs"),
                       ZipCase("zipFileOpenDownloadsWithAbsolutePaths"),
+// Disable the test in debug mode. In debug mode, the test run time is very
+// close to, and often exceeds the 45 second test timeout.
+#if defined(NDEBUG)
                       ZipCase("zipFileOpenDownloadsEncryptedCancelPassphrase"),
+#endif
                       ZipCase("zipFileOpenDrive").DisableDriveFs(),
                       ZipCase("zipFileOpenDrive").EnableDriveFs(),
                       ZipCase("zipFileOpenUsb"),
diff --git a/chrome/browser/chromeos/file_manager/file_manager_uitest.cc b/chrome/browser/chromeos/file_manager/file_manager_uitest.cc
index 3a62f9b..fac8fe7f02 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_uitest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_uitest.cc
@@ -73,6 +73,10 @@
   RunTest("crostiniTasks");
 }
 
+IN_PROC_BROWSER_TEST_F(FileManagerUITest, Menu) {
+  RunTest("menu");
+}
+
 IN_PROC_BROWSER_TEST_F(FileManagerUITest, ProgressCenter) {
   RunTest("progressCenter");
 }
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 978eb3a..ad53810 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -58,50 +58,40 @@
 
 enum InputMethodCategory {
   INPUT_METHOD_CATEGORY_UNKNOWN = 0,
-  INPUT_METHOD_CATEGORY_XKB,  // XKB input methods
-  INPUT_METHOD_CATEGORY_ZH,   // Chinese input methods
-  INPUT_METHOD_CATEGORY_JA,   // Japanese input methods
-  INPUT_METHOD_CATEGORY_KO,   // Korean input methods
-  INPUT_METHOD_CATEGORY_M17N, // Multilingualization input methods
-  INPUT_METHOD_CATEGORY_T13N, // Transliteration input methods
+  INPUT_METHOD_CATEGORY_XKB,   // XKB input methods
+  INPUT_METHOD_CATEGORY_ZH,    // Chinese input methods
+  INPUT_METHOD_CATEGORY_JA,    // Japanese input methods
+  INPUT_METHOD_CATEGORY_KO,    // Korean input methods
+  INPUT_METHOD_CATEGORY_M17N,  // Multilingualization input methods
+  INPUT_METHOD_CATEGORY_T13N,  // Transliteration input methods
+  INPUT_METHOD_CATEGORY_ARC,   // ARC input methods
   INPUT_METHOD_CATEGORY_MAX
 };
 
-InputMethodCategory GetInputMethodCategory(const std::string& input_method_id,
-                                           char* first_char = NULL) {
+InputMethodCategory GetInputMethodCategory(const std::string& input_method_id) {
   const std::string component_id =
       extension_ime_util::GetComponentIDByInputMethodID(input_method_id);
   InputMethodCategory category = INPUT_METHOD_CATEGORY_UNKNOWN;
-  char ch = 0;
   if (base::StartsWith(component_id, "xkb:", base::CompareCase::SENSITIVE)) {
-    ch = component_id[4];
     category = INPUT_METHOD_CATEGORY_XKB;
   } else if (base::StartsWith(component_id, "zh-",
                               base::CompareCase::SENSITIVE)) {
-    size_t pos = component_id.find("-t-i0-");
-    if (pos > 0)
-      pos += 6;
-    ch = component_id[pos];
     category = INPUT_METHOD_CATEGORY_ZH;
   } else if (base::StartsWith(component_id, "nacl_mozc_",
                               base::CompareCase::SENSITIVE)) {
-    ch = component_id[10];
     category = INPUT_METHOD_CATEGORY_JA;
   } else if (base::StartsWith(component_id, "hangul_",
                               base::CompareCase::SENSITIVE)) {
-    ch = component_id[7];
     category = INPUT_METHOD_CATEGORY_KO;
   } else if (base::StartsWith(component_id, "vkd_",
                               base::CompareCase::SENSITIVE)) {
-    ch = component_id[4];
     category = INPUT_METHOD_CATEGORY_M17N;
-  } else if (component_id.find("-t-i0-") > 0) {
-    ch = component_id[0];
+  } else if (component_id.find("-t-i0-") != std::string::npos) {
     category = INPUT_METHOD_CATEGORY_T13N;
+  } else if (extension_ime_util::IsArcIME(input_method_id)) {
+    category = INPUT_METHOD_CATEGORY_ARC;
   }
 
-  if (first_char)
-    *first_char = ch;
   return category;
 }
 
diff --git a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
index 1ca84e1..3e22b48 100644
--- a/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
+++ b/chrome/browser/chromeos/policy/browser_policy_connector_chromeos.cc
@@ -13,6 +13,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/path_service.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
@@ -29,6 +30,7 @@
 #include "chrome/browser/chromeos/policy/device_local_account.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
 #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h"
+#include "chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h"
 #include "chrome/browser/chromeos/policy/enrollment_config.h"
 #include "chrome/browser/chromeos/policy/hostname_handler.h"
 #include "chrome/browser/chromeos/policy/minimum_version_policy_handler.h"
@@ -40,6 +42,7 @@
 #include "chrome/browser/policy/device_management_service_configuration.h"
 #include "chrome/common/pref_names.h"
 #include "chromeos/attestation/attestation_flow.h"
+#include "chromeos/chromeos_paths.h"
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/cryptohome/async_method_caller.h"
 #include "chromeos/cryptohome/system_salt_getter.h"
@@ -56,7 +59,9 @@
 #include "chromeos/system/statistics_provider.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
+#include "components/policy/core/common/cloud/resource_cache.h"
 #include "components/policy/core/common/proxy_policy_provider.h"
+#include "components/policy/policy_constants.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "google_apis/gaia/gaia_auth_util.h"
@@ -123,9 +128,20 @@
       state_keys_broker_ = std::make_unique<ServerBackedStateKeysBroker>(
           chromeos::DBusThreadManager::Get()->GetSessionManagerClient());
 
+      base::FilePath device_policy_external_data_path;
+      CHECK(base::PathService::Get(chromeos::DIR_DEVICE_POLICY_EXTERNAL_DATA,
+                                   &device_policy_external_data_path));
+
+      auto external_data_manager =
+          std::make_unique<DevicePolicyCloudExternalDataManager>(
+              base::BindRepeating(&GetChromePolicyDetails),
+              GetBackgroundTaskRunner(), device_policy_external_data_path,
+              device_cloud_policy_store.get());
+
       device_cloud_policy_manager_ = new DeviceCloudPolicyManagerChromeOS(
           std::move(device_cloud_policy_store),
-          base::ThreadTaskRunnerHandle::Get(), state_keys_broker_.get());
+          std::move(external_data_manager), base::ThreadTaskRunnerHandle::Get(),
+          state_keys_broker_.get());
       providers_for_init_.push_back(
           base::WrapUnique<ConfigurationPolicyProvider>(
               device_cloud_policy_manager_));
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc b/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc
index d50b8c4..880c4f4 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_manager_base.cc
@@ -366,7 +366,13 @@
 
 CloudExternalDataManagerBase::~CloudExternalDataManagerBase() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  backend_task_runner_->DeleteSoon(FROM_HERE, backend_.release());
+  Backend* backend_to_delete = backend_.release();
+  if (!backend_task_runner_->DeleteSoon(FROM_HERE, backend_to_delete)) {
+    // If the task runner is no longer running, it's safe to just delete the
+    // object, since no further events will be delivered by external data
+    // manager.
+    delete backend_to_delete;
+  }
 }
 
 void CloudExternalDataManagerBase::SetExternalDataStore(
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc
index 527e318..b582f16 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.cc
@@ -7,9 +7,15 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_writer.h"
 #include "base/memory/weak_ptr.h"
+#include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/threading/thread_restrictions.h"
 #include "base/values.h"
+#include "chrome/common/chrome_paths.h"
 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -17,7 +23,9 @@
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_types.h"
 #include "crypto/sha2.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
 
 namespace policy {
 namespace test {
@@ -40,6 +48,27 @@
   return metadata;
 }
 
+std::string ConstructExternalDataPolicy(
+    const net::test_server::EmbeddedTestServer& test_server,
+    const std::string& external_data_path) {
+  std::string url =
+      test_server.GetURL(std::string("/") + external_data_path).spec();
+
+  std::string external_data;
+  base::FilePath test_data_dir;
+  EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+  {
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    EXPECT_TRUE(base::ReadFileToString(
+        test_data_dir.AppendASCII(external_data_path), &external_data));
+  }
+
+  std::string policy;
+  EXPECT_TRUE(base::JSONWriter::Write(
+      *ConstructExternalDataReference(url, external_data), &policy));
+  return policy;
+}
+
 void SetExternalDataReference(CloudPolicyCore* core,
                               const std::string& policy,
                               std::unique_ptr<base::DictionaryValue> metadata) {
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h
index 7ae9fb3..5a2fc63 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h
+++ b/chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h
@@ -14,6 +14,12 @@
 class DictionaryValue;
 }
 
+namespace net {
+namespace test_server {
+class EmbeddedTestServer;
+}
+}  // namespace net
+
 namespace policy {
 
 class CloudPolicyCore;
@@ -32,6 +38,12 @@
     const std::string& url,
     const std::string& data);
 
+// Constructs the external data policy from the content of the file located on
+// |external_data_path|.
+std::string ConstructExternalDataPolicy(
+    const net::test_server::EmbeddedTestServer& test_server,
+    const std::string& external_data_path);
+
 // TODO(bartfab): Makes an arbitrary |policy| in |core| reference external data
 // as specified in |metadata|. This is only done because there are no policies
 // that reference external data yet. Once the first such policy is added, it
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_store.cc b/chrome/browser/chromeos/policy/cloud_external_data_store.cc
index af8189a1..3bc7163 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_store.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_store.cc
@@ -37,7 +37,13 @@
 }
 
 CloudExternalDataStore::~CloudExternalDataStore() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  // No RunsTasksInCurrentSequence() check to avoid unit tests failures.
+  // In unit tests the browser process instance is deleted only after test ends
+  // and test task scheduler is shutted down. Therefore we need to delete some
+  // components of BrowserPolicyConnector (ResourceCache and
+  // CloudExternalDataManagerBase::Backend) manually when task runner doesn't
+  // accept new tasks (DeleteSoon in this case). This leads to the situation
+  // when this destructor is called not on |task_runner|.
 }
 
 void CloudExternalDataStore::Prune(
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
index 728fada3..abd33c9 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -38,6 +38,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/settings/install_attributes.h"
 #include "chromeos/system/statistics_provider.h"
+#include "components/policy/core/common/cloud/cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/cloud_policy_service.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
@@ -49,6 +50,7 @@
 #include "content/public/browser/network_service_instance.h"
 #include "crypto/sha2.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 
 namespace em = enterprise_management;
@@ -109,6 +111,7 @@
 
 DeviceCloudPolicyManagerChromeOS::DeviceCloudPolicyManagerChromeOS(
     std::unique_ptr<DeviceCloudPolicyStoreChromeOS> store,
+    std::unique_ptr<CloudExternalDataManager> external_data_manager,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
     ServerBackedStateKeysBroker* state_keys_broker)
     : CloudPolicyManager(
@@ -118,6 +121,7 @@
           task_runner,
           base::BindRepeating(&content::GetNetworkConnectionTracker)),
       device_store_(std::move(store)),
+      external_data_manager_(std::move(external_data_manager)),
       state_keys_broker_(state_keys_broker),
       task_runner_(task_runner),
       local_state_(nullptr) {}
@@ -199,6 +203,7 @@
   syslog_uploader_.reset();
   heartbeat_scheduler_.reset();
   state_keys_update_subscription_.reset();
+  external_data_manager_->Disconnect();
   CloudPolicyManager::Shutdown();
   signin_profile_forwarding_schema_registry_.reset();
 }
@@ -270,6 +275,9 @@
   core()->TrackRefreshDelayPref(local_state_,
                                 prefs::kDevicePolicyRefreshRate);
 
+  external_data_manager_->Connect(
+      g_browser_process->shared_url_loader_factory());
+
   enrollment_policy_observer_.reset(
       new chromeos::attestation::EnrollmentPolicyObserver(client()));
 
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
index 2bf2acc7..76b439f 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h
@@ -63,6 +63,7 @@
   // upload tasks.
   DeviceCloudPolicyManagerChromeOS(
       std::unique_ptr<DeviceCloudPolicyStoreChromeOS> store,
+      std::unique_ptr<CloudExternalDataManager> external_data_manager,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner,
       ServerBackedStateKeysBroker* state_keys_broker);
   ~DeviceCloudPolicyManagerChromeOS() override;
@@ -154,6 +155,10 @@
   // Points to the same object as the base CloudPolicyManager::store(), but with
   // actual device policy specific type.
   std::unique_ptr<DeviceCloudPolicyStoreChromeOS> device_store_;
+
+  // Manages external data referenced by device policies.
+  std::unique_ptr<CloudExternalDataManager> external_data_manager_;
+
   ServerBackedStateKeysBroker* state_keys_broker_;
 
   // Helper object that handles updating the server with our current device
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 667fb546..d494942d 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -48,6 +48,7 @@
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/cloud_policy_core.h"
 #include "components/policy/core/common/cloud/dm_auth.h"
+#include "components/policy/core/common/cloud/mock_cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/mock_device_management_service.h"
 #include "components/policy/core/common/cloud/mock_signing_service.h"
 #include "components/policy/core/common/external_data_fetcher.h"
@@ -106,9 +107,11 @@
  public:
   TestingDeviceCloudPolicyManagerChromeOS(
       std::unique_ptr<DeviceCloudPolicyStoreChromeOS> store,
+      std::unique_ptr<CloudExternalDataManager> external_data_manager,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner,
       ServerBackedStateKeysBroker* state_keys_broker)
       : DeviceCloudPolicyManagerChromeOS(std::move(store),
+                                         std::move(external_data_manager),
                                          task_runner,
                                          state_keys_broker) {
     set_component_policy_disabled_for_testing(true);
@@ -158,8 +161,9 @@
         &device_settings_service_, install_attributes_.get(),
         base::ThreadTaskRunnerHandle::Get());
     manager_ = std::make_unique<TestingDeviceCloudPolicyManagerChromeOS>(
-        base::WrapUnique(store_), base::ThreadTaskRunnerHandle::Get(),
-        &state_keys_broker_);
+        base::WrapUnique(store_),
+        std::make_unique<MockCloudExternalDataManager>(),
+        base::ThreadTaskRunnerHandle::Get(), &state_keys_broker_);
 
     RegisterLocalState(local_state_.registry());
     manager_->Init(&schema_registry_);
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
index ff960d75..4178d42 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/chromeos/policy/value_validation/onc_device_policy_value_validator.h"
 #include "chromeos/settings/install_attributes.h"
 #include "components/ownership/owner_key_util.h"
+#include "components/policy/core/common/cloud/cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/policy/proto/device_management_backend.pb.h"
@@ -168,7 +169,7 @@
     PolicyMap new_policy_map;
     if (is_managed()) {
       DecodeDevicePolicy(*device_settings_service_->device_settings(),
-                         &new_policy_map);
+                         external_data_manager(), &new_policy_map);
     }
     policy_map_.Swap(&new_policy_map);
 
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.cc b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.cc
new file mode 100644
index 0000000..1e56ede
--- /dev/null
+++ b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.cc
@@ -0,0 +1,62 @@
+// 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/device_policy_cloud_external_data_manager.h"
+
+#include <stdint.h>
+#include <utility>
+
+#include "base/location.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/browser/chromeos/policy/cloud_external_data_store.h"
+#include "components/policy/core/common/cloud/cloud_policy_store.h"
+#include "components/policy/core/common/cloud/resource_cache.h"
+
+namespace policy {
+
+namespace {
+
+const char kCacheKey[] = "device_policy_external_data";
+
+// Maximum size of the device policy external data cache directory set to 10MB.
+const int64_t kCacheMaxSize = 10 * 1024 * 1024;
+// Only used for tests.
+int64_t g_cache_max_size_override = 0;
+
+}  // namespace
+
+DevicePolicyCloudExternalDataManager::DevicePolicyCloudExternalDataManager(
+    const GetChromePolicyDetailsCallback& get_policy_details,
+    scoped_refptr<base::SequencedTaskRunner> backend_task_runner,
+    const base::FilePath& cache_path,
+    CloudPolicyStore* policy_store)
+    : CloudExternalDataManagerBase(get_policy_details, backend_task_runner) {
+  int cache_max_size = kCacheMaxSize;
+  if (g_cache_max_size_override != 0)
+    cache_max_size = g_cache_max_size_override;
+  resource_cache_ = std::make_unique<ResourceCache>(
+      cache_path, backend_task_runner, cache_max_size);
+
+  SetPolicyStore(policy_store);
+  SetExternalDataStore(std::make_unique<CloudExternalDataStore>(
+      kCacheKey, backend_task_runner, resource_cache_.get()));
+}
+
+DevicePolicyCloudExternalDataManager::~DevicePolicyCloudExternalDataManager() {
+  SetExternalDataStore(nullptr);
+  ResourceCache* resource_cache_to_delete = resource_cache_.release();
+  if (!backend_task_runner_->DeleteSoon(FROM_HERE, resource_cache_to_delete)) {
+    // If the task runner is no longer running, it's safe to just delete the
+    // object, since no further events will be delivered by external data
+    // manager.
+    delete resource_cache_to_delete;
+  }
+}
+
+void DevicePolicyCloudExternalDataManager::SetCacheMaxSizeForTesting(
+    int64_t cache_max_size) {
+  g_cache_max_size_override = cache_max_size;
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h
new file mode 100644
index 0000000..85f799b3
--- /dev/null
+++ b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.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 CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
+#define CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
+#include "components/policy/core/common/policy_details.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace policy {
+
+class CloudPolicyStore;
+class ResourceCache;
+
+// Downloads, verifies and caches external data referenced by policies.
+// This is the implementation for device policy external data.
+class DevicePolicyCloudExternalDataManager
+    : public CloudExternalDataManagerBase {
+ public:
+  // |get_policy_details| is used to determine the maximum size that the
+  // data referenced by each policy can have. Download scheduling, verification,
+  // caching and retrieval tasks are done via the |backend_task_runner|, which
+  // must support file I/O. |resource_cache| is used to construct a data store
+  // which caches downloaded blobs on disk.
+  DevicePolicyCloudExternalDataManager(
+      const GetChromePolicyDetailsCallback& get_policy_details,
+      scoped_refptr<base::SequencedTaskRunner> backend_task_runner,
+      const base::FilePath& cache_path,
+      CloudPolicyStore* policy_store);
+  ~DevicePolicyCloudExternalDataManager() override;
+
+  // Sets the cache maximum size for testing.
+  // It's used to avoid creating big data in tests.
+  static void SetCacheMaxSizeForTesting(int64_t cache_max_size);
+
+ private:
+  // Cache used by the data store. Must outlive the data store.
+  std::unique_ptr<ResourceCache> resource_cache_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevicePolicyCloudExternalDataManager);
+};
+
+}  // namespace policy
+
+#endif  // CHROME_BROWSER_CHROMEOS_POLICY_DEVICE_POLICY_CLOUD_EXTERNAL_DATA_MANAGER_H_
diff --git a/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
new file mode 100644
index 0000000..c7ffd3e
--- /dev/null
+++ b/chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc
@@ -0,0 +1,212 @@
+// 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 <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base.h"
+#include "chrome/browser/chromeos/policy/cloud_external_data_manager_base_test_util.h"
+#include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/chromeos/policy/device_policy_cloud_external_data_manager.h"
+#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
+#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
+#include "chrome/browser/chromeos/settings/scoped_cros_settings_test_helper.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/chromeos_paths.h"
+#include "components/policy/core/common/cloud/cloud_policy_core.h"
+#include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
+#include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_service.h"
+#include "components/policy/policy_constants.h"
+#include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+
+// The contents of these files are served as external data.
+const char kExternalDataPath[] = "policy/printers_configuration.json";
+const char kExternalDataPathUpdated[] =
+    "policy/printers_configuration_updated.json";
+const char kExternalDataPathOverSizeLimit[] =
+    "policy/printers_configuration_over_size_limit.json";
+// The name of an External Data Policy in Device Policy.
+const char* const kPolicyName = policy::key::kDeviceNativePrinters;
+
+const int64_t kTestCacheMaxSize = 64;
+
+}  // namespace
+
+class DevicePolicyCloudExternalDataManagerTest
+    : public DevicePolicyCrosBrowserTest {
+ public:
+  DevicePolicyCloudExternalDataManagerTest() {
+    DevicePolicyCloudExternalDataManager::SetCacheMaxSizeForTesting(
+        kTestCacheMaxSize);
+  }
+  ~DevicePolicyCloudExternalDataManagerTest() override = default;
+
+ protected:
+  void SetUpOnMainThread() override {
+    ASSERT_TRUE(embedded_test_server()->Start());
+    DevicePolicyCrosBrowserTest::SetUpOnMainThread();
+
+    BrowserPolicyConnectorChromeOS* policy_connector =
+        g_browser_process->platform_part()->browser_policy_connector_chromeos();
+    ASSERT_TRUE(policy_connector);
+    policy_service_ = policy_connector->GetPolicyService();
+    ASSERT_TRUE(
+        policy_service_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
+    policy_change_registrar_ = std::make_unique<PolicyChangeRegistrar>(
+        policy_service_, PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+    policy_change_registrar_->Observe(
+        kPolicyName,
+        base::BindRepeating(
+            &DevicePolicyCloudExternalDataManagerTest::PolicyChangedCallback,
+            base::Unretained(this)));
+
+    policy_change_waiting_run_loop_ = std::make_unique<base::RunLoop>();
+  }
+
+  void TearDownOnMainThread() override {
+    policy_change_registrar_.reset();
+    DevicePolicyCrosBrowserTest::TearDownOnMainThread();
+  }
+
+  std::string GetExternalData() {
+    const PolicyMap& policies = policy_service_->GetPolicies(
+        PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+    const PolicyMap::Entry* policy_entry = policies.Get(kPolicyName);
+    EXPECT_TRUE(policy_entry);
+    EXPECT_TRUE(policy_entry->external_data_fetcher);
+
+    base::RunLoop run_loop;
+    std::unique_ptr<std::string> fetched_external_data;
+    policy_entry->external_data_fetcher->Fetch(
+        base::BindRepeating(&test::ExternalDataFetchCallback,
+                            &fetched_external_data, run_loop.QuitClosure()));
+    run_loop.Run();
+
+    EXPECT_TRUE(fetched_external_data);
+    return *fetched_external_data;
+  }
+
+  int64_t ComputeExternalDataCacheDirectorySize() {
+    base::FilePath device_policy_external_data_path;
+    CHECK(base::PathService::Get(chromeos::DIR_DEVICE_POLICY_EXTERNAL_DATA,
+                                 &device_policy_external_data_path));
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    return base::ComputeDirectorySize(device_policy_external_data_path);
+  }
+
+  void SetDeviceNativePrintersExternalData(const std::string& policy) {
+    device_policy()
+        ->payload()
+        .mutable_native_device_printers()
+        ->set_external_policy(policy);
+    RefreshDevicePolicy();
+    WaitUntilPolicyChanged();
+  }
+
+  void ClearDeviceNativePrintersExternalData() {
+    device_policy()->payload().clear_native_device_printers();
+    RefreshDevicePolicy();
+    WaitUntilPolicyChanged();
+  }
+
+  std::string ReadExternalDataFile(const std::string& file_path) {
+    base::FilePath test_data_dir;
+    EXPECT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
+    std::string external_data;
+    {
+      base::ScopedAllowBlockingForTesting allow_blocking;
+      EXPECT_TRUE(base::ReadFileToString(test_data_dir.AppendASCII(file_path),
+                                         &external_data));
+    }
+    return external_data;
+  }
+
+ private:
+  void PolicyChangedCallback(const base::Value* old_value,
+                             const base::Value* new_value) {
+    policy_change_waiting_run_loop_->Quit();
+  }
+
+  void WaitUntilPolicyChanged() {
+    policy_change_waiting_run_loop_->Run();
+    policy_change_waiting_run_loop_.reset(new base::RunLoop());
+  }
+
+  PolicyService* policy_service_ = nullptr;
+  std::unique_ptr<PolicyChangeRegistrar> policy_change_registrar_;
+  std::unique_ptr<base::RunLoop> policy_change_waiting_run_loop_;
+};
+
+IN_PROC_BROWSER_TEST_F(DevicePolicyCloudExternalDataManagerTest,
+                       FetchExternalData) {
+  SetDeviceNativePrintersExternalData(test::ConstructExternalDataPolicy(
+      *embedded_test_server(), kExternalDataPath));
+  EXPECT_EQ(ReadExternalDataFile(kExternalDataPath), GetExternalData());
+}
+
+IN_PROC_BROWSER_TEST_F(DevicePolicyCloudExternalDataManagerTest,
+                       FetchOverSizeLimitExternalData) {
+  EXPECT_EQ(0, ComputeExternalDataCacheDirectorySize());
+
+  std::string external_data =
+      ReadExternalDataFile(kExternalDataPathOverSizeLimit);
+  // Check that file size is greater than cache limit.
+  ASSERT_GT(base::checked_cast<int64_t>(external_data.size()),
+            kTestCacheMaxSize);
+  SetDeviceNativePrintersExternalData(test::ConstructExternalDataPolicy(
+      *embedded_test_server(), kExternalDataPathOverSizeLimit));
+  EXPECT_EQ(external_data, GetExternalData());
+
+  // Check that nothing is cached because file was too big.
+  EXPECT_EQ(0, ComputeExternalDataCacheDirectorySize());
+}
+
+IN_PROC_BROWSER_TEST_F(DevicePolicyCloudExternalDataManagerTest,
+                       CleanUpResourceCache) {
+  EXPECT_EQ(0, ComputeExternalDataCacheDirectorySize());
+
+  std::string external_data = ReadExternalDataFile(kExternalDataPath);
+  SetDeviceNativePrintersExternalData(test::ConstructExternalDataPolicy(
+      *embedded_test_server(), kExternalDataPath));
+  EXPECT_EQ(external_data, GetExternalData());
+  EXPECT_EQ(base::checked_cast<int64_t>(external_data.size()),
+            ComputeExternalDataCacheDirectorySize());
+
+  external_data = ReadExternalDataFile(kExternalDataPathUpdated);
+  SetDeviceNativePrintersExternalData(test::ConstructExternalDataPolicy(
+      *embedded_test_server(), kExternalDataPathUpdated));
+  EXPECT_EQ(external_data, GetExternalData());
+  // Check that previous policy data was cleared and replaced by new one.
+  EXPECT_EQ(base::checked_cast<int64_t>(external_data.size()),
+            ComputeExternalDataCacheDirectorySize());
+
+  ClearDeviceNativePrintersExternalData();
+  // Check that policy data was cleared.
+  EXPECT_EQ(0, ComputeExternalDataCacheDirectorySize());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
index 582e986..766d7433 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.cc
@@ -24,6 +24,7 @@
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/policy/core/common/chrome_schema.h"
 #include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/core/common/external_data_manager.h"
 #include "components/policy/core/common/policy_map.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/core/common/schema.h"
@@ -46,20 +47,41 @@
 // Otherwise, the policy will be set to a base::Value of the original
 // |json_string|. This way, the faulty value can still be seen in
 // chrome://policy along with any errors/warnings.
-void SetJsonDevicePolicy(const std::string& policy_name,
-                         const std::string& json_string,
-                         PolicyMap* policies) {
+void SetJsonDevicePolicy(
+    const std::string& policy_name,
+    const std::string& json_string,
+    std::unique_ptr<ExternalDataFetcher> external_data_fetcher,
+    PolicyMap* policies) {
   std::string error;
   std::unique_ptr<base::Value> decoded_json =
       DecodeJsonStringAndNormalize(json_string, policy_name, &error);
   auto value_to_set = decoded_json ? std::move(decoded_json)
                                    : std::make_unique<base::Value>(json_string);
   policies->Set(policy_name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
-                POLICY_SOURCE_CLOUD, std::move(value_to_set), nullptr);
+                POLICY_SOURCE_CLOUD, std::move(value_to_set),
+                std::move(external_data_fetcher));
   if (!error.empty())
     policies->AddError(policy_name, error);
 }
 
+void SetJsonDevicePolicy(const std::string& policy_name,
+                         const std::string& json_string,
+                         PolicyMap* policies) {
+  SetJsonDevicePolicy(policy_name, json_string,
+                      /* external_data_fetcher */ nullptr, policies);
+}
+
+void SetExternalDataDevicePolicy(
+    const std::string& policy_name,
+    const std::string& json_string,
+    base::WeakPtr<ExternalDataManager> external_data_manager,
+    PolicyMap* policies) {
+  SetJsonDevicePolicy(
+      policy_name, json_string,
+      std::make_unique<ExternalDataFetcher>(external_data_manager, policy_name),
+      policies);
+}
+
 // Decodes a protobuf integer to an IntegerValue. Returns NULL in case the input
 // value is out of bounds.
 std::unique_ptr<base::Value> DecodeIntegerValue(google::protobuf::int64 value) {
@@ -721,6 +743,22 @@
   }
 }
 
+void DecodeExternalDataPolicies(
+    const em::ChromeDeviceSettingsProto& policy,
+    base::WeakPtr<ExternalDataManager> external_data_manager,
+    PolicyMap* policies) {
+  // TODO(https://crbug.com/814364): Migrate device wallpaper here.
+  if (policy.has_native_device_printers()) {
+    const em::DeviceNativePrintersProto& container(
+        policy.native_device_printers());
+    if (container.has_external_policy()) {
+      SetExternalDataDevicePolicy(key::kDeviceNativePrinters,
+                                  container.external_policy(),
+                                  external_data_manager, policies);
+    }
+  }
+}
+
 void DecodeGenericPolicies(const em::ChromeDeviceSettingsProto& policy,
                            PolicyMap* policies) {
   if (policy.has_device_policy_refresh_rate()) {
@@ -930,15 +968,6 @@
                     std::make_unique<base::Value>(container.name()), nullptr);
   }
 
-  if (policy.has_native_device_printers()) {
-    const em::DeviceNativePrintersProto& container(
-        policy.native_device_printers());
-    if (container.has_external_policy()) {
-      SetJsonDevicePolicy(key::kDeviceNativePrinters,
-                          container.external_policy(), policies);
-    }
-  }
-
   if (policy.has_native_device_printers_access_mode()) {
     const em::DeviceNativePrintersAccessModeProto& container(
         policy.native_device_printers_access_mode());
@@ -1146,14 +1175,17 @@
   return root;
 }
 
-void DecodeDevicePolicy(const em::ChromeDeviceSettingsProto& policy,
-                        PolicyMap* policies) {
+void DecodeDevicePolicy(
+    const em::ChromeDeviceSettingsProto& policy,
+    base::WeakPtr<ExternalDataManager> external_data_manager,
+    PolicyMap* policies) {
   // Decode the various groups of policies.
   DecodeLoginPolicies(policy, policies);
   DecodeNetworkPolicies(policy, policies);
   DecodeReportingPolicies(policy, policies);
   DecodeAutoUpdatePolicies(policy, policies);
   DecodeAccessibilityPolicies(policy, policies);
+  DecodeExternalDataPolicies(policy, external_data_manager, policies);
   DecodeGenericPolicies(policy, policies);
 }
 
diff --git a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h
index edc4f7f7..72d1fc53 100644
--- a/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h
+++ b/chrome/browser/chromeos/policy/device_policy_decoder_chromeos.h
@@ -8,6 +8,8 @@
 #include <memory>
 #include <string>
 
+#include "base/memory/weak_ptr.h"
+
 namespace enterprise_management {
 class ChromeDeviceSettingsProto;
 }
@@ -18,6 +20,7 @@
 
 namespace policy {
 
+class ExternalDataManager;
 class PolicyMap;
 
 // Decodes a JSON string to a base::Value and validates it against the schema
@@ -35,6 +38,7 @@
 // PolicyMap.
 void DecodeDevicePolicy(
     const enterprise_management::ChromeDeviceSettingsProto& policy,
+    base::WeakPtr<ExternalDataManager> external_data_manager,
     PolicyMap* policies);
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/fake_device_cloud_policy_manager.cc b/chrome/browser/chromeos/policy/fake_device_cloud_policy_manager.cc
index e784c3ad..1a08c2f 100644
--- a/chrome/browser/chromeos/policy/fake_device_cloud_policy_manager.cc
+++ b/chrome/browser/chromeos/policy/fake_device_cloud_policy_manager.cc
@@ -8,13 +8,18 @@
 
 #include "base/callback.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos.h"
+#include "components/policy/core/common/cloud/mock_cloud_external_data_manager.h"
 
 namespace policy {
 
 FakeDeviceCloudPolicyManager::FakeDeviceCloudPolicyManager(
     std::unique_ptr<DeviceCloudPolicyStoreChromeOS> store,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : DeviceCloudPolicyManagerChromeOS(std::move(store), task_runner, NULL),
+    : DeviceCloudPolicyManagerChromeOS(
+          std::move(store),
+          std::make_unique<MockCloudExternalDataManager>(),
+          task_runner,
+          nullptr),
       unregister_result_(true) {}
 
 FakeDeviceCloudPolicyManager::~FakeDeviceCloudPolicyManager() {
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc
index 2d6c4ed..8dcb5b60 100644
--- a/chrome/browser/devtools/device/android_device_manager.cc
+++ b/chrome/browser/devtools/device/android_device_manager.cc
@@ -540,9 +540,10 @@
   if (!thread_)
     return;
   // Shut down thread on a thread other than UI so it can join a thread.
-  base::PostTaskWithTraits(FROM_HERE,
-                           {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
-                           base::BindOnce(&HandlerThread::StopThread, thread_));
+  base::PostTaskWithTraits(
+      FROM_HERE,
+      {base::WithBaseSyncPrimitives(), base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&HandlerThread::StopThread, thread_));
 }
 
 // static
diff --git a/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc b/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc
index 4f51938..6c46349 100644
--- a/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc
+++ b/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/service_manager_connection.h"
+#include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "services/device/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 
@@ -162,7 +163,9 @@
   DCHECK(device_manager_);
   device_manager_->GetDevices(
       /*options=*/nullptr,
-      base::BindOnce(&GetAndroidDeviceInfoList, std::move(callback)));
+      mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+          base::BindOnce(&GetAndroidDeviceInfoList, std::move(callback)),
+          std::vector<device::mojom::UsbDeviceInfoPtr>()));
 }
 
 void UsbDeviceManagerHelper::GetDevice(
@@ -206,10 +209,12 @@
   EnsureUsbDeviceManagerConnection();
 
   DCHECK(device_manager_);
+  auto countCb = base::BindOnce(&CountAndroidDevices, std::move(callback));
   device_manager_->GetDevices(
-      /*options=*/nullptr, base::BindOnce(&GetAndroidDeviceInfoList,
-                                          base::BindOnce(&CountAndroidDevices,
-                                                         std::move(callback))));
+      /*options=*/nullptr,
+      mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+          base::BindOnce(&GetAndroidDeviceInfoList, std::move(countCb)),
+          std::vector<device::mojom::UsbDeviceInfoPtr>()));
 }
 
 void UsbDeviceManagerHelper::SetUsbManagerForTestingInternal(
@@ -221,7 +226,5 @@
 
 void UsbDeviceManagerHelper::OnDeviceManagerConnectionError() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  // TODO(donna.wu@intel.com): finish ongoing count/enumerate requests with some
-  // result for the connection error cases.
   device_manager_.reset();
 }
diff --git a/chrome/browser/devtools/device/usb/usb_device_manager_helper.h b/chrome/browser/devtools/device/usb/usb_device_manager_helper.h
index f8b43c3..d180043 100644
--- a/chrome/browser/devtools/device/usb/usb_device_manager_helper.h
+++ b/chrome/browser/devtools/device/usb/usb_device_manager_helper.h
@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "base/threading/thread_checker.h"
-#include "chrome/browser/devtools/device/usb/usb_device_manager_helper.h"
 #include "device/usb/public/mojom/device.mojom.h"
 #include "device/usb/public/mojom/device_manager.mojom.h"
 
@@ -39,8 +38,6 @@
   int zero_mask = 0;
 };
 
-using AndroidInterfaceInfoListCallback =
-    base::OnceCallback<void(std::vector<AndroidInterfaceInfo>)>;
 using AndroidDeviceInfoListCallback =
     base::OnceCallback<void(std::vector<AndroidDeviceInfo>)>;
 
diff --git a/chrome/browser/engagement/site_engagement_service_factory.cc b/chrome/browser/engagement/site_engagement_service_factory.cc
index 347face..df722d6 100644
--- a/chrome/browser/engagement/site_engagement_service_factory.cc
+++ b/chrome/browser/engagement/site_engagement_service_factory.cc
@@ -15,7 +15,16 @@
 SiteEngagementService* SiteEngagementServiceFactory::GetForProfile(
     Profile* profile) {
   return static_cast<SiteEngagementService*>(
-      GetInstance()->GetServiceForBrowserContext(profile, true));
+      GetInstance()->GetServiceForBrowserContext(profile,
+                                                 /*create_service=*/true));
+}
+
+// static
+SiteEngagementService* SiteEngagementServiceFactory::GetForProfileIfExists(
+    Profile* profile) {
+  return static_cast<SiteEngagementService*>(
+      GetInstance()->GetServiceForBrowserContext(profile,
+                                                 /*create_service=*/false));
 }
 
 // static
diff --git a/chrome/browser/engagement/site_engagement_service_factory.h b/chrome/browser/engagement/site_engagement_service_factory.h
index f16923f..458b3de 100644
--- a/chrome/browser/engagement/site_engagement_service_factory.h
+++ b/chrome/browser/engagement/site_engagement_service_factory.h
@@ -22,6 +22,7 @@
 class SiteEngagementServiceFactory : public BrowserContextKeyedServiceFactory {
  public:
   static SiteEngagementService* GetForProfile(Profile* profile);
+  static SiteEngagementService* GetForProfileIfExists(Profile* profile);
 
   static SiteEngagementServiceFactory* GetInstance();
 
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index efda74fb..ad35f9e5 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/engagement/site_engagement_metrics.h"
 #include "chrome/browser/engagement/site_engagement_observer.h"
 #include "chrome/browser/engagement/site_engagement_score.h"
+#include "chrome/browser/engagement/site_engagement_service_factory.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
@@ -169,6 +170,12 @@
     HistoryServiceFactory::GetInstance()->SetTestingFactory(
         profile(), base::BindRepeating(&BuildTestHistoryService));
     SiteEngagementScore::SetParamValuesForTesting();
+
+    // Ensure that we have just one SiteEngagementService: no service created
+    // with TestingProfile.
+    // (See KeyedServiceBaseFactory::ServiceIsCreatedWithContext).
+    DCHECK(!SiteEngagementServiceFactory::GetForProfileIfExists(profile()));
+
     service_ = base::WrapUnique(new SiteEngagementService(profile(), &clock_));
   }
 
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index 692805f..cb340247 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -181,7 +181,7 @@
   CreateTestExtension();
   ProfileSyncServiceFactory::GetForProfile(browser()->profile())
       ->GetLocalDeviceInfoProviderForTest()
-      ->Initialize(kTestCacheGuid, "machine name", "device_id");
+      ->Initialize(kTestCacheGuid, "machine name");
 }
 
 void ExtensionSessionsTest::CreateTestExtension() {
diff --git a/chrome/browser/extensions/extension_fullscreen_apitest.cc b/chrome/browser/extensions/extension_fullscreen_apitest.cc
index e5d5d4ad..dac6cf4 100644
--- a/chrome/browser/extensions/extension_fullscreen_apitest.cc
+++ b/chrome/browser/extensions/extension_fullscreen_apitest.cc
@@ -7,6 +7,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
+#include "ui/base/ui_base_features.h"
 
 namespace extensions {
 
@@ -70,6 +71,9 @@
 
 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
                        MAYBE_DisplayModeWindowIsInFullscreen) {
+  // TODO(crbug.com/897879): this test is flaky.
+  if (features::IsSingleProcessMash())
+    return;
   ASSERT_TRUE(RunPlatformAppTest("fullscreen/mq_display_mode")) << message_;
 }
 
diff --git a/chrome/browser/favicon/favicon_utils.cc b/chrome/browser/favicon/favicon_utils.cc
index ab5f635..202f9645 100644
--- a/chrome/browser/favicon/favicon_utils.cc
+++ b/chrome/browser/favicon/favicon_utils.cc
@@ -42,27 +42,28 @@
 }
 
 bool ShouldDisplayFavicon(content::WebContents* web_contents) {
-  // No favicon on interstitials. This check must be done first since
-  // interstitial navigations don't commit and always have a pending entry.
+  // No favicon on interstitials.
   if (web_contents->ShowingInterstitialPage())
     return false;
 
-  // Always display a throbber during pending loads.
-  const content::NavigationController& controller =
-      web_contents->GetController();
-  if (controller.GetLastCommittedEntry() && controller.GetPendingEntry())
-    return true;
-
-  GURL url = web_contents->GetURL();
+  // Suppress the icon for the new-tab page, even if a navigation to it is
+  // not committed yet. Note that we're looking at the visible URL, so
+  // navigations from NTP generally don't hit this case and still show an icon.
+  GURL url = web_contents->GetVisibleURL();
   if (url.SchemeIs(content::kChromeUIScheme) &&
       url.host_piece() == chrome::kChromeUINewTabHost) {
     return false;
   }
 
-  // No favicon on Instant New Tab Pages.
-  if (search::IsInstantNTP(web_contents))
+  // Also suppress instant-NTP. This does not use search::IsInstantNTP since
+  // it looks at the last-committed entry and we need to show icons for pending
+  // navigations away from it.
+  if (search::IsInstantNTPURL(url, Profile::FromBrowserContext(
+                                       web_contents->GetBrowserContext()))) {
     return false;
+  }
 
+  // Otherwise, always display the favicon.
   return true;
 }
 
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 5a28d60..e30b515f 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -867,7 +867,7 @@
   if (startup_watchdog->IsJoinable()) {
     // Allow the watchdog thread to shutdown on UI. Watchdog thread shutdowns
     // very fast.
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_thread_join;
     delete startup_watchdog;
     return;
   }
diff --git a/chrome/browser/navigation_predictor/navigation_predictor.cc b/chrome/browser/navigation_predictor/navigation_predictor.cc
index f934214..186c55a 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor.cc
@@ -25,6 +25,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "third_party/blink/public/common/features.h"
 #include "url/gurl.h"
+#include "url/url_canon.h"
 
 namespace {
 
@@ -36,6 +37,19 @@
   return rfh->GetParent() == nullptr;
 }
 
+std::string GetURLWithoutRefParams(const GURL& gurl) {
+  url::Replacements<char> replacements;
+  replacements.ClearRef();
+  return gurl.ReplaceComponents(replacements).spec();
+}
+
+// Returns true if |a| and |b| are both valid HTTP/HTTPS URLs and have the
+// same scheme, host, path and query params. This method does not take into
+// account the ref params of the two URLs.
+bool AreGURLsEqualExcludingRefParams(const GURL& a, const GURL& b) {
+  return GetURLWithoutRefParams(a) == GetURLWithoutRefParams(b);
+}
+
 }  // namespace
 
 struct NavigationPredictor::NavigationScore {
@@ -457,9 +471,13 @@
 
   for (auto& metric : *metrics) {
     // Do not include anchor elements that point to the same URL as the URL of
-    // the current navigation since these are unlikely to be clicked.
-    if (metric->target_url == metric->source_url)
+    // the current navigation since these are unlikely to be clicked. Also,
+    // exclude the anchor elements that differ from the URL of the current
+    // navigation by only the ref param.
+    if (AreGURLsEqualExcludingRefParams(metric->target_url,
+                                        metric->source_url)) {
       continue;
+    }
 
     if (!metric->target_url.SchemeIsCryptographic())
       continue;
@@ -470,7 +488,10 @@
     if (metric->is_in_iframe)
       continue;
 
-    const std::string& key = metric->target_url.spec();
+    // Skip ref params when merging the anchor elements. This ensures that two
+    // anchor elements which differ only in the ref params are combined
+    // together.
+    const std::string& key = GetURLWithoutRefParams(metric->target_url);
     auto iter = metrics_map.find(key);
     if (iter == metrics_map.end()) {
       metrics_map[key] = std::move(metric);
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
index 62f329d..aa3c4753 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_browsertest.cc
@@ -104,7 +104,7 @@
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
-      "AnchorElementMetrics.Visible.NumberOfAnchorElements", 3, 1);
+      "AnchorElementMetrics.Visible.NumberOfAnchorElements", 5, 1);
   // Same document anchor element should be removed after merge.
   histogram_tester.ExpectUniqueSample(
       "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge", 2, 1);
@@ -605,7 +605,7 @@
   base::RunLoop().RunUntilIdle();
 
   histogram_tester.ExpectUniqueSample(
-      "AnchorElementMetrics.Visible.NumberOfAnchorElements", 3, 1);
+      "AnchorElementMetrics.Visible.NumberOfAnchorElements", 5, 1);
   // Same document anchor element should be removed after merge.
   histogram_tester.ExpectUniqueSample(
       "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge", 2, 1);
diff --git a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
index 770435b..8ca5256 100644
--- a/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
+++ b/chrome/browser/navigation_predictor/navigation_predictor_unittest.cc
@@ -239,6 +239,97 @@
       "AnchorElementMetrics.Visible.HighestNavigationScore", 0);
 }
 
+TEST_F(NavigationPredictorTest, Merge_UniqueAnchorElements) {
+  base::HistogramTester histogram_tester;
+
+  const std::string source = "https://example.com";
+  const std::string href_xlarge = "https://example.com/xlarge";
+  const std::string href_large = "https://google.com/large";
+  const std::string href_medium = "https://google.com/medium";
+  const std::string href_small = "https://google.com/small";
+  const std::string href_xsmall = "https://google.com/xsmall";
+
+  std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
+  metrics.push_back(CreateMetricsPtr(source, href_xsmall, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_large, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_xlarge, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_small, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_medium, 0.01));
+
+  int number_of_metrics_sent = metrics.size();
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElements",
+      number_of_metrics_sent, 1);
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge",
+      number_of_metrics_sent, 1);
+}
+
+TEST_F(NavigationPredictorTest, Merge_DuplicateAnchorElements) {
+  base::HistogramTester histogram_tester;
+
+  const std::string source = "https://example.com";
+  const std::string href = "https://example.com/xlarge";
+  // URLs that differ only in ref fragments should be merged.
+  const std::string href_ref_1 = "https://example.com/xlarge#";
+  const std::string href_ref_2 = "https://example.com/xlarge#ref_foo";
+  const std::string href_query_1 = "https://example.com/xlarge?q=foo";
+  const std::string href_query_ref = "https://example.com/xlarge?q=foo#ref_bar";
+
+  std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
+  metrics.push_back(CreateMetricsPtr(source, href, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_ref_1, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_ref_2, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_query_1, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_query_ref, 0.01));
+
+  int number_of_metrics_sent = metrics.size();
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElements",
+      number_of_metrics_sent, 1);
+
+  // Only two anchor elements are unique: |href| and |href_query_1|.
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge", 2, 1);
+}
+
+TEST_F(NavigationPredictorTest, Merge_AnchorElementSameAsDocumentURL) {
+  base::HistogramTester histogram_tester;
+
+  const std::string source = "https://example.com/";
+  const std::string href = "https://example.com/";
+  // URLs that differ only in ref fragments should be merged.
+  const std::string href_ref_1 = "https://example.com/#ref=foo";
+  const std::string href_ref_2 = "https://example.com/xlarge#ref=foo";
+  const std::string href_query_1 = "https://example.com/xlarge?q=foo";
+  const std::string href_query_ref = "https://example.com/xlarge?q=foo#ref_bar";
+
+  std::vector<blink::mojom::AnchorElementMetricsPtr> metrics;
+  metrics.push_back(CreateMetricsPtr(source, href, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_ref_1, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_ref_2, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_query_1, 0.01));
+  metrics.push_back(CreateMetricsPtr(source, href_query_ref, 0.01));
+
+  int number_of_metrics_sent = metrics.size();
+  predictor_service()->ReportAnchorElementMetricsOnLoad(std::move(metrics));
+  base::RunLoop().RunUntilIdle();
+
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElements",
+      number_of_metrics_sent, 1);
+  // Only two anchor elements are unique and different from the document URL:
+  // |href_ref_2| and |href_query_1|.
+  histogram_tester.ExpectUniqueSample(
+      "AnchorElementMetrics.Visible.NumberOfAnchorElementsAfterMerge", 2, 1);
+}
+
 // In this test, multiple anchor element metrics are sent to
 // ReportAnchorElementMetricsOnLoad. Test that CalculateAnchorNavigationScore
 // works, and that highest navigation score can be recorded correctly.
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc
index 3abe4c9..0e9ed4b 100644
--- a/chrome/browser/password_manager/password_manager_browsertest.cc
+++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -5,6 +5,7 @@
 #include <string>
 #include <utility>
 
+#include "base/cfi_buildflags.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
@@ -1128,7 +1129,15 @@
   EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
 }
 
-IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
+// https://crbug.com/916413 tracks test flakiness on chromium.memory/Linux CFI
+#if BUILDFLAG(CFI_CAST_CHECK) || BUILDFLAG(CFI_ICALL_CHECK) || \
+    BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC) || BUILDFLAG(CFI_ENFORCEMENT_TRAP)
+#define MAYBE_DeleteFrameBeforeSubmit DISABLED_DeleteFrameBeforeSubmit
+#else
+#define MAYBE_DeleteFrameBeforeSubmit DeleteFrameBeforeSubmit
+#endif
+IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
+                       MAYBE_DeleteFrameBeforeSubmit) {
   NavigateToFile("/password/multi_frames.html");
 
   NavigationObserver observer(WebContents());
diff --git a/chrome/browser/printing/printer_query.cc b/chrome/browser/printing/printer_query.cc
index cc23687..09f8e164 100644
--- a/chrome/browser/printing/printer_query.cc
+++ b/chrome/browser/printing/printer_query.cc
@@ -136,7 +136,7 @@
     // http://crbug.com/66082: We're blocking on the PrinterQuery's worker
     // thread.  It's not clear to me if this may result in blocking the current
     // thread for an unacceptable time.  We should probably fix it.
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_thread_join;
     worker_->Stop();
     worker_.reset();
   }
diff --git a/chrome/browser/resources/app_management/BUILD.gn b/chrome/browser/resources/app_management/BUILD.gn
index 9a5fb5b..c67292d 100644
--- a/chrome/browser/resources/app_management/BUILD.gn
+++ b/chrome/browser/resources/app_management/BUILD.gn
@@ -31,6 +31,15 @@
     ]
   }
 
+  js_library("api_listener") {
+    deps = [
+      ":actions",
+      ":store",
+      ":util",
+      "//ui/webui/resources/js:cr",
+    ]
+  }
+
   js_library("app") {
     deps = [
       ":actions",
diff --git a/chrome/browser/resources/app_management/api_listener.html b/chrome/browser/resources/app_management/api_listener.html
new file mode 100644
index 0000000..99295bb
--- /dev/null
+++ b/chrome/browser/resources/app_management/api_listener.html
@@ -0,0 +1,5 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://apps/actions.html">
+<link rel="import" href="chrome://apps/store.html">
+<link rel="import" href="chrome://apps/util.html">
+<script src="chrome://apps/api_listener.js"></script>
diff --git a/chrome/browser/resources/app_management/api_listener.js b/chrome/browser/resources/app_management/api_listener.js
new file mode 100644
index 0000000..5facd053
--- /dev/null
+++ b/chrome/browser/resources/app_management/api_listener.js
@@ -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.
+cr.define('app_management.ApiListener', function() {
+  let initialized = false;
+
+  function init() {
+    assert(!initialized);
+    app_management.BrowserProxy.getInstance().handler.getApps();
+    const callbackRouter =
+        app_management.BrowserProxy.getInstance().callbackRouter;
+
+    app_management.Store.getInstance().init(
+        app_management.util.createEmptyState());
+
+    callbackRouter.onAppsAdded.addListener(onAppsAdded.bind(this));
+    callbackRouter.onAppChanged.addListener(onAppChanged.bind(this));
+    callbackRouter.onAppRemoved.addListener(onAppRemoved.bind(this));
+    initialized = true;
+  }
+
+  /**
+   * @param {cr.ui.Action} action
+   */
+  function dispatch(action) {
+    app_management.Store.getInstance().dispatch(action);
+  }
+
+  /**
+   * @param {Array<appManagement.mojom.App>} apps
+   */
+  function onAppsAdded(apps) {
+    dispatch(app_management.actions.addApps(apps));
+  }
+
+  /**
+   * @param {appManagement.mojom.App} app
+   */
+  function onAppChanged(app) {
+    dispatch(app_management.actions.changeApp(app));
+  }
+
+  /**
+   * @param {string} appId
+   */
+  function onAppRemoved(appId) {
+    dispatch(app_management.actions.removeApp(appId));
+  }
+
+  init();
+});
diff --git a/chrome/browser/resources/app_management/app.html b/chrome/browser/resources/app_management/app.html
index a0a278d..0de08c2 100644
--- a/chrome/browser/resources/app_management/app.html
+++ b/chrome/browser/resources/app_management/app.html
@@ -7,7 +7,8 @@
 <link rel="import" href="chrome://apps/pwa_permission_view.html">
 <link rel="import" href="chrome://apps/store.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
+
+<link rel="import" href="chrome://apps/api_listener.html">
 
 <dom-module id="app-management-app">
   <template>
diff --git a/chrome/browser/resources/app_management/app.js b/chrome/browser/resources/app_management/app.js
index 8fcb3ec..e9914c25 100644
--- a/chrome/browser/resources/app_management/app.js
+++ b/chrome/browser/resources/app_management/app.js
@@ -4,56 +4,4 @@
 
 Polymer({
   is: 'app-management-app',
-
-  /** @override */
-  attached: function() {
-    app_management.BrowserProxy.getInstance().handler.getApps();
-    const callbackRouter =
-        app_management.BrowserProxy.getInstance().callbackRouter;
-
-    app_management.Store.getInstance().init(
-        app_management.util.createEmptyState());
-    this.listenerIds_ = [
-      callbackRouter.onAppsAdded.addListener(this.onAppsAdded.bind(this)),
-      callbackRouter.onAppChanged.addListener(this.onAppChanged.bind(this)),
-      callbackRouter.onAppRemoved.addListener(this.onAppRemoved.bind(this)),
-    ];
-  },
-
-  detached: function() {
-    const callbackRouter =
-        app_management.BrowserProxy.getInstance().callbackRouter;
-    this.listenerIds_.forEach((id) => callbackRouter.removeListener(id));
-  },
-
-  /**
-   * @param {cr.ui.Action} action
-   */
-  dispatch: function(action) {
-    app_management.Store.getInstance().dispatch(action);
-  },
-
-  /**
-   * @param {Array<appManagement.mojom.App>} apps
-   */
-  onAppsAdded: function(apps) {
-    const action = app_management.actions.addApps(apps);
-    this.dispatch(action);
-  },
-
-  /**
-   * @param {appManagement.mojom.App} app
-   */
-  onAppChanged: function(app) {
-    const action = app_management.actions.changeApp(app);
-    this.dispatch(action);
-  },
-
-  /**
-   * @param {string} appId
-   */
-  onAppRemoved: function(appId) {
-    const action = app_management.actions.removeApp(appId);
-    this.dispatch(action);
-  },
 });
diff --git a/chrome/browser/resources/app_management/browser_proxy.html b/chrome/browser/resources/app_management/browser_proxy.html
index 8667e7b0..36658bd50 100644
--- a/chrome/browser/resources/app_management/browser_proxy.html
+++ b/chrome/browser/resources/app_management/browser_proxy.html
@@ -1,6 +1,4 @@
 <link rel="import" href="chrome://resources/html/cr.html">
-<script src="browser_proxy.js"></script>
-<script src="fake_page_handler.js"></script>
 <script src="chrome://resources/js/mojo_bindings_lite.js"></script>
 <script src="big_buffer.mojom-lite.js"></script>
 <script src="image_info.mojom-lite.js"></script>
@@ -8,3 +6,6 @@
 <script src="image.mojom-lite.js"></script>
 <script src="types.mojom-lite.js"></script>
 <script src="app_management.mojom-lite.js"></script>
+
+<script src="browser_proxy.js"></script>
+<script src="fake_page_handler.js"></script>
diff --git a/chrome/browser/resources/app_management/browser_proxy.js b/chrome/browser/resources/app_management/browser_proxy.js
index 9876c58..e034dc3 100644
--- a/chrome/browser/resources/app_management/browser_proxy.js
+++ b/chrome/browser/resources/app_management/browser_proxy.js
@@ -16,6 +16,20 @@
       if (useFake) {
         this.handler = new app_management.FakePageHandler(
             this.callbackRouter.createProxy());
+        const /** @type {!Array<appManagement.mojom.App>}*/ appList = [
+          app_management.FakePageHandler.createApp(
+              'ahfgeienlihckogmohjhadlkjgocpleb'),
+          app_management.FakePageHandler.createApp(
+              'aohghmighlieiainnegkcijnfilokake',
+              {type: apps.mojom.AppType.kArc}),
+          app_management.FakePageHandler.createApp(
+              'blpcfgokakmgnkcojhhkbfbldkacnbeo'),
+          app_management.FakePageHandler.createApp(
+              'pjkljhegncpnkpknbcohdijeoejaedia'),
+          app_management.FakePageHandler.createApp(
+              'aapocclcgogkmnckokdopfmhonfmgoek'),
+        ];
+        this.handler.setApps(appList);
       } else {
         this.handler = new appManagement.mojom.PageHandlerProxy();
         const factory = appManagement.mojom.PageHandlerFactory.getProxy();
diff --git a/chrome/browser/resources/app_management/fake_page_handler.js b/chrome/browser/resources/app_management/fake_page_handler.js
index 2d8122ff..742c3ad4 100644
--- a/chrome/browser/resources/app_management/fake_page_handler.js
+++ b/chrome/browser/resources/app_management/fake_page_handler.js
@@ -10,15 +10,7 @@
       this.page = page;
 
       /** @type {!Array<appManagement.mojom.App>} */
-      this.apps_ = [
-        FakePageHandler.createApp('ahfgeienlihckogmohjhadlkjgocpleb'),
-        FakePageHandler.createApp(
-            'aohghmighlieiainnegkcijnfilokake',
-            {type: apps.mojom.AppType.kArc}),
-        FakePageHandler.createApp('blpcfgokakmgnkcojhhkbfbldkacnbeo'),
-        FakePageHandler.createApp('pjkljhegncpnkpknbcohdijeoejaedia'),
-        FakePageHandler.createApp('aapocclcgogkmnckokdopfmhonfmgoek'),
-      ];
+      this.apps_ = [];
     }
 
     getApps() {
@@ -31,17 +23,25 @@
      * @return {!appManagement.mojom.App}
      */
     static createApp(id, config) {
-      const app = /** @type {!appManagement.mojom.App} */ ({
+      const app = {
         id: id,
         type: apps.mojom.AppType.kUnknown,
         title: 'App Title',
         isPinned: apps.mojom.OptionalBool.kUnknown,
-      });
+      };
+
       if (config)
         Object.assign(app, config);
 
       return app;
     }
+
+    /**
+     * @param {!Array<appManagement.mojom.App>} appList
+     */
+    setApps(appList) {
+      this.apps_ = appList;
+    }
   }
 
   return {FakePageHandler: FakePageHandler};
diff --git a/chrome/browser/resources/app_management/main_view.html b/chrome/browser/resources/app_management/main_view.html
index 241a5b30..8e69768 100644
--- a/chrome/browser/resources/app_management/main_view.html
+++ b/chrome/browser/resources/app_management/main_view.html
@@ -8,7 +8,6 @@
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
 <link rel="import" href="chrome://resources/html/icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 
 <dom-module id="app-management-main-view">
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index cd45ee1..326fb0ae 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -119,6 +119,8 @@
         <include name="IDR_PDF_VIEWER_BOOKMARKS_CONTENT_JS" file="pdf/elements/viewer-bookmarks-content/viewer-bookmarks-content.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_ERROR_SCREEN_HTML" file="pdf/elements/viewer-error-screen/viewer-error-screen.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_ERROR_SCREEN_JS" file="pdf/elements/viewer-error-screen/viewer-error-screen.js" type="BINDATA" />
+        <include name="IDR_PDF_VIEWER_INK_HOST_HTML" file="pdf/elements/viewer-ink-host/viewer-ink-host.html" type="BINDATA" />
+        <include name="IDR_PDF_VIEWER_INK_HOST_JS" file="pdf/elements/viewer-ink-host/viewer-ink-host.js" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_HTML" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.html" type="BINDATA" />
         <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_JS" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.js" type="BINDATA" flattenhtml="true" />
         <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_HTML" file="pdf/elements/viewer-page-selector/viewer-page-selector.html" type="BINDATA" />
diff --git a/chrome/browser/resources/md_history/synced_device_manager.js b/chrome/browser/resources/md_history/synced_device_manager.js
index 62ec34e..0aa5228 100644
--- a/chrome/browser/resources/md_history/synced_device_manager.js
+++ b/chrome/browser/resources/md_history/synced_device_manager.js
@@ -285,8 +285,13 @@
    * Get called when user's sign in state changes, this will affect UI of synced
    * tabs page. Sign in promo gets displayed when user is signed out, and
    * different messages are shown when there are no synced tabs.
+   * @param {?boolean} current
+   * @param {?boolean} previous
    */
-  signInStateChanged_: function() {
+  signInStateChanged_: function(current, previous) {
+    if (previous === undefined)
+      return;
+
     this.fire('history-view-changed');
 
     // User signed out, clear synced device list and show the sign in promo.
diff --git a/chrome/browser/resources/omnibox/omnibox_output.js b/chrome/browser/resources/omnibox/omnibox_output.js
index 2a6a31c..9c04063 100644
--- a/chrome/browser/resources/omnibox/omnibox_output.js
+++ b/chrome/browser/resources/omnibox/omnibox_output.js
@@ -291,7 +291,7 @@
       this.matches.forEach(this.appendChild.bind(this));
     }
 
-    /** @return {string} */
+    /** @return {?string} */
     get innerHeaderText() {
       return this.matches[0].providerName;
     }
@@ -319,8 +319,8 @@
     set match(match) {
       /** @type {!Object} */
       this.properties = {};
-      /** @type {string} */
-      this.providerName = match.providerName;
+      /** @type {?string} */
+      this.providerName = match.providerName || null;
 
       COLUMNS.forEach(column => {
         const values = column.sourceProperties.map(
diff --git a/chrome/browser/resources/pdf/BUILD.gn b/chrome/browser/resources/pdf/BUILD.gn
index 9ad96cd1..547be3d9 100644
--- a/chrome/browser/resources/pdf/BUILD.gn
+++ b/chrome/browser/resources/pdf/BUILD.gn
@@ -10,6 +10,7 @@
     ":pdf_resources",
     "elements/viewer-bookmark:closure_compile",
     "elements/viewer-error-screen:closure_compile",
+    "elements/viewer-ink-host:closure_compile",
     "elements/viewer-page-indicator:closure_compile",
     "elements/viewer-page-selector:closure_compile",
     "elements/viewer-password-screen:closure_compile",
diff --git a/chrome/browser/resources/pdf/elements/viewer-ink-host/BUILD.gn b/chrome/browser/resources/pdf/elements/viewer-ink-host/BUILD.gn
new file mode 100644
index 0000000..57ae6968
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-ink-host/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+  deps = [
+    ":viewer-ink-host",
+  ]
+}
+
+js_library("viewer-ink-host") {
+}
diff --git a/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.html b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.html
new file mode 100644
index 0000000..3337192
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.html
@@ -0,0 +1,13 @@
+<link rel="import" href="chrome://resources/html/polymer.html">
+
+<dom-module id="viewer-ink-host">
+  <template>
+    <style>
+      :host {
+        visibility: hidden;
+      }
+    </style>
+    [[dummyContent_]]
+  </template>
+  <script src="viewer-ink-host.js"></script>
+</dom-module>
diff --git a/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
new file mode 100644
index 0000000..9b77b74
--- /dev/null
+++ b/chrome/browser/resources/pdf/elements/viewer-ink-host/viewer-ink-host.js
@@ -0,0 +1,49 @@
+// 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.
+
+/**
+ * Hosts the Ink component which is responsible for both PDF rendering and
+ * annotation when in annotation mode.
+ */
+Polymer({
+  is: 'viewer-ink-host',
+
+  properties: {
+    /** @private */
+    dummyContent_: String,
+  },
+
+  /** @private {?string} */
+  dummyFileName_: null,
+
+  /** @private {ArrayBuffer} */
+  dummyData_: null,
+
+  /**
+   * Begins annotation mode with the document represented by `data`.
+   * When the return value resolves the Ink component will be ready
+   * to render immediately.
+   *
+   * @param {string} fileName The name of the PDF file.
+   * @param {ArrayBuffer} data The contents of the PDF document.
+   * @return {!Promise} void value.
+   */
+  load: async function(fileName, data) {
+    this.dummyContent_ = `Annotating ${data.byteLength} bytes`;
+    this.dummyFileName_ = fileName;
+    this.dummyData_ = data;
+    this.style.visibility = 'visible';
+  },
+
+  /**
+   * @return {!Promise<{fileName: string, dataToSave: ArrayBuffer}>}
+   *     The serialized PDF document including any annotations that were made.
+   */
+  saveDocument: async function() {
+    return {
+      fileName: this.dummyFileName_,
+      dataToSave: this.dummyData_,
+    };
+  },
+});
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
index 964ec04..5eda02d 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.html
@@ -125,6 +125,7 @@
         <div id="buttons" class="invisible">
           <template is="dom-if" if="[[pdfAnnotationsEnabled]]">
             <paper-icon-button id="annotate" icon="pdf:create"
+                on-click="toggleAnnotation"
                 aria-label$="{{strings.tooltipAnnotate}}"
                 title$="{{strings.tooltipAnnotate}}">
             </paper-icon-button>
@@ -160,7 +161,7 @@
         </div>
       </div>
       <div id="progress-container">
-        <paper-progress id="progress" value="{{loadProgress}}"></paper-progress>
+        <paper-progress id="progress" value="[[loadProgress]]"></paper-progress>
       </div>
     </div>
   </template>
diff --git a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
index 62edf11..cb63eeec 100644
--- a/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
+++ b/chrome/browser/resources/pdf/elements/viewer-pdf-toolbar/viewer-pdf-toolbar.js
@@ -9,7 +9,7 @@
     /**
      * The current loading progress of the PDF document (0 - 100).
      */
-    loadProgress: {type: Number, observer: 'loadProgressChanged'},
+    loadProgress: {type: Number, observer: 'loadProgressChanged_'},
 
     /**
      * The title of the PDF document.
@@ -37,6 +37,14 @@
     opened: {type: Boolean, value: true},
 
     /**
+     * Whether the viewer is currently in annotation mode.
+     */
+    annotationMode: {
+      type: Boolean,
+      notify: true,
+    },
+
+    /**
      * Whether the PDF Annotations feature is enabled.
      */
     pdfAnnotationsEnabled: Boolean,
@@ -44,11 +52,18 @@
     strings: Object,
   },
 
-  loadProgressChanged: function() {
-    if (this.loadProgress >= 100) {
-      this.$.pageselector.classList.toggle('invisible', false);
-      this.$.buttons.classList.toggle('invisible', false);
-      this.$.progress.style.opacity = 0;
+  /**
+   * @param {number} newProgress
+   * @param {number} oldProgress
+   * @private
+   */
+  loadProgressChanged_: function(newProgress, oldProgress) {
+    const loaded = newProgress >= 100;
+    const progressReset = newProgress < oldProgress;
+    if (progressReset || loaded) {
+      this.$.pageselector.classList.toggle('invisible', !loaded);
+      this.$.buttons.classList.toggle('invisible', !loaded);
+      this.$.progress.style.opacity = loaded ? 0 : 1;
     }
   },
 
@@ -126,6 +141,10 @@
 
   print: function() {
     this.fire('print');
+  },
+
+  toggleAnnotation: function() {
+    this.annotationMode = !this.annotationMode;
   }
 });
 })();
diff --git a/chrome/browser/resources/pdf/index.css b/chrome/browser/resources/pdf/index.css
index 6b3f217..35af88c 100644
--- a/chrome/browser/resources/pdf/index.css
+++ b/chrome/browser/resources/pdf/index.css
@@ -20,6 +20,7 @@
   z-index: 4;
 }
 
+viewer-ink-host,
 #plugin {
   height: 100%;
   position: fixed;
diff --git a/chrome/browser/resources/pdf/index.html b/chrome/browser/resources/pdf/index.html
index 102a6571..a14ae79 100644
--- a/chrome/browser/resources/pdf/index.html
+++ b/chrome/browser/resources/pdf/index.html
@@ -3,6 +3,7 @@
 <head>
   <meta charset="utf-8">
   <link rel="import" href="elements/viewer-error-screen/viewer-error-screen.html">
+  <link rel="import" href="elements/viewer-ink-host/viewer-ink-host.html">
   <link rel="import" href="elements/viewer-page-indicator/viewer-page-indicator.html">
   <link rel="import" href="elements/viewer-page-selector/viewer-page-selector.html">
   <link rel="import" href="elements/viewer-password-screen/viewer-password-screen.html">
@@ -38,6 +39,7 @@
 <script src="pdf_scripting_api.js"></script>
 <script src="chrome://resources/js/load_time_data.js"></script>
 <script src="chrome://resources/js/util.js"></script>
+<script src="chrome://resources/js/promise_resolver.js"></script>
 <script src="browser_api.js"></script>
 <script src="metrics.js"></script>
 <script src="pdf_viewer.js"></script>
diff --git a/chrome/browser/resources/pdf/pdf_viewer.js b/chrome/browser/resources/pdf/pdf_viewer.js
index ff4bb30..ed5cd49 100644
--- a/chrome/browser/resources/pdf/pdf_viewer.js
+++ b/chrome/browser/resources/pdf/pdf_viewer.js
@@ -125,9 +125,7 @@
   this.isFormFieldFocused_ = false;
   this.beepCount_ = 0;
   this.delayedScriptingMessages_ = [];
-
-  /** @private {!Set<string>} */
-  this.pendingTokens_ = new Set();
+  this.loaded_ = new PromiseResolver();
 
   this.isPrintPreview_ = location.origin === 'chrome://print';
   this.isPrintPreviewLoadingFinished_ = false;
@@ -220,10 +218,12 @@
   } else {
     this.plugin_.setAttribute('full-frame', '');
   }
+
   document.body.appendChild(this.plugin_);
 
   this.pluginController_ =
       new PluginController(this.plugin_, this, this.viewport_);
+  this.inkController_ = new InkController(this, this.viewport_);
   this.currentController_ = this.pluginController_;
 
   // Setup the button event listeners.
@@ -252,6 +252,8 @@
         'print', () => this.currentController_.print());
     this.toolbar_.addEventListener(
         'rotate-right', () => this.currentController_.rotateClockwise());
+    this.toolbar_.addEventListener(
+        'annotation-mode-changed', e => this.annotationModeChanged_(e));
 
     this.toolbar_.docTitle = getFilenameFromURL(this.originalUrl_);
   }
@@ -473,6 +475,52 @@
   },
 
   /**
+   * Handles the annotation mode being toggled on or off.
+   *
+   * @param {CustomEvent} e
+   * @private
+   */
+  annotationModeChanged_: async function(e) {
+    const annotationMode = e.detail.value;
+    if (annotationMode) {
+      // TODO(dstockwell): add assert lib and replace this with assert
+      if (this.currentController_ != this.pluginController_) {
+        throw new Error(
+            'Plugin controller is not current, cannot enter annotation mode');
+      }
+      // Enter annotation mode.
+      // TODO(dstockwell): set plugin read-only, begin transition
+      this.updateProgress(0);
+      // TODO(dstockwell): handle save failure
+      const result = await this.pluginController_.save(true);
+      // TODO(dstockwell): feed real progress data from the Ink component
+      this.updateProgress(50);
+      await this.inkController_.load(result.fileName, result.dataToSave);
+      this.currentController_ = this.inkController_;
+      this.pluginController_.unload();
+      this.updateProgress(100);
+    } else {
+      // Exit annotation mode.
+      // TODO(dstockwell): add assert lib and replace this with assert
+      if (this.currentController_ != this.inkController_) {
+        throw new Error(
+            'Ink controller is not current, cannot exit annotation mode');
+      }
+      // TODO(dstockwell): set ink read-only, begin transition
+      this.updateProgress(0);
+      // This runs separately to allow other consumers of `loaded` to queue
+      // up after this task.
+      this.loaded.then(() => {
+        this.currentController_ = this.pluginController_;
+        this.inkController_.unload();
+      });
+      // TODO(dstockwell): handle save failure
+      const result = await this.inkController_.save(true);
+      await this.pluginController_.load(result.fileName, result.dataToSave);
+    }
+  },
+
+  /**
    * Request to change the viewport fitting type.
    *
    * @param {CustomEvent} e Event received with the new FittingType as detail.
@@ -560,8 +608,40 @@
   },
 
   /**
+   * @return {Promise} Resolved when the load state reaches LOADED,
+   *     rejects on FAILED.
+   */
+  get loaded() {
+    return this.loaded_.promise;
+  },
+
+  /**
+   * Updates the load state and triggers completion of the `loaded`
+   * promise if necessary.
+   * @param {!LoadState} loadState
+   * @private
+   */
+  setLoadState_(loadState) {
+    if (this.loadState_ == loadState) {
+      return;
+    }
+    if ((loadState == LoadState.SUCCESS || loadState == LoadState.FAILURE) &&
+        this.loadState_ != LoadState.LOADING) {
+      throw new Error('Internal error: invalid loadState transition.');
+    }
+    this.loadState_ = loadState;
+    if (loadState == LoadState.SUCCESS) {
+      this.loaded_.resolve();
+    } else if (loadState == LoadState.FAILED) {
+      this.loaded_.reject();
+    } else {
+      this.loaded_ = new PromiseResolver();
+    }
+  },
+
+  /**
    * Update the loading progress of the document in response to a progress
-   * message being received from the plugin.
+   * message being received from the content controller.
    *
    * @param {number} progress the progress as a percentage.
    */
@@ -577,7 +657,7 @@
         this.passwordScreen_.deny();
         this.passwordScreen_.close();
       }
-      this.loadState_ = LoadState.FAILED;
+      this.setLoadState_(LoadState.FAILED);
       this.isPrintPreviewLoadingFinished_ = true;
       this.sendDocumentLoadedMessage_();
     } else if (progress == 100) {
@@ -586,12 +666,14 @@
         this.viewport_.position = this.lastViewportPosition_;
       this.paramsParser_.getViewportFromUrlParams(
           this.originalUrl_, this.handleURLParams_.bind(this));
-      this.loadState_ = LoadState.SUCCESS;
+      this.setLoadState_(LoadState.SUCCESS);
       this.sendDocumentLoadedMessage_();
       while (this.delayedScriptingMessages_.length > 0)
         this.handleScriptingMessage(this.delayedScriptingMessages_.shift());
 
       this.toolbarManager_.hideToolbarsAfterTimeout();
+    } else {
+      this.setLoadState_(LoadState.LOADING);
     }
   },
 
@@ -797,7 +879,7 @@
         this.pluginController_.postMessage(message.data);
         return true;
       case 'resetPrintPreviewMode':
-        this.loadState_ = LoadState.LOADING;
+        this.setLoadState_(LoadState.LOADING);
         if (!this.inPrintPreviewMode_) {
           this.inPrintPreviewMode_ = true;
           this.isUserInitiatedEvent_ = false;
@@ -1003,7 +1085,8 @@
    * Saves the current PDF document to disk.
    */
   save: async function() {
-    const result = await this.currentController_.save();
+    // TODO(dstockwell): Report an error to user if this fails.
+    const result = await this.currentController_.save(false);
     if (result == null) {
       // The content controller handled the save internally.
       return;
@@ -1057,10 +1140,77 @@
 
   /**
    * Requests that the current document be saved.
+   * @param {boolean} requireResult whether a response is required, otherwise
+   *     the controller may save the document to disk internally.
    * @return {Promise<{fileName: string, dataToSave: ArrayBuffer}}
    * @abstract
    */
-  save() {}
+  save(requireResult) {}
+
+  /**
+   * Loads PDF document from `data` activates UI.
+   * @param {string} fileName
+   * @param {ArrayBuffer} data
+   * @return {Promise<void>}
+   * @abstract
+   */
+  load(fileName, data) {}
+
+  /**
+   * Unloads the current document and removes the UI.
+   * @abstract
+   */
+  unload() {}
+}
+
+class InkController extends ContentController {
+  /**
+   * @param {PDFViewer} viewer
+   * @param {Viewport} viewport
+   */
+  constructor(viewer, viewport) {
+    super();
+    this.viewer_ = viewer;
+    this.viewport_ = viewport;
+
+    /** @type {ViewerInkHost} */
+    this.inkHost_ = null;
+  }
+
+  /** @override */
+  rotateClockwise() {
+    // TODO(dstockwell): implement rotation
+  }
+
+  /** @override */
+  rotateCounterClockwise() {
+    // TODO(dstockwell): implement rotation
+  }
+
+  /** @override */
+  print() {
+    // TODO(dstockwell): implement printing
+  }
+
+  /** @override */
+  save(requireResult) {
+    return this.inkHost_.saveDocument();
+  }
+
+  /** @override */
+  load(filename, data) {
+    if (!this.inkHost_) {
+      this.inkHost_ = document.createElement('viewer-ink-host');
+      document.body.appendChild(this.inkHost_);
+    }
+    return this.inkHost_.load(filename, data);
+  }
+
+  /** @override */
+  unload() {
+    this.inkHost_.remove();
+    this.inkHost_ = null;
+  }
 }
 
 class PluginController extends ContentController {
@@ -1075,7 +1225,7 @@
     this.viewer_ = viewer;
     this.viewport_ = viewport;
 
-    /** @private {!Map<string, Function>} */
+    /** @private {!Map<string, PromiseResolver>} */
     this.pendingTokens_ = new Map();
     this.plugin_.addEventListener(
         'message', e => this.handlePluginMessage_(e), false);
@@ -1162,13 +1312,30 @@
   }
 
   /** @override */
-  save() {
-    return new Promise(resolve => {
-      const newToken = createToken();
-      this.pendingTokens_.set(newToken, resolve);
-      const force = false;
-      this.postMessage({type: 'save', token: newToken});
-    });
+  save(requireResult) {
+    const resolver = new PromiseResolver();
+    const newToken = createToken();
+    this.pendingTokens_.set(newToken, resolver);
+    this.postMessage({type: 'save', token: newToken, force: requireResult});
+    return resolver.promise;
+  }
+
+  /** @override */
+  async load(fileName, data) {
+    const url = URL.createObjectURL(new Blob([data]));
+    this.plugin_.removeAttribute('headers');
+    this.plugin_.setAttribute('stream-url', url);
+    this.plugin_.style.display = 'block';
+    try {
+      await this.viewer_.loaded;
+    } finally {
+      URL.revokeObjectURL(url);
+    }
+  }
+
+  /** @override */
+  unload() {
+    this.plugin_.style.display = 'none';
   }
 
   /**
@@ -1250,15 +1417,21 @@
    * @private
    */
   saveData_(messageData) {
-    if (!(loadTimeData.getBoolean('pdfFormSaveEnabled')))
+    if (!(loadTimeData.getBoolean('pdfFormSaveEnabled') ||
+          loadTimeData.getBoolean('pdfAnnotationsEnabled')))
       throw new Error('Internal error: save not enabled.');
 
     // Verify a token that was created by this instance is included to avoid
     // being spammed.
-    const resolve = this.pendingTokens_.get(messageData.token);
+    const resolver = this.pendingTokens_.get(messageData.token);
     if (!this.pendingTokens_.delete(messageData.token))
       throw new Error('Internal error: save token not found, abort save.');
 
+    if (!messageData.dataToSave) {
+      resolver.reject();
+      return;
+    }
+
     // Verify the file size and the first bytes to make sure it's a PDF. Cap at
     // 100 MB. This cap should be kept in sync with and is also enforced in
     // pdf/out_of_process_instance.cc.
@@ -1275,6 +1448,6 @@
       throw new Error('Not a PDF file.');
     }
 
-    resolve(messageData);
+    resolver.resolve(messageData);
   }
 }
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 7eb7a3e..89b14a0 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -195,12 +195,11 @@
   init_params.network_connection_tracker =
       content::GetNetworkConnectionTracker();
   init_params.debug_identifier = profile->GetDebugName();
-  init_params.local_device_info_provider =
-      std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
-          chrome::GetChannel(), chrome::GetVersionString(),
-          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET);
 
   bool local_sync_backend_enabled = false;
+  syncer::LocalDeviceInfoProviderImpl::SigninScopedDeviceIdCallback
+      signin_scoped_device_id_callback;
+
 // Since the local sync backend is currently only supported on Windows don't
 // even check the pref on other os-es.
 #if defined(OS_WIN)
@@ -219,7 +218,7 @@
     if (local_sync_backend_folder.empty())
       return nullptr;
 
-    init_params.signin_scoped_device_id_callback =
+    signin_scoped_device_id_callback =
         base::BindRepeating([]() { return std::string("local_device"); });
 
     init_params.start_behavior = ProfileSyncService::AUTO_START;
@@ -238,11 +237,12 @@
 
     init_params.identity_manager =
         IdentityManagerFactory::GetForProfile(profile);
-    init_params.signin_scoped_device_id_callback =
-        base::BindRepeating(&GetSigninScopedDeviceIdForProfile, profile);
     init_params.gaia_cookie_manager_service =
         GaiaCookieManagerServiceFactory::GetForProfile(profile);
 
+    signin_scoped_device_id_callback =
+        base::BindRepeating(&GetSigninScopedDeviceIdForProfile, profile);
+
     bool use_fcm_invalidations =
         base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
     if (use_fcm_invalidations) {
@@ -276,6 +276,12 @@
                                      : ProfileSyncService::MANUAL_START;
   }
 
+  init_params.local_device_info_provider =
+      std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
+          chrome::GetChannel(), chrome::GetVersionString(),
+          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET,
+          signin_scoped_device_id_callback);
+
   auto pss = std::make_unique<ProfileSyncService>(std::move(init_params));
   pss->Initialize();
   return pss.release();
diff --git a/chrome/browser/sync/profile_sync_test_util.cc b/chrome/browser/sync/profile_sync_test_util.cc
index bfcba6a3..29739397 100644
--- a/chrome/browser/sync/profile_sync_test_util.cc
+++ b/chrome/browser/sync/profile_sync_test_util.cc
@@ -52,8 +52,6 @@
   ProfileSyncService::InitParams init_params;
 
   init_params.identity_manager = IdentityManagerFactory::GetForProfile(profile);
-  init_params.signin_scoped_device_id_callback =
-      base::BindRepeating([]() { return std::string(); });
   init_params.start_behavior = ProfileSyncService::MANUAL_START;
   init_params.sync_client = std::move(sync_client);
   init_params.network_time_update_callback = base::DoNothing();
@@ -75,7 +73,10 @@
   init_params.local_device_info_provider =
       std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
           chrome::GetChannel(), chrome::GetVersionString(),
-          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET);
+          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET,
+          /*signin_scoped_device_id_callback=*/base::BindRepeating([]() {
+            return std::string();
+          }));
 
   return init_params;
 }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 223ca97e..15266a3 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -490,6 +490,8 @@
     "//components/update_client",
     "//components/upload_list",
     "//components/url_formatter",
+    "//components/url_formatter/top_domains:common",
+    "//components/url_formatter/top_domains:generate_top_domains_for_edit_distance",
     "//components/user_manager",
     "//components/user_prefs",
     "//components/variations",
diff --git a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
index 4e16f2a..2ab22a18 100644
--- a/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
+++ b/chrome/browser/ui/app_list/search/arc/arc_playstore_search_result.cc
@@ -114,7 +114,7 @@
          crx_file::id_util::GenerateId(install_intent_uri().value()));
   SetDisplayType(ash::SearchResultDisplayType::kTile);
   SetBadgeIcon(CreateBadgeIcon(
-      is_instant_app() ? kIcBadgeInstantIcon : kIcBadgePlayIcon,
+      is_instant_app() ? kBadgeInstantIcon : kBadgePlayIcon,
       app_list::AppListConfig::instance().search_tile_badge_icon_dimension(),
       kBadgePadding, kBadgeIconSize, kBadgeColor));
   SetFormattedPrice(base::UTF8ToUTF16(formatted_price().value()));
diff --git a/chrome/browser/ui/app_list/search/omnibox_result.cc b/chrome/browser/ui/app_list/search/omnibox_result.cc
index 923e353..f52437e 100644
--- a/chrome/browser/ui/app_list/search/omnibox_result.cc
+++ b/chrome/browser/ui/app_list/search/omnibox_result.cc
@@ -90,7 +90,7 @@
     case AutocompleteMatchType::TAB_SEARCH_DEPRECATED:
     case AutocompleteMatchType::DOCUMENT_SUGGESTION:
     case AutocompleteMatchType::PEDAL:
-      return kIcDomainIcon;
+      return kDomainIcon;
 
     case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
     case AutocompleteMatchType::SEARCH_SUGGEST:
@@ -100,14 +100,14 @@
     case AutocompleteMatchType::SEARCH_OTHER_ENGINE:
     case AutocompleteMatchType::CONTACT_DEPRECATED:
     case AutocompleteMatchType::VOICE_SUGGEST:
-      return kIcSearchIcon;
+      return kSearchIcon;
 
     case AutocompleteMatchType::SEARCH_HISTORY:
     case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED:
-      return kIcHistoryIcon;
+      return kHistoryIcon;
 
     case AutocompleteMatchType::CALCULATOR:
-      return kIcEqualIcon;
+      return kEqualIcon;
 
     case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
     case AutocompleteMatchType::NUM_TYPES:
@@ -115,7 +115,7 @@
       break;
   }
   NOTREACHED();
-  return kIcDomainIcon;
+  return kDomainIcon;
 }
 
 }  // namespace
@@ -163,7 +163,7 @@
       bookmark_model && bookmark_model->IsBookmarked(match_.destination_url);
 
   const gfx::VectorIcon& icon =
-      is_bookmarked ? kIcBookmarkIcon : TypeToVectorIcon(match_.type);
+      is_bookmarked ? kBookmarkIcon : TypeToVectorIcon(match_.type);
   SetIcon(gfx::CreateVectorIcon(
       icon, AppListConfig::instance().search_list_icon_dimension(),
       kListIconColor));
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index e2567c6f..f117127 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -313,6 +313,7 @@
                        const GURL& url,
                        NavigateParams* params) {
   NavigationController::LoadURLParams load_url_params(url);
+  load_url_params.initiator_origin = params->initiator_origin;
   load_url_params.source_site_instance = params->source_site_instance;
   load_url_params.referrer = params->referrer;
   load_url_params.frame_name = params->frame_name;
diff --git a/chrome/browser/ui/browser_navigator_params.cc b/chrome/browser/ui/browser_navigator_params.cc
index 50fe09ab..c5211e8 100644
--- a/chrome/browser/ui/browser_navigator_params.cc
+++ b/chrome/browser/ui/browser_navigator_params.cc
@@ -46,6 +46,7 @@
 
 void NavigateParams::FillNavigateParamsFromOpenURLParams(
     const content::OpenURLParams& params) {
+  this->initiator_origin = params.initiator_origin;
   this->referrer = params.referrer;
   this->source_site_instance = params.source_site_instance;
   this->frame_tree_node_id = params.frame_tree_node_id;
diff --git a/chrome/browser/ui/browser_navigator_params.h b/chrome/browser/ui/browser_navigator_params.h
index 8ba5b47..634346a 100644
--- a/chrome/browser/ui/browser_navigator_params.h
+++ b/chrome/browser/ui/browser_navigator_params.h
@@ -80,6 +80,9 @@
   GURL url;
   content::Referrer referrer;
 
+  // The origin of the initiator of the navigation.
+  base::Optional<url::Origin> initiator_origin;
+
   // The frame name to be used for the main frame.
   std::string frame_name;
 
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
index 73e48630..db2e06b 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
@@ -16,6 +16,7 @@
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/ukm/content/source_url_recorder.h"
 #include "components/url_formatter/idn_spoof_checker.h"
+#include "components/url_formatter/top_domains/top_domain_util.h"
 #include "components/url_formatter/url_formatter.h"
 #include "content/public/browser/navigation_handle.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
@@ -24,6 +25,12 @@
 
 namespace {
 
+#include "components/url_formatter/top_domains/top500-domains-inc.cc"
+
+using MatchType = LookalikeUrlNavigationObserver::MatchType;
+using NavigationSuggestionEvent =
+    LookalikeUrlNavigationObserver::NavigationSuggestionEvent;
+
 void RecordEvent(
     LookalikeUrlNavigationObserver::NavigationSuggestionEvent event) {
   UMA_HISTOGRAM_ENUMERATION(LookalikeUrlNavigationObserver::kHistogramName,
@@ -41,102 +48,13 @@
   return false;
 }
 
-}  // namespace
-
-// static
-const char LookalikeUrlNavigationObserver::kHistogramName[] =
-    "NavigationSuggestion.Event";
-
-LookalikeUrlNavigationObserver::LookalikeUrlNavigationObserver(
-    content::WebContents* web_contents)
-    : WebContentsObserver(web_contents) {}
-
-LookalikeUrlNavigationObserver::~LookalikeUrlNavigationObserver() {}
-
-void LookalikeUrlNavigationObserver::DidFinishNavigation(
-    content::NavigationHandle* navigation_handle) {
-  // Ignore subframe and same document navigations.
-  if (!navigation_handle->IsInMainFrame() ||
-      navigation_handle->IsSameDocument())
-    return;
-
-  // If the navigation was not committed, it means either the page was a
-  // download or error 204/205, or the navigation never left the previous
-  // URL. Basically, this isn't a problem since we stayed at the existing URL.
-  if (!navigation_handle->HasCommitted())
-    return;
-
-  const GURL url = navigation_handle->GetURL();
-
-  // If the user has engaged with this site, don't show any lookalike
-  // navigation suggestions.
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
-  SiteEngagementService* service = SiteEngagementService::Get(profile);
-  if (service->IsEngagementAtLeast(url, blink::mojom::EngagementLevel::MEDIUM))
-    return;
-
-  const base::StringPiece host = url.host_piece();
-  url_formatter::IDNConversionResult result =
-      url_formatter::IDNToUnicodeWithDetails(host);
-  if (!result.has_idn_component)
-    return;
-
-  std::string matched_domain;
-  MatchType match_type;
-  if (result.matching_top_domain.empty()) {
-    matched_domain = GetMatchingSiteEngagementDomain(service, url);
-    if (matched_domain.empty())
-      return;
-    RecordEvent(NavigationSuggestionEvent::kMatchSiteEngagement);
-    match_type = MatchType::kSiteEngagement;
-  } else {
-    matched_domain = result.matching_top_domain;
-    RecordEvent(NavigationSuggestionEvent::kMatchTopSite);
-    match_type = MatchType::kTopSite;
-  }
-
-  DCHECK(!matched_domain.empty());
-
-  GURL::Replacements replace_host;
-  replace_host.SetHostStr(matched_domain);
-  const GURL suggested_url = url.ReplaceComponents(replace_host);
-
-  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
-  CHECK(ukm_recorder);
-  ukm::SourceId source_id =
-      ukm::GetSourceIdForWebContentsDocument(web_contents());
-  ukm::builders::LookalikeUrl_NavigationSuggestion(source_id)
-      .SetMatchType(static_cast<int>(match_type))
-      .Record(ukm_recorder);
-
-  if (base::FeatureList::IsEnabled(
-          features::kLookalikeUrlNavigationSuggestionsUI)) {
-    RecordEvent(NavigationSuggestionEvent::kInfobarShown);
-    AlternateNavInfoBarDelegate::CreateForLookalikeUrlNavigation(
-        web_contents(), base::UTF8ToUTF16(matched_domain), suggested_url, url,
-        base::BindOnce(RecordEvent, NavigationSuggestionEvent::kLinkClicked));
-  }
-}
-
-// static
-void LookalikeUrlNavigationObserver::CreateForWebContents(
-    content::WebContents* web_contents) {
-  DCHECK(web_contents);
-  if (!FromWebContents(web_contents)) {
-    web_contents->SetUserData(
-        UserDataKey(),
-        std::make_unique<LookalikeUrlNavigationObserver>(web_contents));
-  }
-}
-
-std::string LookalikeUrlNavigationObserver::GetMatchingSiteEngagementDomain(
+// Returns a site that the user has used before that the eTLD+1 in
+// |domain_and_registry| may be attempting to spoof, based on skeleton
+// comparison.
+std::string GetMatchingSiteEngagementDomain(
     SiteEngagementService* service,
-    const GURL& url) {
+    const std::string& domain_and_registry) {
   // Compute skeletons using eTLD+1.
-  const std::string domain_and_registry =
-      net::registry_controlled_domains::GetDomainAndRegistry(
-          url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
   // eTLD+1 can be empty for private domains.
   if (domain_and_registry.empty())
     return std::string();
@@ -195,4 +113,186 @@
   return std::string();
 }
 
+}  // namespace
+
+// static
+const char LookalikeUrlNavigationObserver::kHistogramName[] =
+    "NavigationSuggestion.Event";
+
+LookalikeUrlNavigationObserver::LookalikeUrlNavigationObserver(
+    content::WebContents* web_contents)
+    : WebContentsObserver(web_contents) {}
+
+LookalikeUrlNavigationObserver::~LookalikeUrlNavigationObserver() {}
+
+void LookalikeUrlNavigationObserver::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  // Ignore subframe and same document navigations.
+  if (!navigation_handle->IsInMainFrame() ||
+      navigation_handle->IsSameDocument())
+    return;
+
+  // If the navigation was not committed, it means either the page was a
+  // download or error 204/205, or the navigation never left the previous
+  // URL. Basically, this isn't a problem since we stayed at the existing URL.
+  if (!navigation_handle->HasCommitted())
+    return;
+
+  const GURL url = navigation_handle->GetURL();
+
+  // If the user has engaged with this site, don't show any lookalike
+  // navigation suggestions.
+  Profile* profile =
+      Profile::FromBrowserContext(web_contents()->GetBrowserContext());
+  SiteEngagementService* service = SiteEngagementService::Get(profile);
+  if (service->IsEngagementAtLeast(url, blink::mojom::EngagementLevel::MEDIUM))
+    return;
+
+  std::string matched_domain;
+  MatchType match_type;
+  if (!GetMatchingDomain(url, service, &matched_domain, &match_type))
+    return;
+
+  DCHECK(!matched_domain.empty());
+
+  GURL::Replacements replace_host;
+  replace_host.SetHostStr(matched_domain);
+  const GURL suggested_url = url.ReplaceComponents(replace_host);
+
+  ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
+  CHECK(ukm_recorder);
+  ukm::SourceId source_id =
+      ukm::GetSourceIdForWebContentsDocument(web_contents());
+  ukm::builders::LookalikeUrl_NavigationSuggestion(source_id)
+      .SetMatchType(static_cast<int>(match_type))
+      .Record(ukm_recorder);
+
+  if (base::FeatureList::IsEnabled(
+          features::kLookalikeUrlNavigationSuggestionsUI)) {
+    RecordEvent(NavigationSuggestionEvent::kInfobarShown);
+    AlternateNavInfoBarDelegate::CreateForLookalikeUrlNavigation(
+        web_contents(), base::UTF8ToUTF16(matched_domain), suggested_url, url,
+        base::BindOnce(RecordEvent, NavigationSuggestionEvent::kLinkClicked));
+  }
+}
+
+bool LookalikeUrlNavigationObserver::GetMatchingDomain(
+    const GURL& url,
+    SiteEngagementService* service,
+    std::string* matched_domain,
+    MatchType* match_type) {
+  // Perform all computations on eTLD+1.
+  const std::string domain_and_registry =
+      net::registry_controlled_domains::GetDomainAndRegistry(
+          url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+
+  url_formatter::IDNConversionResult result =
+      url_formatter::IDNToUnicodeWithDetails(domain_and_registry);
+  if (result.has_idn_component) {
+    // If the navigated domain is IDN, check its skeleton against top domains
+    // and engaged sites.
+    if (!result.matching_top_domain.empty()) {
+      RecordEvent(NavigationSuggestionEvent::kMatchTopSite);
+      *matched_domain = result.matching_top_domain;
+      *match_type = MatchType::kTopSite;
+      return true;
+    }
+
+    const std::string matched_engaged_domain =
+        GetMatchingSiteEngagementDomain(service, domain_and_registry);
+    if (!matched_engaged_domain.empty()) {
+      RecordEvent(NavigationSuggestionEvent::kMatchSiteEngagement);
+      *matched_domain = matched_engaged_domain;
+      *match_type = MatchType::kSiteEngagement;
+      return true;
+    }
+  }
+
+  // If we can't find an exact top domain or an engaged site, try to find a top
+  // domain within an edit distance of one.
+  const std::string similar_domain =
+      GetSimilarDomainFromTop500(base::UTF16ToUTF8(result.result));
+  if (!similar_domain.empty() && domain_and_registry != similar_domain) {
+    RecordEvent(NavigationSuggestionEvent::kMatchEditDistance);
+    *matched_domain = similar_domain;
+    *match_type = MatchType::kEditDistance;
+    return true;
+  }
+  return false;
+}
+
+// static
+bool LookalikeUrlNavigationObserver::IsEditDistanceAtMostOne(
+    const base::string16& str1,
+    const base::string16& str2) {
+  if (str1.size() > str2.size() + 1 || str2.size() > str1.size() + 1) {
+    return false;
+  }
+  base::string16::const_iterator i = str1.begin();
+  base::string16::const_iterator j = str2.begin();
+  size_t edit_count = 0;
+  while (i != str1.end() && j != str2.end()) {
+    if (*i == *j) {
+      i++;
+      j++;
+    } else {
+      edit_count++;
+      if (edit_count > 1) {
+        return false;
+      }
+
+      if (str1.size() > str2.size()) {
+        // First string is longer than the second. This can only happen if the
+        // first string has an extra character.
+        i++;
+      } else if (str2.size() > str1.size()) {
+        // Second string is longer than the first. This can only happen if the
+        // second string has an extra character.
+        j++;
+      } else {
+        // Both strings are the same length. This can only happen if the two
+        // strings differ by a single character.
+        i++;
+        j++;
+      }
+    }
+  }
+  if (i != str1.end() || j != str2.end()) {
+    // A character at the end did not match.
+    edit_count++;
+  }
+  return edit_count <= 1;
+}
+
+// static
+std::string LookalikeUrlNavigationObserver::GetSimilarDomainFromTop500(
+    const std::string& domain_and_registry) {
+  if (!url_formatter::top_domains::IsEditDistanceCandidate(
+          domain_and_registry)) {
+    return std::string();
+  }
+
+  for (const std::string& skeleton :
+       url_formatter::GetSkeletons(base::UTF8ToUTF16(domain_and_registry))) {
+    for (const char* const top_domain_skeleton : kTop500) {
+      if (IsEditDistanceAtMostOne(base::UTF8ToUTF16(skeleton),
+                                  base::UTF8ToUTF16(top_domain_skeleton))) {
+        return url_formatter::LookupSkeletonInTopDomains(top_domain_skeleton);
+      }
+    }
+  }
+  return std::string();
+}
+
+// static
+void LookalikeUrlNavigationObserver::CreateForWebContents(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  if (!FromWebContents(web_contents)) {
+    web_contents->SetUserData(
+        UserDataKey(),
+        std::make_unique<LookalikeUrlNavigationObserver>(web_contents));
+  }
+}
+
 WEB_CONTENTS_USER_DATA_KEY_IMPL(LookalikeUrlNavigationObserver)
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
index c780c9ce..dd008338 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h
@@ -27,10 +27,11 @@
     kLinkClicked = 2,
     kMatchTopSite = 3,
     kMatchSiteEngagement = 4,
+    kMatchEditDistance = 5,
 
     // Append new items to the end of the list above; do not modify or
     // replace existing values. Comment out obsolete items.
-    kMaxValue = kMatchSiteEngagement,
+    kMaxValue = kMatchEditDistance,
   };
 
   // Used for UKM. There is only a single MatchType per navigation.
@@ -38,10 +39,11 @@
     kNone = 0,
     kTopSite = 1,
     kSiteEngagement = 2,
+    kEditDistance = 3,
 
     // Append new items to the end of the list above; do not modify or replace
     // existing values. Comment out obsolete items.
-    kMaxValue = kSiteEngagement,
+    kMaxValue = kEditDistance,
   };
 
   static const char kHistogramName[];
@@ -57,10 +59,30 @@
 
  private:
   friend class content::WebContentsUserData<LookalikeUrlNavigationObserver>;
-  // Returns a site that the user has used before that |url| may be attempting
-  // to spoof, based on skeleton comparison.
-  std::string GetMatchingSiteEngagementDomain(SiteEngagementService* service,
-                                              const GURL& url);
+  FRIEND_TEST_ALL_PREFIXES(LookalikeUrlNavigationObserverTest,
+                           IsEditDistanceAtMostOne);
+
+  // Returns true if a domain is visually similar to the hostname of |url|. The
+  // matching domain can be a top domain or an engaged site. Similarity check
+  // is made using both visual skeleton and edit distance comparison. If this
+  // returns true, match details will be written into |matched_domain| and
+  // |match_type|. They cannot be nullptr.
+  bool GetMatchingDomain(const GURL& url,
+                         SiteEngagementService* service,
+                         std::string* matched_domain,
+                         MatchType* match_type);
+
+  // Returns if the Levenshtein distance between |str1| and |str2| is at most 1.
+  // This has O(max(n,m)) complexity as opposed to O(n*m) of the usual edit
+  // distance computation.
+  static bool IsEditDistanceAtMostOne(const base::string16& str1,
+                                      const base::string16& str2);
+
+  // Returns the first matching top domain with an edit distance of at most one
+  // to |domain_and_registry|.
+  static std::string GetSimilarDomainFromTop500(
+      const std::string& domain_and_registry);
+
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 };
 
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
index 790ec49..6fdec4c 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
@@ -134,7 +134,6 @@
     // Sanity check navigated_url.
     url_formatter::IDNConversionResult result =
         url_formatter::IDNToUnicodeWithDetails(navigated_url.host_piece());
-    ASSERT_TRUE(result.has_idn_component);
 
     history::HistoryService* const history_service =
         HistoryServiceFactory::GetForProfile(
@@ -259,6 +258,57 @@
            LookalikeUrlNavigationObserver::MatchType::kTopSite);
 }
 
+// Navigate to a domain within an edit distance of 1 to a top domain.
+// This should record metrics. It should also show a "Did you mean to go to ..."
+// infobar if configured via a feature param.
+IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationObserverBrowserTest,
+                       Idn_TopDomainEditDistance_Match) {
+  base::HistogramTester histograms;
+
+  // The skeleton of this domain, gooogle.corn, is one 1 edit away from
+  // google.corn, the skeleton of google.com.
+  const GURL kNavigatedUrl =
+      embedded_test_server()->GetURL("goooglé.com", "/title1.html");
+
+  if (GetParam() == FeatureTestState::kEnabled) {
+    // Even if the navigated site has a low engagement score, it should be
+    // considered for lookalike suggestions.
+    SetSiteEngagementScore(kNavigatedUrl, kLowEngagement);
+    // If the feature is enabled, the UI will be displayed. Expect extra
+    // histogram entries for kInfobarShown and kLinkClicked events.
+    TestInfobarShown(kNavigatedUrl,
+                     embedded_test_server()->GetURL(
+                         "google.com", "/title1.html") /* suggested */);
+    histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
+                                3);
+    histograms.ExpectBucketCount(LookalikeUrlNavigationObserver::kHistogramName,
+                                 LookalikeUrlNavigationObserver::
+                                     NavigationSuggestionEvent::kInfobarShown,
+                                 1);
+    histograms.ExpectBucketCount(
+        LookalikeUrlNavigationObserver::kHistogramName,
+        LookalikeUrlNavigationObserver::NavigationSuggestionEvent::kLinkClicked,
+        1);
+    histograms.ExpectBucketCount(
+        LookalikeUrlNavigationObserver::kHistogramName,
+        LookalikeUrlNavigationObserver::NavigationSuggestionEvent::
+            kMatchEditDistance,
+        1);
+  } else {
+    TestInfobarNotShown(kNavigatedUrl);
+    histograms.ExpectTotalCount(LookalikeUrlNavigationObserver::kHistogramName,
+                                1);
+    histograms.ExpectBucketCount(
+        LookalikeUrlNavigationObserver::kHistogramName,
+        LookalikeUrlNavigationObserver::NavigationSuggestionEvent::
+            kMatchEditDistance,
+        1);
+  }
+
+  CheckUkm({kNavigatedUrl},
+           LookalikeUrlNavigationObserver::MatchType::kEditDistance);
+}
+
 // Navigate to a domain whose visual representation looks like a domain with a
 // site engagement score above a certain threshold. This should record metrics.
 // It should also show a "Did you mean to go to ..." infobar if configured via
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_unittest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_unittest.cc
new file mode 100644
index 0000000..8a03f5c
--- /dev/null
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_unittest.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 "chrome/browser/ui/omnibox/lookalike_url_navigation_observer.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(LookalikeUrlNavigationObserverTest, IsEditDistanceAtMostOne) {
+  const struct TestCase {
+    const wchar_t* domain;
+    const wchar_t* top_domain;
+    bool expected;
+  } kTestCases[] = {
+      {L"", L"", true},
+      {L"a", L"a", true},
+      {L"a", L"", true},
+      {L"", L"a", true},
+
+      {L"", L"ab", false},
+      {L"ab", L"", false},
+
+      {L"ab", L"a", true},
+      {L"a", L"ab", true},
+      {L"ab", L"b", true},
+      {L"b", L"ab", true},
+      {L"ab", L"ab", true},
+
+      {L"", L"ab", false},
+      {L"ab", L"", false},
+      {L"a", L"abc", false},
+      {L"abc", L"a", false},
+
+      {L"aba", L"ab", true},
+      {L"ba", L"aba", true},
+      {L"abc", L"ac", true},
+      {L"ac", L"abc", true},
+
+      // Same length.
+      {L"xbc", L"ybc", true},
+      {L"axc", L"ayc", true},
+      {L"abx", L"aby", true},
+
+      // Should also work for non-ASCII.
+      {L"é", L"", true},
+      {L"", L"é", true},
+      {L"tést", L"test", true},
+      {L"test", L"tést", true},
+      {L"tés", L"test", false},
+      {L"test", L"tés", false},
+
+      // Real world test cases.
+      {L"google.com", L"gooogle.com", true},
+      {L"gogle.com", L"google.com", true},
+      {L"googlé.com", L"google.com", true},
+      {L"google.com", L"googlé.com", true},
+      // Different by two characters.
+      {L"google.com", L"goooglé.com", false},
+  };
+  for (const TestCase& test_case : kTestCases) {
+    bool result = LookalikeUrlNavigationObserver::IsEditDistanceAtMostOne(
+        base::WideToUTF16(test_case.domain),
+        base::WideToUTF16(test_case.top_domain));
+    EXPECT_EQ(test_case.expected, result);
+  }
+}
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index e12826a..9794617 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -405,7 +405,8 @@
 };
 
 // Test if ctrl-* accelerators are workable in omnibox.
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, BrowserAccelerators) {
+// Flaky. See https://crbug.com/751031.
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, DISABLED_BrowserAccelerators) {
   OmniboxView* omnibox_view = NULL;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
 
@@ -1161,7 +1162,8 @@
             popup_model->result().default_match()->destination_url.spec());
 }
 
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, DeleteItem) {
+// Flaky. See https://crbug.com/751031.
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, DISABLED_DeleteItem) {
   // Disable the search provider, to make sure the popup contains only history
   // items.
   TemplateURLService* model =
@@ -1806,7 +1808,8 @@
 
 // Test that if the Omnibox has focus, and had everything selected before a
 // non-user-initiated update, then it retains the selection after the update.
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, SelectAllStaysAfterUpdate) {
+// Flaky. See https://crbug.com/751031.
+IN_PROC_BROWSER_TEST_F(OmniboxViewTest, DISABLED_SelectAllStaysAfterUpdate) {
   OmniboxView* omnibox_view = nullptr;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
 
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index e471798eb..0ef7a74 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -126,8 +126,7 @@
 
     ProfileSyncServiceFactory::GetForProfile(profile())
         ->GetLocalDeviceInfoProviderForTest()
-        ->Initialize(activation_request.cache_guid, "Test Machine",
-                     "device_id");
+        ->Initialize(activation_request.cache_guid, "Test Machine");
 
     std::unique_ptr<syncer::DataTypeActivationResponse> activation_response;
     base::RunLoop loop;
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.cc b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
index a36d5a6..9f31099e 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
@@ -54,9 +54,12 @@
 // TODO(timloh): This is just a placeholder.
 constexpr int kDownloadSizeInBytes = 300 * 1024 * 1024;
 
-constexpr int kOOBEButtonRowInset = 32;
+constexpr gfx::Insets kOOBEButtonRowInsets(32, 64, 32, 64);
 constexpr int kOOBEWindowWidth = 768;
-constexpr int kOOBEWindowHeight = 640 - 2 * kOOBEButtonRowInset;
+// TODO(timloh): The button row's preferred height (48px) adds to this. I'm not
+// sure where this actually comes from but since we plan to rewrite this dialog
+// in WebUI soon, this constant just hard-coded here.
+constexpr int kOOBEWindowHeight = 640 - 48;
 constexpr int kLinuxIllustrationWidth = 448;
 constexpr int kLinuxIllustrationHeight = 180;
 
@@ -99,7 +102,7 @@
                                               nullptr, nullptr);
   }
   g_crostini_installer_view->GetDialogClientView()->SetButtonRowInsets(
-      gfx::Insets(kOOBEButtonRowInset));
+      kOOBEButtonRowInsets);
   g_crostini_installer_view->GetWidget()->GetRootView()->Layout();
   // We do our layout when the big message is at its biggest. Then we can
   // set it to the desired value.
@@ -370,27 +373,24 @@
 CrostiniInstallerView::CrostiniInstallerView(Profile* profile)
     : profile_(profile), weak_ptr_factory_(this) {
   // Layout constants from the spec.
-  constexpr gfx::Insets kDialogInsets(60, 64, 32, 64);
+  constexpr gfx::Insets kDialogInsets(60, 64, 0, 64);
   constexpr int kDialogSpacingVertical = 32;
   constexpr gfx::Size kLogoImageSize(32, 32);
+  constexpr gfx::Insets kLowerContainerInsets(0, 0, 80, 0);
 
   views::BoxLayout* layout =
       SetLayoutManager(std::make_unique<views::BoxLayout>(
           views::BoxLayout::kVertical, gfx::Insets(), kDialogSpacingVertical));
 
   views::View* upper_container_view = new views::View();
-  upper_container_view->SetSize(gfx::Size(
-      kOOBEWindowWidth, kOOBEWindowHeight - kLinuxIllustrationHeight));
   upper_container_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
       views::BoxLayout::kVertical, kDialogInsets, kDialogSpacingVertical));
   AddChildView(upper_container_view);
 
   views::View* lower_container_view = new views::View();
-  lower_container_view->SetSize(
-      gfx::Size(kOOBEWindowWidth, kLinuxIllustrationHeight));
   views::BoxLayout* lower_container_layout =
-      lower_container_view->SetLayoutManager(
-          std::make_unique<views::BoxLayout>(views::BoxLayout::kVertical));
+      lower_container_view->SetLayoutManager(std::make_unique<views::BoxLayout>(
+          views::BoxLayout::kVertical, kLowerContainerInsets));
   AddChildView(lower_container_view);
 
   logo_image_ = new views::ImageView();
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
index 3cc54d9..1210462 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
@@ -4,7 +4,10 @@
 
 #include "chrome/browser/ui/views/location_bar/custom_tab_bar_view.h"
 
+#include <memory>
+
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/extensions/hosted_app_browser_controller.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/omnibox/omnibox_theme.h"
@@ -13,15 +16,24 @@
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/hosted_app_button_container.h"
 #include "components/url_formatter/url_formatter.h"
+#include "components/vector_icons/vector_icons.h"
+#include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/strings/grit/ui_strings.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
+#include "ui/views/controls/button/image_button.h"
+#include "ui/views/controls/button/image_button_factory.h"
 #include "ui/views/layout/box_layout.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/style/typography_provider.h"
+#include "ui/views/view_properties.h"
+#include "url/gurl.h"
 
 #if defined(OS_CHROMEOS)
 #include "ash/public/cpp/ash_constants.h"
@@ -42,6 +54,50 @@
 #endif
 }
 
+views::ImageButton* CreateCloseButton(views::ButtonListener* listener,
+                                      SkColor color) {
+  views::ImageButton* close_button = CreateVectorImageButton(listener);
+  SetImageFromVectorIconWithColor(close_button, vector_icons::kCloseRoundedIcon,
+                                  color);
+  close_button->SetTooltipText(l10n_util::GetStringUTF16(IDS_APP_CLOSE));
+  close_button->SizeToPreferredSize();
+
+  // Use a circular ink drop.
+  auto highlight_path = std::make_unique<SkPath>();
+  highlight_path->addOval(gfx::RectToSkRect(gfx::Rect(close_button->size())));
+  close_button->SetProperty(views::kHighlightPathKey, highlight_path.release());
+
+  return close_button;
+}
+
+void GoBackToApp(content::WebContents* web_contents) {
+  Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+  GURL launch_url = browser->hosted_app_controller()->GetAppLaunchURL();
+  content::NavigationController& controller = web_contents->GetController();
+  content::BrowserContext* context = web_contents->GetBrowserContext();
+
+  content::NavigationEntry* entry = nullptr;
+  int offset = 0;
+
+  // Go back until we find an in scope url, or run out of urls.
+  while ((entry = controller.GetEntryAtOffset(offset)) &&
+         !extensions::IsSameScope(entry->GetURL(), launch_url, context)) {
+    offset--;
+  }
+
+  // If there are no in scope urls, push the app's launch url and clear
+  // the history.
+  if (!entry) {
+    content::NavigationController::LoadURLParams load(launch_url);
+    load.should_clear_history_list = true;
+    controller.LoadURLWithParams(load);
+    return;
+  }
+
+  // Otherwise, go back to the first in scope url.
+  controller.GoToOffset(offset);
+}
+
 }  // namespace
 
 // Container view for laying out and rendering the title/origin of the current
@@ -106,6 +162,9 @@
   const gfx::FontList& font_list = views::style::GetFont(
       CONTEXT_OMNIBOX_PRIMARY, views::style::STYLE_PRIMARY);
 
+  close_button_ = CreateCloseButton(this, text_color_);
+  AddChildView(close_button_);
+
   location_icon_view_ = new LocationIconView(font_list, this);
   AddChildView(location_icon_view_);
 
@@ -198,3 +257,8 @@
 const LocationBarModel* CustomTabBarView::GetLocationBarModel() const {
   return delegate_->GetLocationBarModel();
 }
+
+void CustomTabBarView::ButtonPressed(views::Button* sender,
+                                     const ui::Event& event) {
+  GoBackToApp(GetWebContents());
+}
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
index ce4f2b5..10b6f7b 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/browser/ui/views/location_bar/location_icon_view.h"
+#include "ui/views/controls/button/button.h"
 
 class CustomTabBarTitleOriginView;
 class BrowserView;
@@ -20,7 +21,8 @@
 // scope.
 class CustomTabBarView : public views::View,
                          public TabStripModelObserver,
-                         public LocationIconView::Delegate {
+                         public LocationIconView::Delegate,
+                         public views::ButtonListener {
  public:
   static const char kViewClassName[];
 
@@ -48,6 +50,9 @@
                                      on_icon_fetched) const override;
   SkColor GetLocationIconInkDropColor() const override;
 
+  // ButtonListener:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
   // Methods for testing.
   base::string16 title_for_testing() const { return last_title_; }
   base::string16 location_for_testing() const { return last_location_; }
@@ -59,6 +64,7 @@
   base::string16 last_title_;
   base::string16 last_location_;
 
+  views::Button* close_button_ = nullptr;
   LocationBarView::Delegate* delegate_ = nullptr;
   LocationIconView* location_icon_view_ = nullptr;
   CustomTabBarTitleOriginView* title_origin_view_ = nullptr;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index c9646fed..0ea93c4 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -386,6 +386,9 @@
     case IDS_PASTE_AND_GO:
       model()->PasteAndGo(GetClipboardText());
       return;
+    case IDS_SHOW_URL:
+      model()->Unelide(true /* exit_query_in_omnibox */);
+      return;
     case IDC_EDIT_SEARCH_ENGINES:
       location_bar_view_->command_updater()->ExecuteCommand(command_id);
       return;
@@ -1223,6 +1226,11 @@
     return !read_only() && !GetClipboardText().empty();
   if (command_id == IDS_PASTE_AND_GO)
     return !read_only() && model()->CanPasteAndGo(GetClipboardText());
+
+  // Menu item is only shown when it is valid.
+  if (command_id == IDS_SHOW_URL)
+    return true;
+
   return Textfield::IsCommandIdEnabled(command_id) ||
          location_bar_view_->command_updater()->IsCommandEnabled(command_id);
 }
@@ -1574,6 +1582,16 @@
   menu_contents->InsertItemWithStringIdAt(
       paste_position + 1, IDS_PASTE_AND_GO, IDS_PASTE_AND_GO);
 
+  // Only add this menu entry if Query in Omnibox feature is enabled.
+  if (base::FeatureList::IsEnabled(omnibox::kQueryInOmnibox)) {
+    // If the user has not started editing the text, and we are not showing the
+    // full URL, then provide a way to unelide via the context menu.
+    if (!read_only() && !model()->user_input_in_progress() &&
+        text() != controller()->GetLocationBarModel()->GetFormattedFullURL()) {
+      menu_contents->AddItemWithStringId(IDS_SHOW_URL, IDS_SHOW_URL);
+    }
+  }
+
   menu_contents->AddSeparator(ui::NORMAL_SEPARATOR);
 
   // Minor note: We use IDC_ for command id here while the underlying textfield
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index e105b369..4f4a40f 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -509,6 +509,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ToolbarView, views::View overrides:
 
+gfx::Size ToolbarView::CalculatePreferredSize() const {
+  gfx::Size size = View::CalculatePreferredSize();
+  size.set_height(size.height() * size_animation_.GetCurrentValue());
+  return size;
+}
+
+gfx::Size ToolbarView::GetMinimumSize() const {
+  gfx::Size size = View::GetMinimumSize();
+  size.set_height(size.height() * size_animation_.GetCurrentValue());
+  return size;
+}
+
 void ToolbarView::Layout() {
   // If we have not been initialized yet just do nothing.
   if (!initialized_)
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index a7ed933..740dabc 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -181,6 +181,8 @@
                                   ui::Accelerator* accelerator) const override;
 
   // views::View:
+  gfx::Size CalculatePreferredSize() const override;
+  gfx::Size GetMinimumSize() const override;
   void Layout() override;
   void OnPaintBackground(gfx::Canvas* canvas) override;
   void OnThemeChanged() override;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
index 8f3c1c9..a984bb7 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
@@ -125,7 +125,7 @@
 
 void ToolbarViewInteractiveUITest::FinishDragAndDrop(
     base::Closure quit_closure) {
-  base::ScopedAllowBlockingForTesting allow_thread_join;
+  base::ScopedAllowBaseSyncPrimitivesForTesting allow_thread_join;
   dnd_thread_.reset();
   TestWhileInDragOperation();
   ui_controls::SendMouseEventsNotifyWhenDone(ui_controls::LEFT, ui_controls::UP,
diff --git a/chrome/browser/ui/webui/app_management/app_management_ui.cc b/chrome/browser/ui/webui/app_management/app_management_ui.cc
index 1975a174..32027df 100644
--- a/chrome/browser/ui/webui/app_management/app_management_ui.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_ui.cc
@@ -54,6 +54,10 @@
 
   source->AddResourcePath("actions.html", IDR_APP_MANAGEMENT_ACTIONS_HTML);
   source->AddResourcePath("actions.js", IDR_APP_MANAGEMENT_ACTIONS_JS);
+  source->AddResourcePath("api_listener.html",
+                          IDR_APP_MANAGEMENT_API_LISTENER_HTML);
+  source->AddResourcePath("api_listener.js",
+                          IDR_APP_MANAGEMENT_API_LISTENER_JS);
   source->AddResourcePath("app.html", IDR_APP_MANAGEMENT_APP_HTML);
   source->AddResourcePath("app.js", IDR_APP_MANAGEMENT_APP_JS);
   source->AddResourcePath("browser_proxy.html",
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index 9621a9c..6592c76 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -436,6 +436,10 @@
   source->AddResourcePath(
       "pdf/elements/viewer-error-screen/viewer-error-screen.js",
       IDR_PDF_VIEWER_ERROR_SCREEN_JS);
+  source->AddResourcePath("pdf/elements/viewer-ink-host/viewer-ink-host.html",
+                          IDR_PDF_VIEWER_INK_HOST_HTML);
+  source->AddResourcePath("pdf/elements/viewer-ink-host/viewer-ink-host.js",
+                          IDR_PDF_VIEWER_INK_HOST_JS);
   source->AddResourcePath(
       "pdf/elements/viewer-page-indicator/viewer-page-indicator.html",
       IDR_PDF_VIEWER_PAGE_INDICATOR_HTML);
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index cb4a9ce..ef17106 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -180,6 +180,9 @@
 const base::Feature kCrostiniAppUninstallGui{"CrostiniAppUninstallGui",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Enable support for "Plugin VMs" on Chrome OS.
+const base::Feature kPluginVm{"PluginVm", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Whether the UsageTimeLimit policy should be applied to the user.
 const base::Feature kUsageTimeLimitPolicy{"UsageTimeLimitPolicy",
                                           base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index b569e40f..931223b 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -115,6 +115,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrostini;
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kCrostiniAppUninstallGui;
+COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kPluginVm;
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kUsageTimeLimitPolicy;
 #endif
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 398e97a..e1e2b05 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1771,6 +1771,7 @@
         "../browser/chromeos/policy/component_active_directory_policy_browsertest.cc",
         "../browser/chromeos/policy/device_cloud_policy_browsertest.cc",
         "../browser/chromeos/policy/device_local_account_browsertest.cc",
+        "../browser/chromeos/policy/device_policy_cloud_external_data_manager_browsertest.cc",
         "../browser/chromeos/policy/device_policy_cros_browser_test.cc",
         "../browser/chromeos/policy/device_policy_cros_browser_test.h",
         "../browser/chromeos/policy/device_quirks_policy_browsertest.cc",
@@ -3203,6 +3204,7 @@
       "../browser/ui/global_error/global_error_service_unittest.cc",
       "../browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc",
       "../browser/ui/omnibox/clipboard_utils_unittest.cc",
+      "../browser/ui/omnibox/lookalike_url_navigation_observer_unittest.cc",
       "../browser/ui/page_info/permission_menu_model_unittest.cc",
       "../browser/ui/passwords/manage_passwords_bubble_model_unittest.cc",
       "../browser/ui/passwords/password_dialog_controller_impl_unittest.cc",
diff --git a/chrome/test/data/navigation_predictor/simple_page_with_anchors.html b/chrome/test/data/navigation_predictor/simple_page_with_anchors.html
index 9b4362e..54c67b36 100644
--- a/chrome/test/data/navigation_predictor/simple_page_with_anchors.html
+++ b/chrome/test/data/navigation_predictor/simple_page_with_anchors.html
@@ -5,5 +5,7 @@
     <a id="google" href="https://google.com">Google</a>
     <a id="example" href="https://example.com">Example</a>
     <a id="example" href="simple_page_with_anchors.html">Same page</a>
+    <a id="example" href="simple_page_with_anchors.html#">Same page</a>
+    <a id="example" href="simple_page_with_anchors.html#foobar">Same page</a>
   </body>
 </html>
\ No newline at end of file
diff --git a/chrome/test/data/pdf/annotations_feature_enabled_test.js b/chrome/test/data/pdf/annotations_feature_enabled_test.js
index 72a3e99..2521739 100644
--- a/chrome/test/data/pdf/annotations_feature_enabled_test.js
+++ b/chrome/test/data/pdf/annotations_feature_enabled_test.js
@@ -2,6 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+
+function contentElement() {
+  return document.elementFromPoint(innerWidth / 2, innerHeight / 2);
+}
+
+async function testAsync(f) {
+  try {
+    await f();
+    chrome.test.succeed();
+  } catch (e) {
+    chrome.test.fail(e);
+  }
+}
+
 chrome.test.runTests([
   function testAnnotationsEnabled() {
     const toolbar = document.body.querySelector('#toolbar');
@@ -10,4 +24,20 @@
         toolbar.shadowRoot.querySelector('#annotate') != null);
     chrome.test.succeed();
   },
+  function testEnterAndExitAnnotationMode() {
+    testAsync(async () => {
+      chrome.test.assertEq('EMBED', contentElement().tagName);
+
+      // Enter annotation mode.
+      $('toolbar').toggleAnnotation();
+      await viewer.loaded;
+      chrome.test.assertEq(
+          'VIEWER-INK-HOST', contentElement().tagName);
+
+      // Exit annotation mode.
+      $('toolbar').toggleAnnotation();
+      await viewer.loaded;
+      chrome.test.assertEq('EMBED', contentElement().tagName);
+    });
+  }
 ]);
diff --git a/chrome/test/data/policy/printers_configuration.json b/chrome/test/data/policy/printers_configuration.json
new file mode 100644
index 0000000..b7600ad8
--- /dev/null
+++ b/chrome/test/data/policy/printers_configuration.json
@@ -0,0 +1 @@
+[{"display_name":"printer 1","uuid":"uuid1"}]
diff --git a/chrome/test/data/policy/printers_configuration_over_size_limit.json b/chrome/test/data/policy/printers_configuration_over_size_limit.json
new file mode 100644
index 0000000..dd11794
--- /dev/null
+++ b/chrome/test/data/policy/printers_configuration_over_size_limit.json
@@ -0,0 +1 @@
+[{"display_name":"printer 1","uuid":"uuid1"},{"display_name":"printer 2","uuid":"uuid2"}]
diff --git a/chrome/test/data/policy/printers_configuration_updated.json b/chrome/test/data/policy/printers_configuration_updated.json
new file mode 100644
index 0000000..e6da336
--- /dev/null
+++ b/chrome/test/data/policy/printers_configuration_updated.json
@@ -0,0 +1 @@
+[{"display_name":"printer 2","uuid":"uuid2"}]
diff --git a/chrome/test/data/webui/app_management/app_management_browsertest.js b/chrome/test/data/webui/app_management/app_management_browsertest.js
index 2d643bcb..1d5bee5 100644
--- a/chrome/test/data/webui/app_management/app_management_browsertest.js
+++ b/chrome/test/data/webui/app_management/app_management_browsertest.js
@@ -41,6 +41,19 @@
   mocha.run();
 });
 
+function AppManagementMainViewTest() {}
+
+AppManagementMainViewTest.prototype = {
+  __proto__: AppManagementBrowserTest.prototype,
+
+  extraLibraries: AppManagementBrowserTest.prototype.extraLibraries.concat([
+    'main_view_test.js',
+  ]),
+};
+
+TEST_F('AppManagementMainViewTest', 'All', function() {
+  mocha.run();
+});
 
 function AppManagementReducersTest() {}
 
diff --git a/chrome/test/data/webui/app_management/main_view_test.js b/chrome/test/data/webui/app_management/main_view_test.js
new file mode 100644
index 0000000..d945712
--- /dev/null
+++ b/chrome/test/data/webui/app_management/main_view_test.js
@@ -0,0 +1,74 @@
+// 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.
+
+suite('<app-management-main-view>', function() {
+  let mainView;
+  let fakeHandler;
+  let callbackRouterProxy;
+  let appIdCounter;
+
+  setup(function() {
+    appIdCounter = 0;
+
+    mainView = document.createElement('app-management-main-view');
+    PolymerTest.clearBody();
+
+    let browserProxy = app_management.BrowserProxy.getInstance();
+    callbackRouterProxy = browserProxy.callbackRouter.createProxy();
+
+    fakeHandler = new app_management.FakePageHandler(callbackRouterProxy);
+    browserProxy.handler = fakeHandler;
+
+    app_management.Store.instance_ = new app_management.Store();
+
+    app_management.Store.getInstance().init(
+        app_management.util.createEmptyState());
+
+    document.body.appendChild(mainView);
+  });
+
+  /**
+   * @param {number} numApps
+   * @return {!Array<appManagement.mojom.App>} apps
+   */
+  function createTestApps(numApps) {
+    let apps = [];
+    for (let i = 0; i < numApps; i++) {
+      apps.push(
+          app_management.FakePageHandler.createApp('TestApp' + appIdCounter++));
+    }
+    return apps;
+  }
+
+  test('simple app addition', async function() {
+    let apps = createTestApps(1);
+    callbackRouterProxy.onAppsAdded(apps);
+    await callbackRouterProxy.flushForTesting();
+    let appItems = mainView.root.querySelectorAll('app-management-item');
+    expectEquals(1, appItems.length);
+
+    expectEquals(appItems[0].app.id, apps[0].id);
+  });
+
+  test('more apps bar visibility', async function() {
+    // The more apps bar shouldn't appear when there are no apps.
+    expectEquals(
+        0, mainView.root.querySelectorAll('app-management-item').length);
+    expectTrue(mainView.$['expander-row'].hidden);
+
+    // The more apps bar shouldn't appear when there are 4 apps.
+    callbackRouterProxy.onAppsAdded(createTestApps(4));
+    await callbackRouterProxy.flushForTesting();
+    expectEquals(
+        4, mainView.root.querySelectorAll('app-management-item').length);
+    expectTrue(mainView.$['expander-row'].hidden);
+
+    // The more apps bar appears when there are 5 apps.
+    callbackRouterProxy.onAppsAdded(createTestApps(1));
+    await callbackRouterProxy.flushForTesting();
+    expectEquals(
+        5, mainView.root.querySelectorAll('app-management-item').length);
+    expectFalse(mainView.$['expander-row'].hidden);
+  });
+});
diff --git a/chrome/test/data/webui/md_history/history_synced_tabs_test.js b/chrome/test/data/webui/md_history/history_synced_tabs_test.js
index aea906fb..83282b0 100644
--- a/chrome/test/data/webui/md_history/history_synced_tabs_test.js
+++ b/chrome/test/data/webui/md_history/history_synced_tabs_test.js
@@ -25,8 +25,11 @@
 
   setup(function() {
     element = document.createElement('history-synced-device-manager');
-    element.signInState = true;
+    // |signInState| is generally set after |searchTerm| in Polymer 2. Set in
+    // the same order in tests, in order to catch regressions like
+    // https://crbug.com/915641.
     element.searchTerm = '';
+    element.signInState = true;
     replaceBody(element);
   });
 
@@ -332,6 +335,19 @@
     });
   });
 
+  test('no synced tabs message displays on load', function() {
+    element.syncedDevices_ = [];
+    // Should show no synced tabs message on initial load. Regression test for
+    // https://crbug.com/915641.
+    return Promise
+        .all([PolymerTest.flushTasks(), test_util.waitForRender(element)])
+        .then(() => {
+          assertNoSyncedTabsMessageShown(element, 'noSyncedResults');
+          const cards = getCards(element);
+          assertEquals(0, cards.length);
+        });
+  });
+
   teardown(function() {
     registerMessageCallback('openForeignSession', this, undefined);
     registerMessageCallback('deleteForeignSession', this, undefined);
diff --git a/chrome/test/data/webui/md_history/md_history_browsertest.js b/chrome/test/data/webui/md_history/md_history_browsertest.js
index ab8cc3b..eafbe18 100644
--- a/chrome/test/data/webui/md_history/md_history_browsertest.js
+++ b/chrome/test/data/webui/md_history/md_history_browsertest.js
@@ -190,6 +190,7 @@
   __proto__: MaterialHistoryBrowserTest.prototype,
 
   extraLibraries: MaterialHistoryBrowserTest.prototype.extraLibraries.concat([
+    '../settings/test_util.js',
     'history_synced_tabs_test.js',
   ]),
 };
diff --git a/chromeos/process_proxy/process_proxy_unittest.cc b/chromeos/process_proxy/process_proxy_unittest.cc
index 338925a..6a368d1d 100644
--- a/chromeos/process_proxy/process_proxy_unittest.cc
+++ b/chromeos/process_proxy/process_proxy_unittest.cc
@@ -206,6 +206,8 @@
   }
 
   void EndRegistryTest(base::OnceClosure done_closure) {
+    base::ScopedAllowBaseSyncPrimitivesForTesting allow_sync_primitives;
+
     registry_->CloseProcess(terminal_id_);
 
     int unused_exit_code = 0;
@@ -213,7 +215,6 @@
         base::GetTerminationStatus(terminal_id_, &unused_exit_code);
     EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status);
     if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
-      base::ScopedAllowBaseSyncPrimitivesForTesting allow_sync_primitives;
       base::Process process =
           base::Process::DeprecatedGetProcessFromHandle(terminal_id_);
       process.Terminate(0, true);
diff --git a/components/arc/video_accelerator/protected_buffer_manager.cc b/components/arc/video_accelerator/protected_buffer_manager.cc
index a6981ac..1ec0230b2 100644
--- a/components/arc/video_accelerator/protected_buffer_manager.cc
+++ b/components/arc/video_accelerator/protected_buffer_manager.cc
@@ -245,7 +245,8 @@
                                                     std::move(dummy_fd));
 }
 
-ProtectedBufferManager::ProtectedBufferManager() {
+ProtectedBufferManager::ProtectedBufferManager()
+    : next_protected_buffer_allocator_id_(0) {
   VLOGF(2);
 }
 
@@ -480,7 +481,6 @@
 }
 
 void ProtectedBufferManager::RemoveEntry(uint32_t id) {
-  buffer_map_lock_.AssertAcquired();
   VLOGF(2) << "id: " << id;
   auto num_erased = buffer_map_.erase(id);
   if (num_erased != 1)
@@ -489,7 +489,6 @@
 
 bool ProtectedBufferManager::CanAllocateFor(uint64_t allocator_id,
                                             uint32_t id) {
-  buffer_map_lock_.AssertAcquired();
   if (buffer_map_.find(id) != buffer_map_.end()) {
     VLOGF(1) << "A protected buffer for this handle already exists";
     return false;
diff --git a/components/arc/video_accelerator/protected_buffer_manager.h b/components/arc/video_accelerator/protected_buffer_manager.h
index e6eb108..67146d6 100644
--- a/components/arc/video_accelerator/protected_buffer_manager.h
+++ b/components/arc/video_accelerator/protected_buffer_manager.h
@@ -14,6 +14,7 @@
 #include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -111,23 +112,24 @@
                                                  uint32_t* id) const;
 
   // Removes an entry for given |id| from buffer_map_.
-  void RemoveEntry(uint32_t id);
+  void RemoveEntry(uint32_t id) EXCLUSIVE_LOCKS_REQUIRED(buffer_map_lock_);
 
   // Returns whether a protected buffer whose unique id is |id| can be
   // allocated by PBA whose allocator id is |allocator_id|.
-  bool CanAllocateFor(uint64_t allocator_id, uint32_t id);
+  bool CanAllocateFor(uint64_t allocator_id, uint32_t id)
+      EXCLUSIVE_LOCKS_REQUIRED(buffer_map_lock_);
 
   // A map of unique ids to the ProtectedBuffers associated with them.
   using ProtectedBufferMap =
       std::map<uint32_t, std::unique_ptr<ProtectedBuffer>>;
-  ProtectedBufferMap buffer_map_;
+  ProtectedBufferMap buffer_map_ GUARDED_BY(buffer_map_lock_);
   // A map of allocator ids to the unique ids of ProtectedBuffers allocated by
   // the allocator with the allocator id. The size is equal to the number of
   // active protected buffer allocators.
-  std::map<uint64_t, std::set<uint32_t>> allocator_to_buffers_map_;
-  uint64_t next_protected_buffer_allocator_id_ = 0;
-  // The lock for buffer_map_ and alocator_to_buffers_map_ and
-  // next_protected_buffer_allocator_id_.
+  std::map<uint64_t, std::set<uint32_t>> allocator_to_buffers_map_
+      GUARDED_BY(buffer_map_lock_);
+  uint64_t next_protected_buffer_allocator_id_ GUARDED_BY(buffer_map_lock_);
+
   base::Lock buffer_map_lock_;
 
   DISALLOW_COPY_AND_ASSIGN(ProtectedBufferManager);
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 877d6fcc..c38726b 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -182,8 +182,6 @@
           base::BindRepeating(&ProfileSyncService::ReconfigureDueToPassphrase,
                               base::Unretained(this)),
           &sync_prefs_),
-      signin_scoped_device_id_callback_(
-          init_params.signin_scoped_device_id_callback),
       network_time_update_callback_(
           std::move(init_params.network_time_update_callback)),
       url_loader_factory_(std::move(init_params.url_loader_factory)),
@@ -203,7 +201,6 @@
       sync_enabled_weak_factory_(this),
       weak_factory_(this) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(signin_scoped_device_id_callback_);
   DCHECK(sync_client_);
   DCHECK(local_device_);
 
@@ -635,8 +632,6 @@
 
   auth_manager_.reset();
 
-  signin_scoped_device_id_callback_.Reset();
-
   if (sync_thread_)
     sync_thread_->Stop();
 
@@ -966,8 +961,7 @@
   sync_js_controller_.AttachJsBackend(js_backend);
 
   // Initialize local device info.
-  local_device_->Initialize(cache_guid, session_name,
-                            signin_scoped_device_id_callback_.Run());
+  local_device_->Initialize(cache_guid, session_name);
 
   if (protocol_event_observers_.might_have_observers()) {
     engine_->RequestBufferedProtocolEventsAndEnableForwarding();
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index f1a6444..06e5f4297 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -155,8 +155,6 @@
                            public syncer::UnrecoverableErrorHandler,
                            public GaiaCookieManagerService::Observer {
  public:
-  using SigninScopedDeviceIdCallback = base::RepeatingCallback<std::string()>;
-
   // If AUTO_START, sync will set IsFirstSetupComplete() automatically and sync
   // will begin syncing without the user needing to confirm sync settings.
   enum StartBehavior {
@@ -183,8 +181,6 @@
 
     std::unique_ptr<syncer::SyncClient> sync_client;
     identity::IdentityManager* identity_manager = nullptr;
-    // TODO(mastiz): Move this to LocalDeviceInfoProviderImpl.
-    SigninScopedDeviceIdCallback signin_scoped_device_id_callback;
     GaiaCookieManagerService* gaia_cookie_manager_service = nullptr;
     std::vector<invalidation::IdentityProvider*>
         invalidations_identity_providers;
@@ -579,7 +575,6 @@
   // this object was created on.
   SEQUENCE_CHECKER(sequence_checker_);
 
-  SigninScopedDeviceIdCallback signin_scoped_device_id_callback_;
   // Cache of the last SyncCycleSnapshot received from the sync engine.
   syncer::SyncCycleSnapshot last_snapshot_;
 
diff --git a/components/browser_sync/profile_sync_test_util.cc b/components/browser_sync/profile_sync_test_util.cc
index 876cf0c..343def56 100644
--- a/components/browser_sync/profile_sync_test_util.cc
+++ b/components/browser_sync/profile_sync_test_util.cc
@@ -7,7 +7,6 @@
 #include <string>
 #include <utility>
 
-#include "base/bind.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
@@ -228,8 +227,6 @@
   init_params.start_behavior = start_behavior;
   init_params.sync_client = std::move(sync_client);
   init_params.identity_manager = identity_manager();
-  init_params.signin_scoped_device_id_callback =
-      base::BindRepeating([]() { return std::string(); });
   init_params.invalidations_identity_providers.push_back(
       identity_provider_.get());
   init_params.network_time_update_callback = base::DoNothing();
diff --git a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
index a9a4d88..88d1f79 100644
--- a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
+++ b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
@@ -203,6 +203,9 @@
   runTest("Calloc");
 }
 
+// GetCrashKeyValue() operates on a per-component basis, can't read the crash
+// key from the gwp_asan_client component in a component build.
+#if !defined(COMPONENT_BUILD)
 MULTIPROCESS_TEST_MAIN(CrashKey) {
   InstallAllocatorHooks(AllocatorState::kGpaMaxPages,
                         AllocatorState::kGpaMaxPages, kSamplingFrequency);
@@ -222,6 +225,7 @@
 TEST_F(SamplingAllocatorShimsTest, CrashKey) {
   runTest("CrashKey");
 }
+#endif  // !defined(COMPONENT_BUILD)
 
 MULTIPROCESS_TEST_MAIN(GetSizeEstimate) {
   InstallAllocatorHooks(AllocatorState::kGpaMaxPages,
diff --git a/components/invalidation/impl/fcm_invalidation_service.cc b/components/invalidation/impl/fcm_invalidation_service.cc
index 2a72bbe9..b922d6d 100644
--- a/components/invalidation/impl/fcm_invalidation_service.cc
+++ b/components/invalidation/impl/fcm_invalidation_service.cc
@@ -72,6 +72,8 @@
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DVLOG(2) << "Registering an invalidation handler";
   invalidator_registrar_.RegisterHandler(handler);
+  // Populate the id for newly registered handlers.
+  handler->OnInvalidatorClientIdChange(client_id_);
   logger_.OnRegistration(handler->GetOwnerName());
 }
 
@@ -223,9 +225,8 @@
   if (client_id_ != id) {
     client_id_ = id;
     pref_service_->SetString(prefs::kFCMInvalidationClientIDCache, id);
+    invalidator_registrar_.UpdateInvalidatorId(id);
   }
-  // TODO(melandory): Notify profile sync service that the invalidator
-  // id has changed;
 }
 
 void FCMInvalidationService::OnDeleteIDCompleted(
diff --git a/components/invalidation/impl/invalidator_registrar.cc b/components/invalidation/impl/invalidator_registrar.cc
index 502c7a60..d0238b2 100644
--- a/components/invalidation/impl/invalidator_registrar.cc
+++ b/components/invalidation/impl/invalidator_registrar.cc
@@ -119,6 +119,11 @@
     observer.OnInvalidatorStateChange(state);
 }
 
+void InvalidatorRegistrar::UpdateInvalidatorId(const std::string& id) {
+  for (auto& observer : handlers_)
+    observer.OnInvalidatorClientIdChange(id);
+}
+
 InvalidatorState InvalidatorRegistrar::GetInvalidatorState() const {
   DCHECK(thread_checker_.CalledOnValidThread());
   return state_;
diff --git a/components/invalidation/impl/invalidator_registrar.h b/components/invalidation/impl/invalidator_registrar.h
index 5e816f26..47072ce3 100644
--- a/components/invalidation/impl/invalidator_registrar.h
+++ b/components/invalidation/impl/invalidator_registrar.h
@@ -64,6 +64,10 @@
   // call GetInvalidatorState() when notified will see the new state.
   void UpdateInvalidatorState(InvalidatorState state);
 
+  // Updates the invalidator id to the given one and then notifies
+  // all handlers.
+  void UpdateInvalidatorId(const std::string& id);
+
   // Returns the current invalidator state.  When called from within
   // InvalidationHandler::OnInvalidatorStateChange(), this returns the
   // updated state.
diff --git a/components/invalidation/public/invalidation_handler.h b/components/invalidation/public/invalidation_handler.h
index 60cd1cb..0e247cd 100644
--- a/components/invalidation/public/invalidation_handler.h
+++ b/components/invalidation/public/invalidation_handler.h
@@ -29,6 +29,11 @@
 
   virtual std::string GetOwnerName() const = 0;
 
+  // Called on change of |client_id|. Client id is used to identify the
+  // the invalidator. The id is only relevant to some handlers, e.g. Sync
+  // where the reflection blocking logic is based on it.
+  virtual void OnInvalidatorClientIdChange(const std::string& client_id) {}
+
  protected:
   virtual ~InvalidationHandler();
 };
diff --git a/components/metrics/metrics_pref_names.cc b/components/metrics/metrics_pref_names.cc
index ae74ae2..5ab8d56 100644
--- a/components/metrics/metrics_pref_names.cc
+++ b/components/metrics/metrics_pref_names.cc
@@ -28,10 +28,16 @@
 // count info, etc.
 const char kMetricsInitialLogs[] = "user_experience_metrics.initial_logs2";
 
-// The metrics entropy source.
-// Note: The name low_entropy_source2 is a result of creating
-// new prefs to do a one-time reset of the previous values.
+// Low entropy source values. The new source (with suffix "3") was created
+// because the old source (with suffix "2") is biased in the wild. Clients which
+// have an old source still incorporate it into the high entropy source, to
+// avoid reshuffling experiments using high entropy, but use the new source for
+// experiments requiring low entropy. Newer clients only have the new source,
+// and use it both for low entropy experiments to to incorporate into the high
+// entropy source for high entropy experiments.
 const char kMetricsLowEntropySource[] =
+    "user_experience_metrics.low_entropy_source3";
+const char kMetricsOldLowEntropySource[] =
     "user_experience_metrics.low_entropy_source2";
 
 // A machine ID used to detect when underlying hardware changes. It is only
diff --git a/components/metrics/metrics_pref_names.h b/components/metrics/metrics_pref_names.h
index 9901968..3ce942bb 100644
--- a/components/metrics/metrics_pref_names.h
+++ b/components/metrics/metrics_pref_names.h
@@ -17,6 +17,7 @@
 extern const char kMetricsDefaultOptIn[];
 extern const char kMetricsInitialLogs[];
 extern const char kMetricsLowEntropySource[];
+extern const char kMetricsOldLowEntropySource[];
 extern const char kMetricsMachineId[];
 extern const char kMetricsOngoingLogs[];
 extern const char kMetricsResetIds[];
diff --git a/components/metrics/metrics_state_manager.cc b/components/metrics/metrics_state_manager.cc
index f4515c9..844ca15 100644
--- a/components/metrics/metrics_state_manager.cc
+++ b/components/metrics/metrics_state_manager.cc
@@ -4,15 +4,17 @@
 
 #include "components/metrics/metrics_state_manager.h"
 
-#include <stddef.h>
-#include <utility>
-
+#include <cstddef>
+#include <cstdint>
+#include <limits>
 #include <memory>
+#include <utility>
 
 #include "base/command_line.h"
 #include "base/guid.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_restrictions.h"
@@ -28,6 +30,7 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "components/variations/caching_permuted_entropy_provider.h"
+#include "components/variations/entropy_provider.h"
 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
 #include "third_party/metrics_proto/system_profile.pb.h"
 
@@ -40,22 +43,12 @@
 // [0, 7999] as the entropy source (12.97 bits of entropy).
 const int kMaxLowEntropySize = 8000;
 
-// Default prefs value for prefs::kMetricsLowEntropySource to indicate that
-// the value has not yet been set.
-const int kLowEntropySourceNotSet = -1;
-
 // Generates a new non-identifying entropy source used to seed persistent
 // activities.
 int GenerateLowEntropySource() {
   return base::RandInt(0, kMaxLowEntropySize - 1);
 }
 
-// Records the given |low_entorpy_source_value| in a histogram.
-void LogLowEntropyValue(int low_entropy_source_value) {
-  base::UmaHistogramSparse("UMA.LowEntropySourceValue",
-                           low_entropy_source_value);
-}
-
 int64_t ReadEnabledDate(PrefService* local_state) {
   return local_state->GetInt64(prefs::kMetricsReportingEnabledTimestamp);
 }
@@ -142,6 +135,7 @@
       load_client_info_(retrieve_client_info),
       clean_exit_beacon_(backup_registry_key, local_state),
       low_entropy_source_(kLowEntropySourceNotSet),
+      old_low_entropy_source_(kLowEntropySourceNotSet),
       entropy_source_returned_(ENTROPY_SOURCE_NONE),
       metrics_ids_were_reset_(false) {
   ResetMetricsIDsIfNecessary();
@@ -246,20 +240,9 @@
 std::unique_ptr<const base::FieldTrial::EntropyProvider>
 MetricsStateManager::CreateDefaultEntropyProvider() {
   if (enabled_state_provider_->IsConsentGiven()) {
-    // For metrics reporting-enabled users, we combine the client ID and low
-    // entropy source to get the final entropy source. Otherwise, only use the
-    // low entropy source.
-    // This has two useful properties:
-    //  1) It makes the entropy source less identifiable for parties that do not
-    //     know the low entropy source.
-    //  2) It makes the final entropy source resettable.
-    const int low_entropy_source_value = GetLowEntropySource();
-
     UpdateEntropySourceReturnedValue(ENTROPY_SOURCE_HIGH);
-    const std::string high_entropy_source =
-        client_id_ + base::IntToString(low_entropy_source_value);
     return std::unique_ptr<const base::FieldTrial::EntropyProvider>(
-        new variations::SHA1EntropyProvider(high_entropy_source));
+        new variations::SHA1EntropyProvider(GetHighEntropySource()));
   }
 
   UpdateEntropySourceReturnedValue(ENTROPY_SOURCE_LOW);
@@ -268,17 +251,9 @@
 
 std::unique_ptr<const base::FieldTrial::EntropyProvider>
 MetricsStateManager::CreateLowEntropyProvider() {
-  const int low_entropy_source_value = GetLowEntropySource();
-
-#if defined(OS_ANDROID) || defined(OS_IOS)
-  return std::unique_ptr<const base::FieldTrial::EntropyProvider>(
-      new variations::CachingPermutedEntropyProvider(
-          local_state_, low_entropy_source_value, kMaxLowEntropySize));
-#else
-  return std::unique_ptr<const base::FieldTrial::EntropyProvider>(
-      new variations::PermutedEntropyProvider(low_entropy_source_value,
-                                              kMaxLowEntropySize));
-#endif
+  int source = GetLowEntropySource();
+  return std::make_unique<variations::NormalizedMurmurHashEntropyProvider>(
+      base::checked_cast<uint16_t>(source), kMaxLowEntropySize);
 }
 
 // static
@@ -305,12 +280,17 @@
   registry->RegisterInt64Pref(prefs::kMetricsReportingEnabledTimestamp, 0);
   registry->RegisterIntegerPref(prefs::kMetricsLowEntropySource,
                                 kLowEntropySourceNotSet);
+  registry->RegisterIntegerPref(prefs::kMetricsOldLowEntropySource,
+                                kLowEntropySourceNotSet);
   registry->RegisterInt64Pref(prefs::kInstallDate, 0);
 
   ClonedInstallDetector::RegisterPrefs(registry);
   variations::CachingPermutedEntropyProvider::RegisterPrefs(registry);
 }
 
+// static
+constexpr int MetricsStateManager::kLowEntropySourceNotSet;
+
 void MetricsStateManager::BackUpCurrentClientInfo() {
   ClientInfo client_info;
   client_info.client_id = client_id_;
@@ -331,38 +311,86 @@
   return client_info;
 }
 
+std::string MetricsStateManager::GetHighEntropySource() {
+  // This should only be called if UMA is enabled, and if UMA is enabled, then
+  // the constructor should have loaded |client_id_|. The user shouldn't be able
+  // to enable UMA between the constructor and calling this, because field trial
+  // setup happens at Chrome initialization.
+  DCHECK(!client_id_.empty());
+
+  // For metrics reporting-enabled users, we combine the client ID and low
+  // entropy source to get the final entropy source.
+  // This has two useful properties:
+  //  1) It makes the entropy source less identifiable for parties that do not
+  //     know the low entropy source.
+  //  2) It makes the final entropy source resettable.
+
+  // If this install has an old low entropy source, continue using it, to avoid
+  // changing the group assignments of studies using high entropy. New installs
+  // only have the new low entropy source. If the number of installs with old
+  // sources ever becomes small enough (see UMA.LowEntropySourceValue), we could
+  // remove it, and just use the new source here.
+  int low_entropy_source = GetOldLowEntropySource();
+  if (low_entropy_source == kLowEntropySourceNotSet)
+    low_entropy_source = GetLowEntropySource();
+
+  return client_id_ + base::IntToString(low_entropy_source);
+}
+
 int MetricsStateManager::GetLowEntropySource() {
-  UpdateLowEntropySource();
+  UpdateLowEntropySources();
   return low_entropy_source_;
 }
 
-void MetricsStateManager::UpdateLowEntropySource() {
-  // Note that the default value for the low entropy source and the default pref
-  // value are both kLowEntropySourceNotSet, which is used to identify if the
-  // value has been set or not.
+int MetricsStateManager::GetOldLowEntropySource() {
+  UpdateLowEntropySources();
+  return old_low_entropy_source_;
+}
+
+void MetricsStateManager::UpdateLowEntropySources() {
+  // The default value for |low_entropy_source_| and the default pref value are
+  // both |kLowEntropySourceNotSet|, which indicates the value has not been set.
   if (low_entropy_source_ != kLowEntropySourceNotSet)
     return;
 
   const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
-  // Only try to load the value from prefs if the user did not request a
-  // reset.
-  // Otherwise, skip to generating a new value.
+  // Only try to load the value from prefs if the user did not request a reset.
+  // Otherwise, skip to generating a new value. We would have already returned
+  // if |low_entropy_source_| were set, ensuring we only do this reset on the
+  // first call to UpdateLowEntropySources().
   if (!command_line->HasSwitch(switches::kResetVariationState)) {
-    int value = local_state_->GetInteger(prefs::kMetricsLowEntropySource);
-    // If the value is outside the [0, kMaxLowEntropySize) range, re-generate
-    // it below.
-    if (value >= 0 && value < kMaxLowEntropySize) {
-      low_entropy_source_ = value;
-      LogLowEntropyValue(low_entropy_source_);
-      return;
-    }
+    int new_pref = local_state_->GetInteger(prefs::kMetricsLowEntropySource);
+    if (IsValidLowEntropySource(new_pref))
+      low_entropy_source_ = new_pref;
+    int old_pref = local_state_->GetInteger(prefs::kMetricsOldLowEntropySource);
+    if (IsValidLowEntropySource(old_pref))
+      old_low_entropy_source_ = old_pref;
   }
 
-  low_entropy_source_ = GenerateLowEntropySource();
-  LogLowEntropyValue(low_entropy_source_);
-  local_state_->SetInteger(prefs::kMetricsLowEntropySource,
-                           low_entropy_source_);
-  variations::CachingPermutedEntropyProvider::ClearCache(local_state_);
+  // If the new source is missing or corrupt (or requested to be reset), then
+  // (re)create it. Don't bother recreating the old source if it's corrupt,
+  // because we only keep the old source around for consistency, and we can't
+  // maintain a consistent value if we recreate it.
+  if (low_entropy_source_ == kLowEntropySourceNotSet) {
+    low_entropy_source_ = GenerateLowEntropySource();
+    DCHECK(IsValidLowEntropySource(low_entropy_source_));
+    local_state_->SetInteger(prefs::kMetricsLowEntropySource,
+                             low_entropy_source_);
+  }
+
+  // If the old source was present but corrupt (or requested to be reset), then
+  // we'll never use it again, so delete it.
+  if (old_low_entropy_source_ == kLowEntropySourceNotSet &&
+      local_state_->HasPrefPath(prefs::kMetricsOldLowEntropySource)) {
+    local_state_->ClearPref(prefs::kMetricsOldLowEntropySource);
+  }
+
+  DCHECK_NE(low_entropy_source_, kLowEntropySourceNotSet);
+  base::UmaHistogramSparse("UMA.LowEntropySource3Value", low_entropy_source_);
+  if (old_low_entropy_source_ != kLowEntropySourceNotSet) {
+    base::UmaHistogramSparse("UMA.LowEntropySourceValue",
+                             old_low_entropy_source_);
+  }
 }
 
 void MetricsStateManager::UpdateEntropySourceReturnedValue(
@@ -394,4 +422,9 @@
   store_client_info_.Run(ClientInfo());
 }
 
+// static
+bool MetricsStateManager::IsValidLowEntropySource(int value) {
+  return value >= 0 && value < kMaxLowEntropySize;
+}
+
 }  // namespace metrics
diff --git a/components/metrics/metrics_state_manager.h b/components/metrics/metrics_state_manager.h
index a1a15b34..f5cfd99 100644
--- a/components/metrics/metrics_state_manager.h
+++ b/components/metrics/metrics_state_manager.h
@@ -108,8 +108,16 @@
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, EntropySourceUsed_Low);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, EntropySourceUsed_High);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, LowEntropySource0NotReset);
+  FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, HaveNoLowEntropySource);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
-                           PermutedEntropyCacheClearedWhenLowEntropyReset);
+                           HaveOnlyNewLowEntropySource);
+  FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
+                           HaveOnlyOldLowEntropySource);
+  FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, HaveBothLowEntropySources);
+  FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
+                           CorruptNewLowEntropySources);
+  FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest,
+                           CorruptOldLowEntropySources);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, ResetBackup);
   FRIEND_TEST_ALL_PREFIXES(MetricsStateManagerTest, ResetMetricsIDs);
 
@@ -123,6 +131,9 @@
     ENTROPY_SOURCE_ENUM_SIZE,
   };
 
+  // Default value for prefs::kMetricsLowEntropySource.
+  static constexpr int kLowEntropySourceNotSet = -1;
+
   // Creates the MetricsStateManager with the given |local_state|. Uses
   // |enabled_state_provider| to query whether there is consent for metrics
   // reporting, and if it is enabled. Clients should instead use Create(), which
@@ -141,14 +152,26 @@
   // Loads the client info via |load_client_info_|.
   std::unique_ptr<ClientInfo> LoadClientInfo();
 
-  // Returns the low entropy source for this client. This is a random value
-  // that is non-identifying amongst browser clients. This method will
-  // generate the entropy source value if it has not been called before.
+  // Returns the high entropy source for this client, which is composed of the
+  // client ID and the low entropy source. This is intended to be unique for
+  // each install. UMA must be enabled (and |client_id_| must be set) before
+  // calling this.
+  std::string GetHighEntropySource();
+
+  // Returns the low entropy source for this client. Generates a new value if
+  // there is none. See the |low_entropy_source_| comment for more info.
   int GetLowEntropySource();
 
-  // Generates the low entropy source value for this client if it is not
-  // already set.
-  void UpdateLowEntropySource();
+  // Returns the old low entropy source for this client. Does not generate a new
+  // value, but instead returns |kLowEntropySourceNotSet|, if there is none. See
+  // the |old_low_entropy_source_| comment for more info.
+  int GetOldLowEntropySource();
+
+  // Loads the low entropy source values from prefs. Creates the new source
+  // value if it doesn't exist, but doesn't create the old source value. After
+  // this function finishes, |low_entropy_source_| will be set, but
+  // |old_low_entropy_source_| may still be |kLowEntropySourceNotSet|.
+  void UpdateLowEntropySources();
 
   // Updates |entropy_source_returned_| with |type| iff the current value is
   // ENTROPY_SOURCE_NONE and logs the new value in a histogram.
@@ -165,6 +188,10 @@
   // pref is true.
   void ResetMetricsIDsIfNecessary();
 
+  // Checks whether a value is on the range of allowed low entropy source
+  // values.
+  static bool IsValidLowEntropySource(int value);
+
   // Whether an instance of this class exists. Used to enforce that there aren't
   // multiple instances of this class at a given time.
   static bool instance_exists_;
@@ -191,8 +218,14 @@
   // The identifier that's sent to the server with the log reports.
   std::string client_id_;
 
-  // The non-identifying low entropy source value.
+  // The non-identifying low entropy source values. These values seed the
+  // pseudorandom generators which pick experimental groups. The "old" value is
+  // thought to be biased in the wild, and is no longer used for experiments
+  // requiring low entropy. Clients which already have an "old" value continue
+  // incorporating it into the high entropy source, to avoid changing those
+  // group assignments. New clients only have the new source.
   int low_entropy_source_;
+  int old_low_entropy_source_;
 
   // The last entropy source returned by this service, used for testing.
   EntropySourceType entropy_source_returned_;
diff --git a/components/metrics/metrics_state_manager_unittest.cc b/components/metrics/metrics_state_manager_unittest.cc
index 0e1f1481..a17d5087 100644
--- a/components/metrics/metrics_state_manager_unittest.cc
+++ b/components/metrics/metrics_state_manager_unittest.cc
@@ -14,6 +14,8 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "components/metrics/client_info.h"
 #include "components/metrics/metrics_log.h"
@@ -161,48 +163,105 @@
   EXPECT_EQ(0, state_manager->GetLowEntropySource());
 }
 
-TEST_F(MetricsStateManagerTest,
-       PermutedEntropyCacheClearedWhenLowEntropyReset) {
-  const PrefService::Preference* low_entropy_pref =
-      prefs_.FindPreference(prefs::kMetricsLowEntropySource);
-  const char* kCachePrefName =
-      variations::prefs::kVariationsPermutedEntropyCache;
-  int low_entropy_value = -1;
+TEST_F(MetricsStateManagerTest, HaveNoLowEntropySource) {
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+  state_manager->client_id_ = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+  // If we have neither the new nor old low entropy sources in prefs, then the
+  // new source should be created...
+  int new_low_source = state_manager->GetLowEntropySource();
+  EXPECT_TRUE(MetricsStateManager::IsValidLowEntropySource(new_low_source))
+      << new_low_source;
+  // ...but the old source should not...
+  EXPECT_EQ(MetricsStateManager::kLowEntropySourceNotSet,
+            state_manager->GetOldLowEntropySource());
+  // ...and the high entropy source should include the *new* low entropy source.
+  std::string high_source = state_manager->GetHighEntropySource();
+  EXPECT_TRUE(base::EndsWith(high_source, base::IntToString(new_low_source),
+                             base::CompareCase::SENSITIVE))
+      << high_source;
+}
 
-  // First, generate an initial low entropy source value.
-  {
-    EXPECT_TRUE(low_entropy_pref->IsDefaultValue());
+TEST_F(MetricsStateManagerTest, HaveOnlyNewLowEntropySource) {
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+  state_manager->client_id_ = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+  // If we have the new low entropy sources in prefs, but not the old one...
+  const int new_low_source = 1234;
+  prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
+  // ...then the new source should be loaded...
+  EXPECT_EQ(new_low_source, state_manager->GetLowEntropySource());
+  // ...but the old source should not be created...
+  EXPECT_EQ(MetricsStateManager::kLowEntropySourceNotSet,
+            state_manager->GetOldLowEntropySource());
+  // ...and the high entropy source should include the *new* low entropy source.
+  std::string high_source = state_manager->GetHighEntropySource();
+  EXPECT_TRUE(base::EndsWith(high_source, base::IntToString(new_low_source),
+                             base::CompareCase::SENSITIVE))
+      << high_source;
+}
 
-    std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
-    state_manager->GetLowEntropySource();
+TEST_F(MetricsStateManagerTest, HaveOnlyOldLowEntropySource) {
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+  state_manager->client_id_ = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+  // If we have the old low entropy sources in prefs, but not the new one...
+  const int old_low_source = 5678;
+  prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
+  // ...then the new source should be created...
+  int new_low_source = state_manager->GetLowEntropySource();
+  EXPECT_TRUE(MetricsStateManager::IsValidLowEntropySource(new_low_source))
+      << new_low_source;
+  // ...and the old source should be loaded...
+  EXPECT_EQ(old_low_source, state_manager->GetOldLowEntropySource());
+  // ...and the high entropy source should include the *old* low entropy source.
+  std::string high_source = state_manager->GetHighEntropySource();
+  EXPECT_TRUE(base::EndsWith(high_source, base::IntToString(old_low_source),
+                             base::CompareCase::SENSITIVE))
+      << high_source;
+}
 
-    EXPECT_FALSE(low_entropy_pref->IsDefaultValue());
-    EXPECT_TRUE(low_entropy_pref->GetValue()->GetAsInteger(&low_entropy_value));
+TEST_F(MetricsStateManagerTest, HaveBothLowEntropySources) {
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+  state_manager->client_id_ = "AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEF";
+  // If we have the new and old low entropy sources in prefs...
+  const int new_low_source = 1234;
+  const int old_low_source = 5678;
+  prefs_.SetInteger(prefs::kMetricsLowEntropySource, new_low_source);
+  prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, old_low_source);
+  // ...then both should be loaded...
+  EXPECT_EQ(new_low_source, state_manager->GetLowEntropySource());
+  EXPECT_EQ(old_low_source, state_manager->GetOldLowEntropySource());
+  // ...and the high entropy source should include the *old* low entropy source.
+  std::string high_source = state_manager->GetHighEntropySource();
+  EXPECT_TRUE(base::EndsWith(high_source, base::IntToString(old_low_source),
+                             base::CompareCase::SENSITIVE))
+      << high_source;
+}
+
+TEST_F(MetricsStateManagerTest, CorruptNewLowEntropySources) {
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+  const int corrupt_sources[] = {-12345, -1, 8000, 12345};
+  for (int corrupt_source : corrupt_sources) {
+    // If the new low entropy source has been corrupted...
+    EXPECT_FALSE(MetricsStateManager::IsValidLowEntropySource(corrupt_source))
+        << corrupt_source;
+    prefs_.SetInteger(prefs::kMetricsLowEntropySource, corrupt_source);
+    // ...then a new source should be created.
+    int loaded_source = state_manager->GetLowEntropySource();
+    EXPECT_TRUE(MetricsStateManager::IsValidLowEntropySource(loaded_source))
+        << loaded_source;
   }
+}
 
-  // Now, set a dummy value in the permuted entropy cache pref and verify that
-  // another call to GetLowEntropySource() doesn't clobber it when
-  // --reset-variation-state wasn't specified.
-  {
-    prefs_.SetString(kCachePrefName, "test");
-
-    std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
-    state_manager->GetLowEntropySource();
-
-    EXPECT_EQ("test", prefs_.GetString(kCachePrefName));
-    EXPECT_EQ(low_entropy_value,
-              prefs_.GetInteger(prefs::kMetricsLowEntropySource));
-  }
-
-  // Verify that the cache does get reset if --reset-variations-state is passed.
-  {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kResetVariationState);
-
-    std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
-    state_manager->GetLowEntropySource();
-
-    EXPECT_TRUE(prefs_.GetString(kCachePrefName).empty());
+TEST_F(MetricsStateManagerTest, CorruptOldLowEntropySources) {
+  std::unique_ptr<MetricsStateManager> state_manager(CreateStateManager());
+  const int corrupt_sources[] = {-12345, -1, 8000, 12345};
+  for (int corrupt_source : corrupt_sources) {
+    // If the old low entropy source has been corrupted...
+    EXPECT_FALSE(MetricsStateManager::IsValidLowEntropySource(corrupt_source))
+        << corrupt_source;
+    prefs_.SetInteger(prefs::kMetricsOldLowEntropySource, corrupt_source);
+    // ...then it should be ignored.
+    EXPECT_EQ(MetricsStateManager::kLowEntropySourceNotSet,
+              state_manager->GetOldLowEntropySource());
   }
 }
 
diff --git a/components/policy/core/common/cloud/external_policy_data_fetcher.cc b/components/policy/core/common/cloud/external_policy_data_fetcher.cc
index 24b4450..54bbbe38 100644
--- a/components/policy/core/common/cloud/external_policy_data_fetcher.cc
+++ b/components/policy/core/common/cloud/external_policy_data_fetcher.cc
@@ -227,7 +227,14 @@
       weak_factory_(this) {}
 
 ExternalPolicyDataFetcher::~ExternalPolicyDataFetcher() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  // No RunsTasksInCurrentSequence() check to avoid unit tests failures.
+  // In unit tests the browser process instance is deleted only after test ends
+  // and test task scheduler is shutted down. Therefore we need to delete some
+  // components of BrowserPolicyConnector (ResourceCache and
+  // CloudExternalDataManagerBase::Backend) manually when task runner doesn't
+  // accept new tasks (DeleteSoon in this case). This leads to the situation
+  // when this destructor is called not on |task_runner|.
+
   for (auto it = jobs_.begin(); it != jobs_.end(); ++it)
     CancelJob(*it);
 }
diff --git a/components/policy/core/common/cloud/external_policy_data_updater.cc b/components/policy/core/common/cloud/external_policy_data_updater.cc
index effd1e99..e68b2058 100644
--- a/components/policy/core/common/cloud/external_policy_data_updater.cc
+++ b/components/policy/core/common/cloud/external_policy_data_updater.cc
@@ -306,7 +306,14 @@
 }
 
 ExternalPolicyDataUpdater::~ExternalPolicyDataUpdater() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  // No RunsTasksInCurrentSequence() check to avoid unit tests failures.
+  // In unit tests the browser process instance is deleted only after test ends
+  // and test task scheduler is shutted down. Therefore we need to delete some
+  // components of BrowserPolicyConnector (ResourceCache and
+  // CloudExternalDataManagerBase::Backend) manually when task runner doesn't
+  // accept new tasks (DeleteSoon in this case). This leads to the situation
+  // when this destructor is called not on |task_runner|.
+
   // Raise the flag to prevent jobs from being started during the destruction of
   // |job_map_|.
   shutting_down_ = true;
diff --git a/components/policy/core/common/cloud/resource_cache.cc b/components/policy/core/common/cloud/resource_cache.cc
index 008ea3d..4541f22 100644
--- a/components/policy/core/common/cloud/resource_cache.cc
+++ b/components/policy/core/common/cloud/resource_cache.cc
@@ -59,7 +59,13 @@
 }
 
 ResourceCache::~ResourceCache() {
-  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  // No RunsTasksInCurrentSequence() check to avoid unit tests failures.
+  // In unit tests the browser process instance is deleted only after test ends
+  // and test task scheduler is shutted down. Therefore we need to delete some
+  // components of BrowserPolicyConnector (ResourceCache and
+  // CloudExternalDataManagerBase::Backend) manually when task runner doesn't
+  // accept new tasks (DeleteSoon in this case). This leads to the situation
+  // when this destructor is called not on |task_runner|.
 }
 
 bool ResourceCache::Store(const std::string& key,
diff --git a/components/sync/device_info/local_device_info_provider.h b/components/sync/device_info/local_device_info_provider.h
index 7ff6b5b..7d13e37 100644
--- a/components/sync/device_info/local_device_info_provider.h
+++ b/components/sync/device_info/local_device_info_provider.h
@@ -43,8 +43,7 @@
 
   // Initializes the local device info.
   virtual void Initialize(const std::string& cache_guid,
-                          const std::string& session_name,
-                          const std::string& signin_scoped_device_id) = 0;
+                          const std::string& session_name) = 0;
 
   // Registers a callback to be called when local device info becomes available.
   // The callback will remain registered until the
diff --git a/components/sync/device_info/local_device_info_provider_impl.cc b/components/sync/device_info/local_device_info_provider_impl.cc
index 5b42c212..2d65dbf 100644
--- a/components/sync/device_info/local_device_info_provider_impl.cc
+++ b/components/sync/device_info/local_device_info_provider_impl.cc
@@ -34,12 +34,14 @@
 LocalDeviceInfoProviderImpl::LocalDeviceInfoProviderImpl(
     version_info::Channel channel,
     const std::string& version,
-    bool is_tablet)
+    bool is_tablet,
+    const SigninScopedDeviceIdCallback& signin_scoped_device_id_callback)
     : channel_(channel),
       version_(version),
       is_tablet_(is_tablet),
+      signin_scoped_device_id_callback_(signin_scoped_device_id_callback),
       weak_factory_(this) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(signin_scoped_device_id_callback_);
 }
 
 LocalDeviceInfoProviderImpl::~LocalDeviceInfoProviderImpl() {
@@ -74,17 +76,15 @@
   return callback_list_.Add(callback);
 }
 
-void LocalDeviceInfoProviderImpl::Initialize(
-    const std::string& cache_guid,
-    const std::string& session_name,
-    const std::string& signin_scoped_device_id) {
+void LocalDeviceInfoProviderImpl::Initialize(const std::string& cache_guid,
+                                             const std::string& session_name) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(!cache_guid.empty());
   cache_guid_ = cache_guid;
 
   local_device_info_ = std::make_unique<DeviceInfo>(
       cache_guid, session_name, version_, GetSyncUserAgent(),
-      GetLocalDeviceType(is_tablet_), signin_scoped_device_id);
+      GetLocalDeviceType(is_tablet_), signin_scoped_device_id_callback_.Run());
 
   // Notify observers.
   callback_list_.Notify();
diff --git a/components/sync/device_info/local_device_info_provider_impl.h b/components/sync/device_info/local_device_info_provider_impl.h
index 0268004..c3f5217 100644
--- a/components/sync/device_info/local_device_info_provider_impl.h
+++ b/components/sync/device_info/local_device_info_provider_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/callback_forward.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequence_checker.h"
@@ -19,9 +20,13 @@
 
 class LocalDeviceInfoProviderImpl : public LocalDeviceInfoProvider {
  public:
-  LocalDeviceInfoProviderImpl(version_info::Channel channel,
-                              const std::string& version,
-                              bool is_tablet);
+  using SigninScopedDeviceIdCallback = base::RepeatingCallback<std::string()>;
+
+  LocalDeviceInfoProviderImpl(
+      version_info::Channel channel,
+      const std::string& version,
+      bool is_tablet,
+      const SigninScopedDeviceIdCallback& signin_scoped_device_id_callback);
   ~LocalDeviceInfoProviderImpl() override;
 
   // LocalDeviceInfoProvider implementation.
@@ -31,8 +36,7 @@
   std::string GetLocalSyncCacheGUID() const override;
 
   void Initialize(const std::string& cache_guid,
-                  const std::string& session_name,
-                  const std::string& signin_scoped_device_id) override;
+                  const std::string& session_name) override;
   std::unique_ptr<Subscription> RegisterOnInitializedCallback(
       const base::Closure& callback) override;
   void Clear() override;
@@ -48,6 +52,8 @@
   // devices).
   const bool is_tablet_;
 
+  const SigninScopedDeviceIdCallback signin_scoped_device_id_callback_;
+
   std::string cache_guid_;
   std::unique_ptr<DeviceInfo> local_device_info_;
   base::CallbackList<void(void)> callback_list_;
diff --git a/components/sync/device_info/local_device_info_provider_impl_unittest.cc b/components/sync/device_info/local_device_info_provider_impl_unittest.cc
index 61e70e9b..ea808ea 100644
--- a/components/sync/device_info/local_device_info_provider_impl_unittest.cc
+++ b/components/sync/device_info/local_device_info_provider_impl_unittest.cc
@@ -4,14 +4,19 @@
 
 #include "components/sync/device_info/local_device_info_provider_impl.h"
 
+#include "base/test/mock_callback.h"
 #include "components/version_info/version_string.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
+namespace {
 
 const char kLocalDeviceGuid[] = "foo";
 const char kLocalDeviceSessionName[] = "bar";
-const char kSigninScopedDeviceId[] = "device_id";
+
+using testing::NotNull;
+using testing::Return;
 
 class LocalDeviceInfoProviderImplTest : public testing::Test {
  public:
@@ -21,7 +26,8 @@
   void SetUp() override {
     provider_ = std::make_unique<LocalDeviceInfoProviderImpl>(
         version_info::Channel::UNKNOWN,
-        version_info::GetVersionStringWithModifier("UNKNOWN"), false);
+        version_info::GetVersionStringWithModifier("UNKNOWN"), false,
+        signin_scoped_device_id_callback_.Get());
   }
 
   void TearDown() override {
@@ -32,23 +38,24 @@
   void InitializeProvider() { InitializeProvider(kLocalDeviceGuid); }
 
   void InitializeProvider(const std::string& guid) {
-    provider_->Initialize(guid, kLocalDeviceSessionName, kSigninScopedDeviceId);
+    provider_->Initialize(guid, kLocalDeviceSessionName);
   }
 
+  testing::NiceMock<base::MockCallback<
+      LocalDeviceInfoProviderImpl::SigninScopedDeviceIdCallback>>
+      signin_scoped_device_id_callback_;
   std::unique_ptr<LocalDeviceInfoProviderImpl> provider_;
 };
 
 TEST_F(LocalDeviceInfoProviderImplTest, GetLocalDeviceInfo) {
   ASSERT_EQ(nullptr, provider_->GetLocalDeviceInfo());
+
   InitializeProvider();
 
   const DeviceInfo* local_device_info = provider_->GetLocalDeviceInfo();
   ASSERT_NE(nullptr, local_device_info);
   EXPECT_EQ(std::string(kLocalDeviceGuid), local_device_info->guid());
-  EXPECT_EQ(std::string(kSigninScopedDeviceId),
-            local_device_info->signin_scoped_device_id());
   EXPECT_EQ(kLocalDeviceSessionName, local_device_info->client_name());
-
   EXPECT_EQ(provider_->GetSyncUserAgent(),
             local_device_info->sync_user_agent());
 
@@ -56,6 +63,19 @@
   ASSERT_EQ(nullptr, provider_->GetLocalDeviceInfo());
 }
 
+TEST_F(LocalDeviceInfoProviderImplTest, GetSigninScopedDeviceId) {
+  const std::string kSigninScopedDeviceId = "device_id";
+
+  EXPECT_CALL(signin_scoped_device_id_callback_, Run())
+      .WillOnce(Return(kSigninScopedDeviceId));
+
+  InitializeProvider();
+
+  ASSERT_THAT(provider_->GetLocalDeviceInfo(), NotNull());
+  EXPECT_EQ(kSigninScopedDeviceId,
+            provider_->GetLocalDeviceInfo()->signin_scoped_device_id());
+}
+
 TEST_F(LocalDeviceInfoProviderImplTest, GetLocalSyncCacheGUID) {
   EXPECT_TRUE(provider_->GetLocalSyncCacheGUID().empty());
 
@@ -66,4 +86,5 @@
   EXPECT_TRUE(provider_->GetLocalSyncCacheGUID().empty());
 }
 
+}  // namespace
 }  // namespace syncer
diff --git a/components/sync/device_info/local_device_info_provider_mock.cc b/components/sync/device_info/local_device_info_provider_mock.cc
index 7203c69..c16872e21 100644
--- a/components/sync/device_info/local_device_info_provider_mock.cc
+++ b/components/sync/device_info/local_device_info_provider_mock.cc
@@ -41,13 +41,11 @@
   return local_device_info_ ? local_device_info_->guid() : "";
 }
 
-void LocalDeviceInfoProviderMock::Initialize(
-    const std::string& cache_guid,
-    const std::string& session_name,
-    const std::string& signin_scoped_device_id) {
+void LocalDeviceInfoProviderMock::Initialize(const std::string& cache_guid,
+                                             const std::string& session_name) {
   local_device_info_ = std::make_unique<DeviceInfo>(
       cache_guid, session_name, "chrome_version", GetSyncUserAgent(),
-      sync_pb::SyncEnums_DeviceType_TYPE_LINUX, signin_scoped_device_id);
+      sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "signin-scoped-device-id");
   SetInitialized(true);
 }
 
diff --git a/components/sync/device_info/local_device_info_provider_mock.h b/components/sync/device_info/local_device_info_provider_mock.h
index c08fd0cd..1e69ce6 100644
--- a/components/sync/device_info/local_device_info_provider_mock.h
+++ b/components/sync/device_info/local_device_info_provider_mock.h
@@ -32,8 +32,7 @@
   std::string GetSyncUserAgent() const override;
   std::string GetLocalSyncCacheGUID() const override;
   void Initialize(const std::string& cache_guid,
-                  const std::string& session_name,
-                  const std::string& signin_scoped_device_id) override;
+                  const std::string& session_name) override;
   std::unique_ptr<Subscription> RegisterOnInitializedCallback(
       const base::Closure& callback) override;
   void Clear() override;
diff --git a/components/sync/driver/glue/sync_backend_host_core.cc b/components/sync/driver/glue/sync_backend_host_core.cc
index e979aa45..795f04c6 100644
--- a/components/sync/driver/glue/sync_backend_host_core.cc
+++ b/components/sync/driver/glue/sync_backend_host_core.cc
@@ -601,6 +601,11 @@
   }
 }
 
+void SyncBackendHostCore::DoOnInvalidatorClientIdChange(
+    const std::string& client_id) {
+  sync_manager_->UpdateInvalidationClientId(client_id);
+}
+
 bool SyncBackendHostCore::HasUnsyncedItemsForTest() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(sync_manager_);
diff --git a/components/sync/driver/glue/sync_backend_host_core.h b/components/sync/driver/glue/sync_backend_host_core.h
index f072aa3..dced9de 100644
--- a/components/sync/driver/glue/sync_backend_host_core.h
+++ b/components/sync/driver/glue/sync_backend_host_core.h
@@ -171,6 +171,9 @@
                             bool empty_jar,
                             const base::Closure& callback);
 
+  // Notify about change in client id.
+  void DoOnInvalidatorClientIdChange(const std::string& client_id);
+
   bool HasUnsyncedItemsForTest() const;
 
  private:
diff --git a/components/sync/driver/glue/sync_backend_host_impl.cc b/components/sync/driver/glue/sync_backend_host_impl.cc
index c819d628..914ffd3 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.cc
+++ b/components/sync/driver/glue/sync_backend_host_impl.cc
@@ -476,6 +476,14 @@
   DCHECK(success);
 }
 
+void SyncBackendHostImpl::OnInvalidatorClientIdChange(
+    const std::string& client_id) {
+  sync_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SyncBackendHostCore::DoOnInvalidatorClientIdChange, core_,
+                     client_id));
+}
+
 void SyncBackendHostImpl::ClearServerDataDoneOnFrontendLoop(
     const base::Closure& frontend_callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/components/sync/driver/glue/sync_backend_host_impl.h b/components/sync/driver/glue/sync_backend_host_impl.h
index a1ef596..7771c364 100644
--- a/components/sync/driver/glue/sync_backend_host_impl.h
+++ b/components/sync/driver/glue/sync_backend_host_impl.h
@@ -100,6 +100,7 @@
   void OnIncomingInvalidation(
       const ObjectIdInvalidationMap& invalidation_map) override;
   std::string GetOwnerName() const override;
+  void OnInvalidatorClientIdChange(const std::string& client_id) override;
 
  protected:
   // The types and functions below are protected so that test
diff --git a/components/sync/engine/fake_sync_manager.cc b/components/sync/engine/fake_sync_manager.cc
index 13788efd..f2d05d1 100644
--- a/components/sync/engine/fake_sync_manager.cc
+++ b/components/sync/engine/fake_sync_manager.cc
@@ -270,4 +270,8 @@
   NOTIMPLEMENTED();
 }
 
+void FakeSyncManager::UpdateInvalidationClientId(const std::string&) {
+  NOTIMPLEMENTED();
+}
+
 }  // namespace syncer
diff --git a/components/sync/engine/fake_sync_manager.h b/components/sync/engine/fake_sync_manager.h
index 67731215..e073c3a0 100644
--- a/components/sync/engine/fake_sync_manager.h
+++ b/components/sync/engine/fake_sync_manager.h
@@ -119,6 +119,7 @@
   void ClearServerData(const base::Closure& callback) override;
   void OnCookieJarChanged(bool account_mismatch, bool empty_jar) override;
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+  void UpdateInvalidationClientId(const std::string&) override;
 
  private:
   scoped_refptr<base::SequencedTaskRunner> sync_task_runner_;
diff --git a/components/sync/engine/sync_manager.h b/components/sync/engine/sync_manager.h
index ff57456..514b05be 100644
--- a/components/sync/engine/sync_manager.h
+++ b/components/sync/engine/sync_manager.h
@@ -397,6 +397,9 @@
 
   // Adds memory usage statistics to |pmd| for chrome://tracing.
   virtual void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) = 0;
+
+  // Updates invalidation client id.
+  virtual void UpdateInvalidationClientId(const std::string& client_id) = 0;
 };
 
 }  // namespace syncer
diff --git a/components/sync/engine_impl/cycle/sync_cycle_context.h b/components/sync/engine_impl/cycle/sync_cycle_context.h
index 7ba80b7..b3a9099 100644
--- a/components/sync/engine_impl/cycle/sync_cycle_context.h
+++ b/components/sync/engine_impl/cycle/sync_cycle_context.h
@@ -103,6 +103,10 @@
     return invalidator_client_id_;
   }
 
+  void set_invalidator_client_id(const std::string& id) {
+    invalidator_client_id_ = id;
+  }
+
   bool ShouldFetchUpdatesBeforeCommit() const {
     return !(server_enabled_pre_commit_update_avoidance_ ||
              client_enabled_pre_commit_update_avoidance_);
@@ -174,7 +178,7 @@
   // register itself with the invalidations server during startup.  We need to
   // provide this to the sync server when we make changes to enable it to
   // prevent us from receiving notifications of changes we make ourselves.
-  const std::string invalidator_client_id_;
+  std::string invalidator_client_id_;
 
   // Flag to enable or disable the no pre-commit GetUpdates experiment.  When
   // this flag is set to false, the syncer has the option of not performing at
diff --git a/components/sync/engine_impl/sync_manager_impl.cc b/components/sync/engine_impl/sync_manager_impl.cc
index aff06d59..a35bf89 100644
--- a/components/sync/engine_impl/sync_manager_impl.cc
+++ b/components/sync/engine_impl/sync_manager_impl.cc
@@ -979,4 +979,10 @@
   directory()->OnMemoryDump(pmd);
 }
 
+void SyncManagerImpl::UpdateInvalidationClientId(const std::string& client_id) {
+  DVLOG(1) << "Setting invalidator client ID: " << client_id;
+  allstatus_.SetInvalidatorClientId(client_id);
+  cycle_context_->set_invalidator_client_id(client_id);
+}
+
 }  // namespace syncer
diff --git a/components/sync/engine_impl/sync_manager_impl.h b/components/sync/engine_impl/sync_manager_impl.h
index ef78b26..4a6f7f4 100644
--- a/components/sync/engine_impl/sync_manager_impl.h
+++ b/components/sync/engine_impl/sync_manager_impl.h
@@ -111,6 +111,7 @@
   void ClearServerData(const base::Closure& callback) override;
   void OnCookieJarChanged(bool account_mismatch, bool empty_jar) override;
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd) override;
+  void UpdateInvalidationClientId(const std::string& client_id) override;
 
   // SyncEncryptionHandler::Observer implementation.
   void OnPassphraseRequired(
diff --git a/components/tracing/common/stack_unwinder_android.cc b/components/tracing/common/stack_unwinder_android.cc
index e5187f2b..75f8e3c 100644
--- a/components/tracing/common/stack_unwinder_android.cc
+++ b/components/tracing/common/stack_unwinder_android.cc
@@ -9,6 +9,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <syscall.h>
+#include <unistd.h>
 #include "link.h"
 
 #include <algorithm>
@@ -524,7 +525,13 @@
   // SIGURG is chosen here because we observe no crashes with this signal and
   // neither Chrome or the AOSP sets up a special handler for this signal.
   if (!sigaction(SIGURG, &act, &oact)) {
-    kill(tid, SIGURG);
+    // Android renderer process knows the pid of the process. This might need to
+    // be fixed for use on Linux.
+    static const int kPid = getpid();
+    if (tgkill(kPid, tid, SIGURG) != 0) {
+      NOTREACHED();
+      return false;
+    }
     bool finished_waiting = wait_event.Wait();
 
     bool changed = sigaction(SIGURG, &oact, &act) == 0;
diff --git a/components/translate/ios/browser/translate_controller.mm b/components/translate/ios/browser/translate_controller.mm
index 35e33e4..bfb1c12 100644
--- a/components/translate/ios/browser/translate_controller.mm
+++ b/components/translate/ios/browser/translate_controller.mm
@@ -251,10 +251,16 @@
     std::unique_ptr<std::string> response_body) {
   const std::unique_ptr<network::SimpleURLLoader>& url_loader = *it;
 
-  std::string response_url = url_loader->GetFinalURL().spec();
-  net::HttpResponseHeaders* headers = url_loader->ResponseInfo()->headers.get();
-  int response_code = headers->response_code();
-  const std::string& status_text = headers->GetStatusText();
+  // |ResponseInfo()| may be a nullptr if response is incomplete.
+  int response_code = 0;
+  std::string status_text;
+  const network::ResourceResponseHead* response_head =
+      url_loader->ResponseInfo();
+  if (response_head && response_head->headers) {
+    net::HttpResponseHeaders* headers = response_head->headers.get();
+    response_code = headers->response_code();
+    status_text = headers->GetStatusText();
+  }
 
   // Escape the returned string so it can be parsed by JSON.parse.
   std::string response_text = response_body ? *response_body : "";
@@ -266,7 +272,7 @@
   std::string script = base::StringPrintf(
       "__gCrWeb.translate.handleResponse('%s', %d, %d, '%s', '%s', '%s')",
       url.c_str(), request_id, response_code, status_text.c_str(),
-      response_url.c_str(), escaped_response_text.c_str());
+      url_loader->GetFinalURL().spec().c_str(), escaped_response_text.c_str());
   web_state_->ExecuteJavaScript(base::UTF8ToUTF16(script));
 
   request_fetchers_.erase(it);
diff --git a/components/url_formatter/BUILD.gn b/components/url_formatter/BUILD.gn
index 1f19aa7a5..85e0992f 100644
--- a/components/url_formatter/BUILD.gn
+++ b/components/url_formatter/BUILD.gn
@@ -27,6 +27,7 @@
   deps = [
     "//base",
     "//base:i18n",
+    "//components/url_formatter/top_domains:common",
     "//components/url_formatter/top_domains:generate_top_domains_trie",
     "//net",
     "//net:preload_decoder",
diff --git a/components/url_formatter/top_domains/BUILD.gn b/components/url_formatter/top_domains/BUILD.gn
index 0eb8ee6f..4abbbec0 100644
--- a/components/url_formatter/top_domains/BUILD.gn
+++ b/components/url_formatter/top_domains/BUILD.gn
@@ -72,9 +72,9 @@
     "make_top_domain_list_for_edit_distance.cc",
   ]
   deps = [
+    ":common",
     "//base",
     "//base:i18n",
-    "//net",
     "//third_party/icu",
   ]
   if (is_ios) {
@@ -82,6 +82,17 @@
   }
 }
 
+source_set("common") {
+  sources = [
+    "top_domain_util.cc",
+    "top_domain_util.h",
+  ]
+
+  deps = [
+    "//net",
+  ]
+}
+
 # TODO(crbug/915921): Combine this and the previous one into a
 # compiled_action_foreach target.
 compiled_action("generate_top_domains_for_edit_distance") {
diff --git a/components/url_formatter/top_domains/make_top_domain_list_for_edit_distance.cc b/components/url_formatter/top_domains/make_top_domain_list_for_edit_distance.cc
index 8177829..a85649a2 100644
--- a/components/url_formatter/top_domains/make_top_domain_list_for_edit_distance.cc
+++ b/components/url_formatter/top_domains/make_top_domain_list_for_edit_distance.cc
@@ -19,15 +19,13 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "components/url_formatter/top_domains/top_domain_util.h"
 #include "third_party/icu/source/common/unicode/unistr.h"
 #include "third_party/icu/source/common/unicode/utypes.h"
 #include "third_party/icu/source/i18n/unicode/uspoof.h"
 
 namespace {
 
-const size_t kMinLengthForEditDistance = 5u;
-
 const size_t kTopN = 500;
 
 void PrintHelp() {
@@ -35,23 +33,6 @@
             << " <output-file> [--v=1]" << std::endl;
 }
 
-// Returns the length of the hostname without the registry part and the
-// dot preceeding it.
-// E.g. For hostname = "google.com", the registry is "com", so this returns 6
-// (length of "google").
-size_t GetWithoutRegistryLength(const std::string& hostname) {
-  const size_t registry_size =
-      net::registry_controlled_domains::PermissiveGetHostRegistryLength(
-          hostname.c_str(),
-          net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
-          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
-  if (registry_size == 0) {
-    return hostname.size();
-  }
-  DCHECK_LE(registry_size, hostname.size() - 1);
-  return hostname.size() - registry_size - 1;
-}
-
 std::string GetSkeleton(const std::string& domain,
                         const USpoofChecker* spoof_checker) {
   UErrorCode status = U_ZERO_ERROR;
@@ -123,7 +104,7 @@
     }
     if (count > kTopN)
       break;
-    if (GetWithoutRegistryLength(line) < kMinLengthForEditDistance) {
+    if (!url_formatter::top_domains::IsEditDistanceCandidate(line)) {
       continue;
     }
     count++;
diff --git a/components/url_formatter/top_domains/top_domain_util.cc b/components/url_formatter/top_domains/top_domain_util.cc
new file mode 100644
index 0000000..e1099e7
--- /dev/null
+++ b/components/url_formatter/top_domains/top_domain_util.cc
@@ -0,0 +1,42 @@
+// 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/url_formatter/top_domains/top_domain_util.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+
+namespace url_formatter {
+
+namespace top_domains {
+
+namespace {
+
+// Minimum length for a hostname to be considered for an edit distance
+// comparison. Shorter domains are ignored.
+const size_t kMinLengthForEditDistance = 5u;
+
+// Returns the portion of hostname without the registry part.
+// E.g. For hostname = "google.com", the registry is "com", and the return value
+// will be 6 (length of "google").
+size_t GetWithoutRegistryLength(const std::string& hostname) {
+  const size_t registry_size =
+      net::registry_controlled_domains::PermissiveGetHostRegistryLength(
+          hostname.c_str(),
+          net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
+          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+  if (registry_size == 0) {
+    return hostname.size();
+  }
+  DCHECK_LE(registry_size, hostname.size() - 1);
+  return hostname.size() - registry_size - 1;
+}
+
+}  // namespace
+
+bool IsEditDistanceCandidate(const std::string& hostname) {
+  return GetWithoutRegistryLength(hostname) >= kMinLengthForEditDistance;
+}
+
+}  // namespace top_domains
+
+}  // namespace url_formatter
diff --git a/components/url_formatter/top_domains/top_domain_util.h b/components/url_formatter/top_domains/top_domain_util.h
new file mode 100644
index 0000000..f9774ce
--- /dev/null
+++ b/components/url_formatter/top_domains/top_domain_util.h
@@ -0,0 +1,22 @@
+// 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_URL_FORMATTER_TOP_DOMAINS_TOP_DOMAIN_UTIL_H_
+#define COMPONENTS_URL_FORMATTER_TOP_DOMAINS_TOP_DOMAIN_UTIL_H_
+
+#include <string>
+
+namespace url_formatter {
+
+namespace top_domains {
+
+// Returns true if |hostname| should be considered for an edit distance
+// comparison. Will generally return false for short domain names.
+bool IsEditDistanceCandidate(const std::string& hostname);
+
+}  // namespace top_domains
+
+}  // namespace url_formatter
+
+#endif  // COMPONENTS_URL_FORMATTER_TOP_DOMAINS_TOP_DOMAIN_UTIL_H_
diff --git a/components/variations/caching_permuted_entropy_provider.h b/components/variations/caching_permuted_entropy_provider.h
index 141e001c..a515e7f7 100644
--- a/components/variations/caching_permuted_entropy_provider.h
+++ b/components/variations/caching_permuted_entropy_provider.h
@@ -21,7 +21,8 @@
 
 // CachingPermutedEntropyProvider is an entropy provider that uses the same
 // algorithm as the PermutedEntropyProvider, but caches the results in Local
-// State between runs.
+// State between runs. Replaced by NormalizedMurmurHashEntropyProvider.
+// TODO(crbug/912368): Remove this.
 class CachingPermutedEntropyProvider : public PermutedEntropyProvider {
  public:
   // Creates a CachingPermutedEntropyProvider using the given |local_state|
diff --git a/components/variations/entropy_provider.cc b/components/variations/entropy_provider.cc
index cea9aa6e..b59c81a 100644
--- a/components/variations/entropy_provider.cc
+++ b/components/variations/entropy_provider.cc
@@ -87,7 +87,7 @@
   // Note: If |entropy_source_| has very low entropy, such as 13 bits or less,
   // it has been observed that this method does not result in a uniform
   // distribution given the same |trial_name|. When using such a low entropy
-  // source, PermutedEntropyProvider should be used instead.
+  // source, NormalizedMurmurHashEntropyProvider should be used instead.
   std::string input(entropy_source_);
   input.append(randomization_seed == 0 ? trial_name : base::UintToString(
                                                           randomization_seed));
diff --git a/components/variations/pref_names.cc b/components/variations/pref_names.cc
index 6e01e80..733ac98c 100644
--- a/components/variations/pref_names.cc
+++ b/components/variations/pref_names.cc
@@ -33,8 +33,9 @@
 const char kVariationsPermanentConsistencyCountry[] =
     "variations_permanent_consistency_country";
 
-// A serialized PermutedEntropyCache protobuf, used as a cache to avoid
-// recomputing permutations.
+// Previously used by CachingPermutedEntropyProvider, which has been replaced by
+// NormalizedMurmurHashEntropyProvider.
+// TODO(crbug/912368): Clear this from prefs when removing old entropy provider.
 const char kVariationsPermutedEntropyCache[] =
     "user_experience_metrics.permuted_entropy_cache";
 
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 154b8398..a43a30d 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1019,6 +1019,17 @@
       base::BindOnce(
           base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed), true));
 
+  // Also allow waiting to join threads.
+  // TODO(https://crbug.com/800808): Ideally this (and the above SetIOAllowed()
+  // would be scoped allowances). That would be one of the first step to ensure
+  // no persistent work is being done after TaskScheduler::Shutdown() in order
+  // to move towards atomic shutdown.
+  base::ThreadRestrictions::SetWaitAllowed(true);
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(
+          base::IgnoreResult(&base::ThreadRestrictions::SetWaitAllowed), true));
+
 #if defined(OS_ANDROID)
   g_browser_main_loop_shutting_down = true;
 #endif
@@ -1096,16 +1107,13 @@
     save_file_manager_->Shutdown();
 
   {
-    base::ScopedAllowBaseSyncPrimitives allow_wait_for_join;
-    {
-      TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread");
-      ResetThread_IO(std::move(io_thread_));
-    }
+    TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:IOThread");
+    ResetThread_IO(std::move(io_thread_));
+  }
 
-    {
-      TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:TaskScheduler");
-      base::TaskScheduler::GetInstance()->Shutdown();
-    }
+  {
+    TRACE_EVENT0("shutdown", "BrowserMainLoop::Subsystem:TaskScheduler");
+    base::TaskScheduler::GetInstance()->Shutdown();
   }
 
   // Must happen after the IO thread is shutdown since this may be accessed from
diff --git a/content/browser/devtools/devtools_http_handler.cc b/content/browser/devtools/devtools_http_handler.cc
index 42134d8b..2fab142 100644
--- a/content/browser/devtools/devtools_http_handler.cc
+++ b/content/browser/devtools/devtools_http_handler.cc
@@ -223,7 +223,8 @@
     thread->task_runner()->DeleteSoon(FROM_HERE, std::move(socket_factory));
   if (thread) {
     base::PostTaskWithTraits(
-        FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
+        FROM_HERE,
+        {base::WithBaseSyncPrimitives(), base::TaskPriority::BEST_EFFORT},
         BindOnce([](std::unique_ptr<base::Thread>) {}, std::move(thread)));
   }
 }
diff --git a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
index 9c2ff28..5c361d43 100644
--- a/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
+++ b/content/browser/devtools/protocol/devtools_protocol_browsertest.cc
@@ -56,6 +56,7 @@
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/layout.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/compositor/compositor_switches.h"
 #include "ui/gfx/codec/jpeg_codec.h"
 #include "ui/gfx/codec/png_codec.h"
@@ -501,6 +502,9 @@
 };
 
 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshot) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   // This test fails consistently on low-end Android devices.
   // See crbug.com/653637.
   // TODO(eseckler): Reenable with error limit if necessary.
@@ -523,6 +527,9 @@
 }
 
 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, CaptureScreenshotJpeg) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   // This test fails consistently on low-end Android devices.
   // See crbug.com/653637.
   // TODO(eseckler): Reenable with error limit if necessary.
@@ -577,6 +584,9 @@
 // of a page that does not specify one.
 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest,
                        SetDefaultBackgroundColorOverride) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   if (base::SysInfo::IsLowEndDevice())
     return;
 
@@ -617,6 +627,9 @@
 // and semi-transparent background, and that setDeviceMetricsOverride doesn't
 // affect it.
 IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, TransparentScreenshots) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   if (base::SysInfo::IsLowEndDevice())
     return;
 
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 492f013e..e7f2a6d 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -1770,7 +1770,7 @@
             .SetSignature(base::HexEncode(sig.sig.data(), sig.sig.size()))
             .SetIntegrity(sig.integrity)
             .SetCertUrl(sig.cert_url.spec())
-            .SetValidityUrl(sig.validity_url.spec())
+            .SetValidityUrl(sig.validity_url.url.spec())
             .SetDate(sig.date)
             .SetExpires(sig.expires)
             .Build();
@@ -1797,7 +1797,7 @@
 
     signed_exchange_info->SetHeader(
         Network::SignedExchangeHeader::Create()
-            .SetRequestUrl(envelope->request_url().spec())
+            .SetRequestUrl(envelope->request_url().url.spec())
             .SetRequestMethod(envelope->request_method())
             .SetResponseCode(envelope->response_code())
             .SetResponseHeaders(Object::fromValue(headers_dict.get(), nullptr))
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index f3512e10..424158e 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -2062,6 +2062,7 @@
 void NavigationControllerImpl::NavigateFromFrameProxy(
     RenderFrameHostImpl* render_frame_host,
     const GURL& url,
+    const url::Origin& initiator_origin,
     bool is_renderer_initiated,
     SiteInstance* source_site_instance,
     const Referrer& referrer,
@@ -2146,6 +2147,7 @@
   }
 
   LoadURLParams params(url);
+  params.initiator_origin = initiator_origin;
   params.source_site_instance = source_site_instance;
   params.load_type = method == "POST" ? LOAD_TYPE_HTTP_POST : LOAD_TYPE_DEFAULT;
   params.transition_type = page_transition;
@@ -2803,6 +2805,10 @@
     FrameNavigationEntry* frame_entry) {
   DCHECK_EQ(-1, GetIndexOfEntry(&entry));
   DCHECK(frame_entry);
+  // TODO(nasko): Enforce this check once all code is updated to supply
+  // initiator_origin for renderer initiated navigations.
+  // DCHECK(!params.is_renderer_initiated ||
+  // params.initiator_origin.has_value());
 
   GURL url_to_load;
   GURL virtual_url;
@@ -2884,10 +2890,10 @@
   const GURL& history_url_for_data_url =
       params.base_url_for_data_url.is_empty() ? GURL() : virtual_url;
   CommonNavigationParams common_params(
-      url_to_load, params.referrer, params.transition_type, navigation_type,
-      download_policy, should_replace_current_entry,
-      params.base_url_for_data_url, history_url_for_data_url, previews_state,
-      navigation_start,
+      url_to_load, params.initiator_origin, params.referrer,
+      params.transition_type, navigation_type, download_policy,
+      should_replace_current_entry, params.base_url_for_data_url,
+      history_url_for_data_url, previews_state, navigation_start,
       params.load_type == LOAD_TYPE_HTTP_POST ? "POST" : "GET",
       params.post_data, base::Optional<SourceLocation>(),
       params.started_from_context_menu, has_user_gesture, InitiatorCSPInfo(),
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index 130f2b9..e7e2d32 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -108,6 +108,7 @@
   void NavigateFromFrameProxy(
       RenderFrameHostImpl* render_frame_host,
       const GURL& url,
+      const url::Origin& initiator_origin,
       bool is_renderer_initiated,
       SiteInstance* source_site_instance,
       const Referrer& referrer,
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 70a2b5f..788962ca 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -665,6 +665,7 @@
   NavigationControllerImpl& controller = controller_impl();
 
   NavigationController::LoadURLParams load_params(GURL("http://foo/2"));
+  load_params.initiator_origin = url::Origin::Create(url1);
   load_params.referrer = Referrer(GURL("http://referrer"),
                                   network::mojom::ReferrerPolicy::kDefault);
   load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
@@ -3439,6 +3440,7 @@
   // For link clicks (renderer-initiated navigations), the pending entry should
   // update before commit but the visible should not.
   NavigationController::LoadURLParams load_url_params(url1);
+  load_url_params.initiator_origin = url::Origin::Create(url0);
   load_url_params.is_renderer_initiated = true;
   controller.LoadURLWithParams(load_url_params);
   entry_id = controller.GetPendingEntry()->GetUniqueID();
@@ -3468,6 +3470,7 @@
   // we show the pending entry's URL as long as the about:blank page is not
   // modified.
   NavigationController::LoadURLParams load_url_params(url);
+  load_url_params.initiator_origin = url::Origin();
   load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
   load_url_params.is_renderer_initiated = true;
   controller.LoadURLWithParams(load_url_params);
@@ -3541,6 +3544,7 @@
   // we show the pending entry's URL as long as the about:blank page is not
   // modified.
   NavigationController::LoadURLParams load_url_params(url);
+  load_url_params.initiator_origin = url::Origin();
   load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
   load_url_params.is_renderer_initiated = true;
   controller.LoadURLWithParams(load_url_params);
@@ -3582,6 +3586,7 @@
   // we show the pending entry's URL as long as the about:blank page is not
   // modified.
   NavigationController::LoadURLParams load_url_params(url1);
+  load_url_params.initiator_origin = url::Origin();
   load_url_params.transition_type = ui::PAGE_TRANSITION_LINK;
   load_url_params.is_renderer_initiated = true;
   controller.LoadURLWithParams(load_url_params);
@@ -3595,6 +3600,7 @@
   main_test_rfh()->PrepareForCommit();
   main_test_rfh()->SendNavigate(entry_id, true, url1);
   NavigationController::LoadURLParams load_url2_params(url2);
+  load_url2_params.initiator_origin = url::Origin::Create(url1);
   load_url2_params.transition_type = ui::PAGE_TRANSITION_LINK;
   load_url2_params.is_renderer_initiated = true;
   controller.LoadURLWithParams(load_url2_params);
@@ -5339,7 +5345,7 @@
   FrameTreeNode* subframe_node =
       main_test_rfh()->frame_tree_node()->child_at(0);
   controller_impl().NavigateFromFrameProxy(
-      subframe_node->current_frame_host(), kSrcDoc,
+      subframe_node->current_frame_host(), kSrcDoc, url::Origin::Create(kUrl2),
       true /* is_renderer_initiated */, main_test_rfh()->GetSiteInstance(),
       Referrer(), ui::PAGE_TRANSITION_LINK,
       false /* should_replace_current_entry */, "GET", nullptr, "", nullptr);
diff --git a/content/browser/frame_host/navigation_entry_impl.cc b/content/browser/frame_host/navigation_entry_impl.cc
index f799af2..6a8cdf37 100644
--- a/content/browser/frame_host/navigation_entry_impl.cc
+++ b/content/browser/frame_host/navigation_entry_impl.cc
@@ -697,7 +697,10 @@
       IsViewSourceMode() ? NavigationDownloadPolicy::kDisallowViewSource
                          : NavigationDownloadPolicy::kAllow;
   return CommonNavigationParams(
-      dest_url, dest_referrer, GetTransitionType(), navigation_type,
+      dest_url,
+      // This is constructing parameters for browser-initiated navigation,
+      // therefore there is no initiator origin.
+      base::nullopt, dest_referrer, GetTransitionType(), navigation_type,
       download_policy, should_replace_entry(), GetBaseURLForDataURL(),
       GetHistoryURLForDataURL(), previews_state, navigation_start,
       frame_entry.method(), post_body ? post_body : post_data_,
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 5129a1e1..115f298 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -299,18 +299,12 @@
   // This is not currently handled here.
   bool is_form_submission = !!post_body;
 
-  base::Optional<url::Origin> initiator =
-      frame_tree_node->IsMainFrame()
-          ? base::Optional<url::Origin>()
-          : base::Optional<url::Origin>(
-                frame_tree_node->frame_tree()->root()->current_origin());
-
   auto navigation_params = mojom::BeginNavigationParams::New(
       extra_headers, net::LOAD_NORMAL, false /* skip_service_worker */,
       blink::mojom::RequestContextType::LOCATION,
       blink::WebMixedContentContextType::kBlockable, is_form_submission,
       GURL() /* searchable_form_url */,
-      std::string() /* searchable_form_encoding */, initiator,
+      std::string() /* searchable_form_encoding */,
       GURL() /* client_side_redirect_url */,
       base::nullopt /* devtools_initiator_info */);
 
@@ -365,9 +359,9 @@
       0,                              // nav_entry_id
       false,                          // is_history_navigation_in_new_child
       std::map<std::string, bool>(),  // subframe_unique_names
-      false,  // intended_as_new_entry
-      -1,     // |pending_history_list_offset| is set to -1 because
-              // history-navigations do not use this path. See comments above.
+      false,                          // intended_as_new_entry
+      -1,  // |pending_history_list_offset| is set to -1 because
+           // history-navigations do not use this path. See comments above.
       current_history_list_offset, current_history_list_length,
       false,  // is_view_source
       false /*should_clear_history_list*/);
@@ -394,7 +388,9 @@
   // TODO(clamy): Improve the *NavigationParams and *CommitParams to avoid
   // copying so many parameters here.
   CommonNavigationParams common_params(
-      params.url, params.referrer, params.transition,
+      params.url,
+      // TODO(nasko): Investigate better value to pass for |initiator_origin|.
+      params.origin, params.referrer, params.transition,
       is_same_document ? FrameMsg_Navigate_Type::SAME_DOCUMENT
                        : FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT,
       NavigationDownloadPolicy::kAllow, params.should_replace_current_entry,
@@ -538,7 +534,7 @@
         common_params_.navigation_type,
         frame_tree_node_->navigator()->GetController()->GetBrowserContext(),
         common_params.method, user_agent_override,
-        common_params_.has_user_gesture, begin_params_->initiator_origin,
+        common_params_.has_user_gesture, common_params.initiator_origin,
         frame_tree_node);
 
     if (begin_params_->is_form_submission) {
@@ -1627,7 +1623,7 @@
       auto resource_request = std::make_unique<network::ResourceRequest>();
       resource_request->url = common_params_.url;
       resource_request->method = common_params_.method;
-      resource_request->request_initiator = begin_params_->initiator_origin;
+      resource_request->request_initiator = common_params_.initiator_origin;
       resource_request->referrer = common_params_.referrer.url;
       resource_request->has_user_gesture = common_params_.has_user_gesture;
 
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index 0673b9c..4d2d481 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -104,6 +104,7 @@
   virtual void RequestOpenURL(
       RenderFrameHostImpl* render_frame_host,
       const GURL& url,
+      const base::Optional<url::Origin>& initiator_origin,
       bool uses_post,
       const scoped_refptr<network::ResourceRequestBody>& body,
       const std::string& extra_headers,
@@ -121,6 +122,7 @@
   virtual void NavigateFromFrameProxy(
       RenderFrameHostImpl* render_frame_host,
       const GURL& url,
+      const url::Origin& initiator_origin,
       SiteInstance* source_site_instance,
       const Referrer& referrer,
       ui::PageTransition page_transition,
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index ae68881..69dacd0f 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -389,6 +389,7 @@
 void NavigatorImpl::RequestOpenURL(
     RenderFrameHostImpl* render_frame_host,
     const GURL& url,
+    const base::Optional<url::Origin>& initiator_origin,
     bool uses_post,
     const scoped_refptr<network::ResourceRequestBody>& body,
     const std::string& extra_headers,
@@ -447,6 +448,7 @@
   params.should_replace_current_entry = should_replace_current_entry;
   params.user_gesture = user_gesture;
   params.triggering_event_info = triggering_event_info;
+  params.initiator_origin = initiator_origin;
 
   // RequestOpenURL is used only for local frames, so we can get here only if
   // the navigation is initiated by a frame in the same SiteInstance as this
@@ -482,6 +484,7 @@
 void NavigatorImpl::NavigateFromFrameProxy(
     RenderFrameHostImpl* render_frame_host,
     const GURL& url,
+    const url::Origin& initiator_origin,
     SiteInstance* source_site_instance,
     const Referrer& referrer,
     ui::PageTransition page_transition,
@@ -535,9 +538,10 @@
       &referrer_to_use);
 
   controller_->NavigateFromFrameProxy(
-      render_frame_host, url, is_renderer_initiated, source_site_instance,
-      referrer_to_use, page_transition, should_replace_current_entry, method,
-      post_body, extra_headers, std::move(blob_url_loader_factory));
+      render_frame_host, url, initiator_origin, is_renderer_initiated,
+      source_site_instance, referrer_to_use, page_transition,
+      should_replace_current_entry, method, post_body, extra_headers,
+      std::move(blob_url_loader_factory));
 }
 
 void NavigatorImpl::OnBeforeUnloadACK(FrameTreeNode* frame_tree_node,
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index 533d097..3b729d1 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -60,6 +60,7 @@
                 RestoreType restore_type) override;
   void RequestOpenURL(RenderFrameHostImpl* render_frame_host,
                       const GURL& url,
+                      const base::Optional<url::Origin>& initiator_origin,
                       bool uses_post,
                       const scoped_refptr<network::ResourceRequestBody>& body,
                       const std::string& extra_headers,
@@ -74,6 +75,7 @@
   void NavigateFromFrameProxy(
       RenderFrameHostImpl* render_frame_host,
       const GURL& url,
+      const url::Origin& initiator_origin,
       SiteInstance* source_site_instance,
       const Referrer& referrer,
       ui::PageTransition page_transition,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 82e0edc..1fa0a79ed0 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2071,10 +2071,10 @@
                validated_url.possibly_invalid_spec());
 
   frame_tree_node_->navigator()->RequestOpenURL(
-      this, validated_url, params.uses_post, params.resource_request_body,
-      params.extra_headers, params.referrer, params.disposition,
-      params.should_replace_current_entry, params.user_gesture,
-      params.triggering_event_info, params.href_translate,
+      this, validated_url, params.initiator_origin, params.uses_post,
+      params.resource_request_body, params.extra_headers, params.referrer,
+      params.disposition, params.should_replace_current_entry,
+      params.user_gesture, params.triggering_event_info, params.href_translate,
       std::move(blob_url_loader_factory));
 }
 
@@ -4154,7 +4154,7 @@
                "frame_tree_node", frame_tree_node_->frame_tree_node_id());
   DCHECK(data_url.SchemeIs(url::kDataScheme));
   CommonNavigationParams common_params(
-      data_url, Referrer(), ui::PAGE_TRANSITION_LINK,
+      data_url, base::nullopt, Referrer(), ui::PAGE_TRANSITION_LINK,
       FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT,
       NavigationDownloadPolicy::kDisallowInterstitial, false, GURL(), GURL(),
       PREVIEWS_OFF, base::TimeTicks::Now(), "GET", nullptr,
diff --git a/content/browser/frame_host/render_frame_proxy_host.cc b/content/browser/frame_host/render_frame_proxy_host.cc
index cfa3fd1..46c6f8f 100644
--- a/content/browser/frame_host/render_frame_proxy_host.cc
+++ b/content/browser/frame_host/render_frame_proxy_host.cc
@@ -327,10 +327,11 @@
   // TODO(clamy): The transition should probably be changed for POST navigations
   // to PAGE_TRANSITION_FORM_SUBMIT. See https://crbug.com/829827.
   frame_tree_node_->navigator()->NavigateFromFrameProxy(
-      current_rfh, validated_url, site_instance_.get(), params.referrer,
-      ui::PAGE_TRANSITION_LINK, params.should_replace_current_entry,
-      params.uses_post ? "POST" : "GET", params.resource_request_body,
-      params.extra_headers, std::move(blob_url_loader_factory));
+      current_rfh, validated_url, params.initiator_origin, site_instance_.get(),
+      params.referrer, ui::PAGE_TRANSITION_LINK,
+      params.should_replace_current_entry, params.uses_post ? "POST" : "GET",
+      params.resource_request_body, params.extra_headers,
+      std::move(blob_url_loader_factory));
 }
 
 void RenderFrameProxyHost::OnCheckCompleted() {
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index d3acc08..e2595330 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -1271,7 +1271,7 @@
                 base::MakeRefCounted<network::ResourceResponse>()));
 
   ASSERT_FALSE(url_loader_client_.has_received_response());
-  url_loader_client_.RunUntilResponseReceived();
+  url_loader_client_.RunUntilResponseBodyArrived();
 
   ASSERT_EQ(MockResourceLoader::Status::IDLE, mock_loader_->OnWillRead());
 
@@ -1328,7 +1328,7 @@
   ASSERT_EQ(MockResourceLoader::Status::IDLE,
             mock_loader_->OnReadCompleted("B"));
 
-  ASSERT_TRUE(url_loader_client_.response_body().is_valid());
+  ASSERT_TRUE(url_loader_client_.has_received_response());
   url_loader_client_.RunUntilResponseBodyArrived();
   ASSERT_TRUE(url_loader_client_.response_body().is_valid());
 
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index da0f0227..f396081c 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -223,7 +223,7 @@
   // been copied from ResourceDispatcherHostImpl. We did not refactor the
   // common code into a function, because RDHI uses accessor functions on the
   // URLRequest class to set these fields. whereas we use ResourceRequest here.
-  new_request->request_initiator = request_info->begin_params->initiator_origin;
+  new_request->request_initiator = request_info->common_params.initiator_origin;
   new_request->referrer = request_info->common_params.referrer.url;
   new_request->referrer_policy = Referrer::ReferrerPolicyForUrlRequest(
       request_info->common_params.referrer.policy);
diff --git a/content/browser/loader/navigation_url_loader_impl_unittest.cc b/content/browser/loader/navigation_url_loader_impl_unittest.cc
index 3dd219a..75b7d1a 100644
--- a/content/browser/loader/navigation_url_loader_impl_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_impl_unittest.cc
@@ -171,11 +171,12 @@
             blink::WebMixedContentContextType::kBlockable,
             false /* is_form_submission */, GURL() /* searchable_form_url */,
             std::string() /* searchable_form_encoding */,
-            url::Origin::Create(url), GURL() /* client_side_redirect_url */,
+            GURL() /* client_side_redirect_url */,
             base::nullopt /* devtools_initiator_info */);
 
     CommonNavigationParams common_params;
     common_params.url = url;
+    common_params.initiator_origin = url::Origin::Create(url);
     common_params.method = method;
     common_params.download_policy = download_policy;
 
diff --git a/content/browser/loader/navigation_url_loader_unittest.cc b/content/browser/loader/navigation_url_loader_unittest.cc
index a90bfba..9b8e9c0 100644
--- a/content/browser/loader/navigation_url_loader_unittest.cc
+++ b/content/browser/loader/navigation_url_loader_unittest.cc
@@ -87,10 +87,11 @@
             blink::WebMixedContentContextType::kBlockable,
             false /* is_form_submission */, GURL() /* searchable_form_url */,
             std::string() /* searchable_form_encoding */,
-            url::Origin::Create(url), GURL() /* client_side_redirect_url */,
+            GURL() /* client_side_redirect_url */,
             base::nullopt /* devtools_initiator_info */);
     CommonNavigationParams common_params;
     common_params.url = url;
+    common_params.initiator_origin = url::Origin::Create(url);
 
     std::unique_ptr<NavigationRequestInfo> request_info(
         new NavigationRequestInfo(common_params, std::move(begin_params), url,
diff --git a/content/browser/loader/prefetch_browsertest.cc b/content/browser/loader/prefetch_browsertest.cc
index 011142e..88b8f1fbf 100644
--- a/content/browser/loader/prefetch_browsertest.cc
+++ b/content/browser/loader/prefetch_browsertest.cc
@@ -343,7 +343,8 @@
       // We mock the SignedExchangeHandler, so just return a HTML content
       // as "application/signed-exchange;v=b2".
       ResponseEntry("<head><title>Prefetch Target (SXG)</title></head>",
-                    "application/signed-exchange;v=b2"));
+                    "application/signed-exchange;v=b2",
+                    {{"x-content-type-options", "nosniff"}}));
   RegisterResponse(preload_url_in_sxg,
                    ResponseEntry("function foo() {}", "text/javascript"));
 
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 2831e90..9f62b45 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1476,7 +1476,7 @@
   new_request->set_method(info.common_params.method);
   new_request->set_site_for_cookies(info.site_for_cookies);
   new_request->set_top_frame_origin(info.top_frame_origin);
-  new_request->set_initiator(info.begin_params->initiator_origin);
+  new_request->set_initiator(info.common_params.initiator_origin);
   new_request->set_upgrade_if_insecure(info.upgrade_if_insecure);
   if (info.is_main_frame) {
     new_request->set_first_party_url_policy(
diff --git a/content/browser/loader/resource_dispatcher_host_unittest.cc b/content/browser/loader/resource_dispatcher_host_unittest.cc
index 43919fe..bb23f50 100644
--- a/content/browser/loader/resource_dispatcher_host_unittest.cc
+++ b/content/browser/loader/resource_dispatcher_host_unittest.cc
@@ -837,10 +837,12 @@
             blink::WebMixedContentContextType::kBlockable,
             false /* is_form_submission */, GURL() /* searchable_form_url */,
             std::string() /* searchable_form_encoding */,
-            url::Origin::Create(url), GURL() /* client_side_redirect_url */,
+            GURL() /* client_side_redirect_url */,
             base::nullopt /* devtools_initiator_info */);
     CommonNavigationParams common_params;
     common_params.url = url;
+    common_params.initiator_origin = url::Origin::Create(url);
+
     std::unique_ptr<NavigationRequestInfo> request_info(
         new NavigationRequestInfo(common_params, std::move(begin_params), url,
                                   url::Origin::Create(url), true, false, false,
diff --git a/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc b/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
index a47a717b..724aa82 100644
--- a/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
+++ b/content/browser/media/capture/aura_window_video_capture_device_browsertest.cc
@@ -23,6 +23,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/aura/window.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -223,6 +224,9 @@
 // stopped.
 IN_PROC_BROWSER_TEST_F(AuraWindowVideoCaptureDeviceBrowserTest,
                        ErrorsOutWhenWindowIsDestroyed) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   NavigateToInitialDocument();
   AllocateAndStartAndWaitForFirstFrame();
 
@@ -245,6 +249,9 @@
 // to be delivered, to ensure the client is up-to-date.
 IN_PROC_BROWSER_TEST_F(AuraWindowVideoCaptureDeviceBrowserTest,
                        SuspendsAndResumes) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   NavigateToInitialDocument();
   AllocateAndStartAndWaitForFirstFrame();
 
@@ -279,6 +286,9 @@
 // content is not changing.
 IN_PROC_BROWSER_TEST_F(AuraWindowVideoCaptureDeviceBrowserTest,
                        DeliversRefreshFramesUponRequest) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   NavigateToInitialDocument();
   AllocateAndStartAndWaitForFirstFrame();
 
@@ -333,6 +343,9 @@
 // compositing.
 IN_PROC_BROWSER_TEST_P(AuraWindowVideoCaptureDeviceBrowserTestP,
                        CapturesContentChanges) {
+  // TODO(crbug.com/877172): CopyOutputRequests not allowed.
+  if (features::IsSingleProcessMash())
+    return;
   SCOPED_TRACE(testing::Message()
                << "Test parameters: "
                << (IsSoftwareCompositingTest() ? "Software Compositing"
diff --git a/content/browser/media/capture/content_capture_device_browsertest_base.cc b/content/browser/media/capture/content_capture_device_browsertest_base.cc
index fbac608..354826c 100644
--- a/content/browser/media/capture/content_capture_device_browsertest_base.cc
+++ b/content/browser/media/capture/content_capture_device_browsertest_base.cc
@@ -13,6 +13,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test.h"
 #include "content/public/test/content_browser_test_utils.h"
@@ -153,6 +154,26 @@
   base::RunLoop().RunUntilIdle();
 }
 
+void ContentCaptureDeviceBrowserTestBase::NavigateToAlternateSite() {
+  ASSERT_TRUE(NavigateToURL(shell(), embedded_test_server()->GetURL(
+                                         kAlternateHostname, kAlternatePath)));
+  ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
+}
+
+void ContentCaptureDeviceBrowserTestBase::CrashTheRenderer() {
+  RenderProcessHostWatcher crash_observer(
+      shell()->web_contents(),
+      RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
+  ASSERT_TRUE(NavigateToURLAndExpectNoCommit(shell(), GURL(kChromeUICrashURL)));
+  crash_observer.Wait();
+  ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
+}
+
+void ContentCaptureDeviceBrowserTestBase::ReloadAfterCrash() {
+  ReloadBlockUntilNavigationsComplete(shell(), 1);
+  ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
+}
+
 bool ContentCaptureDeviceBrowserTestBase::IsSoftwareCompositingTest() const {
   return false;
 }
@@ -276,5 +297,9 @@
 constexpr char ContentCaptureDeviceBrowserTestBase::kSingleFrameHostname[];
 // static
 constexpr char ContentCaptureDeviceBrowserTestBase::kSingleFramePath[];
+// static
+constexpr char ContentCaptureDeviceBrowserTestBase::kAlternateHostname[];
+// static
+constexpr char ContentCaptureDeviceBrowserTestBase::kAlternatePath[];
 
 }  // namespace content
diff --git a/content/browser/media/capture/content_capture_device_browsertest_base.h b/content/browser/media/capture/content_capture_device_browsertest_base.h
index a6f4135f..a1d7253 100644
--- a/content/browser/media/capture/content_capture_device_browsertest_base.h
+++ b/content/browser/media/capture/content_capture_device_browsertest_base.h
@@ -77,6 +77,17 @@
     return capture_stack_.has_captured_frames();
   }
 
+  // Navigates to the test document using a different domain (host). This will
+  // force a new render process to be spun-up, and that is used to test
+  // re-targetting logic.
+  void NavigateToAlternateSite();
+
+  // Crashes the renderer by asking it to navigate to chrome://crash.
+  void CrashTheRenderer();
+
+  // Executes a page reload, assuming this is for a previously-crashed renderer.
+  void ReloadAfterCrash();
+
  protected:
   // These all return false, but can be overridden for parameterized tests to
   // change the behavior of this base class.
@@ -120,6 +131,8 @@
   static constexpr char kOuterFramePath[] = "/outer.html";
   static constexpr char kSingleFrameHostname[] = "singleframe.com";
   static constexpr char kSingleFramePath[] = "/single.html";
+  static constexpr char kAlternateHostname[] = "alternate.com";
+  static constexpr char kAlternatePath[] = "/alternate.html";
 
   DISALLOW_COPY_AND_ASSIGN(ContentCaptureDeviceBrowserTestBase);
 };
diff --git a/content/browser/media/capture/web_contents_video_capture_device.cc b/content/browser/media/capture/web_contents_video_capture_device.cc
index 9eab080..e0ebc1d 100644
--- a/content/browser/media/capture/web_contents_video_capture_device.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device.cc
@@ -116,7 +116,7 @@
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
     WebContents* const contents = web_contents();
-    if (!contents || contents->IsCrashed()) {
+    if (!contents) {
       return nullptr;
     }
 
diff --git a/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc b/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
index e1b4a7d5..79d102e 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_browsertest.cc
@@ -15,6 +15,7 @@
 #include "content/browser/media/capture/content_capture_device_browsertest_base.h"
 #include "content/browser/media/capture/fake_video_capture_stack.h"
 #include "content/browser/media/capture/frame_test_util.h"
+#include "content/browser/renderer_host/render_widget_host_view_base.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
@@ -150,6 +151,14 @@
     }
   }
 
+  // Used by certain tests to determine whether the capturer has been
+  // re-targetted.
+  viz::FrameSinkId GetCurrentFrameSinkId() {
+    auto* const view = static_cast<RenderWidgetHostViewBase*>(
+        shell()->web_contents()->GetRenderWidgetHostView());
+    return view ? view->GetFrameSinkId() : viz::FrameSinkId();
+  }
+
  protected:
   // Don't call this. Call <BaseClass>::GetExpectedSourceSize() instead.
   gfx::Size GetCapturedSourceSize() const final {
@@ -231,6 +240,64 @@
   StopAndDeAllocate();
 }
 
+// Tests that capture is re-targetted when the render view of a WebContents
+// changes.
+IN_PROC_BROWSER_TEST_F(WebContentsVideoCaptureDeviceBrowserTest,
+                       ChangesTargettedRenderView) {
+  NavigateToInitialDocument();
+  AllocateAndStartAndWaitForFirstFrame();
+  EXPECT_TRUE(shell()->web_contents()->IsBeingCaptured());
+
+  // Make a content change in the first page and wait for capture to reflect
+  // that.
+  ChangePageContentColor(SK_ColorRED);
+  WaitForFrameWithColor(SK_ColorRED);
+
+  // Navigate to an alternate site, checking that the FrameSinkIds before/after
+  // the navigation are different.
+  const viz::FrameSinkId frame_sink_id_before = GetCurrentFrameSinkId();
+  EXPECT_TRUE(frame_sink_id_before.is_valid());
+  NavigateToAlternateSite();
+  const viz::FrameSinkId frame_sink_id_after = GetCurrentFrameSinkId();
+  EXPECT_TRUE(frame_sink_id_after.is_valid());
+  EXPECT_NE(frame_sink_id_before, frame_sink_id_after);
+
+  // Make a content change in the second page and wait for capture to reflect
+  // that. This proves that the capturer was successfully re-targetted to the
+  // second page.
+  ChangePageContentColor(SK_ColorGREEN);
+  WaitForFrameWithColor(SK_ColorGREEN);
+}
+
+// Tests that capture is re-targetted when a renderer crash is followed by a
+// reload. Regression test for http://crbug.com/916332.
+IN_PROC_BROWSER_TEST_F(WebContentsVideoCaptureDeviceBrowserTest,
+                       RecoversAfterRendererCrash) {
+  NavigateToInitialDocument();
+  AllocateAndStartAndWaitForFirstFrame();
+  EXPECT_TRUE(shell()->web_contents()->IsBeingCaptured());
+
+  // Make a content change in the first page and wait for capture to reflect
+  // that.
+  ChangePageContentColor(SK_ColorRED);
+  WaitForFrameWithColor(SK_ColorRED);
+
+  // Crash the renderer.
+  EXPECT_TRUE(GetCurrentFrameSinkId().is_valid());
+  CrashTheRenderer();
+  EXPECT_FALSE(GetCurrentFrameSinkId().is_valid());
+
+  // Now, reload the page.
+  ReloadAfterCrash();
+  EXPECT_TRUE(GetCurrentFrameSinkId().is_valid());
+
+  // Make a content change in the reloaded page and wait for capture to reflect
+  // that. This proves that the capturer successfully re-targetted to the
+  // reloaded page.
+  ChangePageContentColor(SK_ColorGREEN);
+  WaitForFrameWithColor(SK_ColorGREEN);
+}
+
 // Tests that the device stops delivering frames while suspended. When resumed,
 // any content changes that occurred during the suspend should cause a new frame
 // to be delivered, to ensure the client is up-to-date.
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 25235226..511b0d8 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -237,6 +237,7 @@
     NavigateToURL(shell(), url);
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_FALSE(observer.last_initiator_origin().has_value());
   }
 
   RenderFrameHost* initial_rfh =
@@ -252,6 +253,7 @@
     NavigateToURL(shell(), url);
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_FALSE(observer.last_initiator_origin().has_value());
   }
 
   // The RenderFrameHost should not have changed.
@@ -267,6 +269,7 @@
     NavigateToURL(shell(), url);
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_FALSE(observer.last_initiator_origin().has_value());
   }
 
   // The RenderFrameHost should have changed.
@@ -286,6 +289,7 @@
     NavigateToURL(shell(), url);
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_FALSE(observer.last_initiator_origin().has_value());
   }
 
   RenderFrameHost* initial_rfh =
@@ -306,6 +310,8 @@
     EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_EQ(shell()->web_contents()->GetMainFrame()->GetLastCommittedOrigin(),
+              observer.last_initiator_origin());
   }
 
   // The RenderFrameHost should not have changed.
@@ -332,6 +338,7 @@
           ->GetFrameTree()
           ->root()
           ->current_frame_host();
+  url::Origin initial_origin = initial_rfh->GetLastCommittedOrigin();
 
   // Simulate clicking on a cross-site link.
   {
@@ -352,6 +359,7 @@
     EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
     EXPECT_EQ(url, observer.last_navigation_url());
     EXPECT_TRUE(observer.last_navigation_succeeded());
+    EXPECT_EQ(initial_origin, observer.last_initiator_origin().value());
   }
 
   // The RenderFrameHost should not have changed unless site-per-process is
@@ -617,8 +625,8 @@
       features::kAllowContentInitiatedDataUrlNavigations);
   // Setup a BeginNavigate IPC with non-empty base_url_for_data_url.
   CommonNavigationParams common_params(
-      data_url, Referrer(), ui::PAGE_TRANSITION_LINK,
-      FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT,
+      data_url, url::Origin::Create(data_url), Referrer(),
+      ui::PAGE_TRANSITION_LINK, FrameMsg_Navigate_Type::DIFFERENT_DOCUMENT,
       NavigationDownloadPolicy::kAllow,
       false /* should_replace_current_entry */,
       file_url, /* base_url_for_data_url */
@@ -635,7 +643,7 @@
           blink::WebMixedContentContextType::kBlockable,
           false /* is_form_submission */, GURL() /* searchable_form_url */,
           std::string() /* searchable_form_encoding */,
-          url::Origin::Create(data_url), GURL() /* client_side_redirect_url */,
+          GURL() /* client_side_redirect_url */,
           base::nullopt /* devtools_initiator_info */);
 
   // Receiving the invalid IPC message should lead to renderer process
diff --git a/content/browser/sandbox_host_linux.cc b/content/browser/sandbox_host_linux.cc
index 2f89027..db3b884c 100644
--- a/content/browser/sandbox_host_linux.cc
+++ b/content/browser/sandbox_host_linux.cc
@@ -64,6 +64,10 @@
     if (IGNORE_EINTR(close(child_socket_)) < 0)
       PLOG(ERROR) << "close";
 
+    // TODO(gab): We might be able to just delete this destructor:
+    // https://chromium-review.googlesource.com/c/chromium/src/+/1378683
+    base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope
+        allow_thread_join_on_shutdown;
     ipc_thread_->Join();
   }
 }
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index b72385bc..4c68676f 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -110,10 +110,11 @@
   GURL extension_url("https://bar.com/simple_page.html");
   WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell->web_contents());
   wc->GetFrameTree()->root()->navigator()->RequestOpenURL(
-      wc->GetFrameTree()->root()->current_frame_host(), extension_url, false,
-      nullptr, std::string(), Referrer(), WindowOpenDisposition::CURRENT_TAB,
-      false, true, blink::WebTriggeringEventInfo::kFromTrustedEvent,
-      std::string(), nullptr /* blob_url_loader_factory */);
+      wc->GetFrameTree()->root()->current_frame_host(), extension_url,
+      url::Origin::Create(foo), false, nullptr, std::string(), Referrer(),
+      WindowOpenDisposition::CURRENT_TAB, false, true,
+      blink::WebTriggeringEventInfo::kFromTrustedEvent, std::string(),
+      nullptr /* blob_url_loader_factory */);
 
   // Since the navigation above requires a cross-process swap, there will be a
   // speculative/pending RenderFrameHost. Ensure it exists and is in a different
diff --git a/content/browser/service_worker/service_worker_client_utils.cc b/content/browser/service_worker/service_worker_client_utils.cc
index 407d0bd..41b25b8 100644
--- a/content/browser/service_worker/service_worker_client_utils.cc
+++ b/content/browser/service_worker/service_worker_client_utils.cc
@@ -288,8 +288,8 @@
 
   Navigator* navigator = rfhi->frame_tree_node()->navigator();
   navigator->RequestOpenURL(
-      rfhi, url, false /* uses_post */, nullptr /* body */,
-      std::string() /* extra_headers */,
+      rfhi, url, url::Origin::Create(script_url), false /* uses_post */,
+      nullptr /* body */, std::string() /* extra_headers */,
       Referrer::SanitizeForRequest(
           url, Referrer(script_url, network::mojom::ReferrerPolicy::kDefault)),
       WindowOpenDisposition::CURRENT_TAB,
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 41a867ba..c25b2648 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -469,6 +469,7 @@
                         network::mojom::ReferrerPolicy::kAlways),
       WindowOpenDisposition::CURRENT_TAB, ui::PAGE_TRANSITION_LINK,
       true /* is_renderer_initiated */);
+  params.initiator_origin = url::Origin::Create(url);
   shell->OpenURLFromTab(shell->web_contents(), params);
 
   same_tab_observer.Wait();
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 21d71f8..03dd2009 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -2776,6 +2776,7 @@
       std::unique_ptr<NavigationController::LoadURLParams> load_params =
           std::make_unique<NavigationController::LoadURLParams>(
               params.target_url);
+      load_params->initiator_origin = opener->GetLastCommittedOrigin();
       load_params->referrer = params.referrer.To<Referrer>();
       load_params->transition_type = ui::PAGE_TRANSITION_LINK;
       load_params->is_renderer_initiated = true;
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 2000249..4f0ae7b 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -535,6 +535,7 @@
   OpenURLParams params(url, Referrer(), frame_tree_node_id,
                        WindowOpenDisposition::CURRENT_TAB,
                        ui::PAGE_TRANSITION_LINK, true);
+  params.initiator_origin = wc->GetMainFrame()->GetLastCommittedOrigin();
   shell()->web_contents()->OpenURL(params);
 
   // Make sure the NavigationEntry ends up with the FrameTreeNode ID.
diff --git a/content/browser/web_package/signed_exchange_envelope.cc b/content/browser/web_package/signed_exchange_envelope.cc
index 27d4ea1..bfa24ccb 100644
--- a/content/browser/web_package/signed_exchange_envelope.cc
+++ b/content/browser/web_package/signed_exchange_envelope.cc
@@ -282,14 +282,14 @@
 
 // static
 base::Optional<SignedExchangeEnvelope> SignedExchangeEnvelope::Parse(
-    const GURL& fallback_url,
+    const signed_exchange_utils::URLWithRawString& fallback_url,
     base::StringPiece signature_header_field,
     base::span<const uint8_t> cbor_header,
     SignedExchangeDevToolsProxy* devtools_proxy) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
                "SignedExchangeEnvelope::Parse");
 
-  const GURL& request_url = fallback_url;
+  const auto& request_url = fallback_url;
 
   cbor::Reader::DecoderError error;
   base::Optional<cbor::Value> value = cbor::Reader::Read(cbor_header, &error);
@@ -351,8 +351,8 @@
   // If the signature’s “validity-url” parameter is not same-origin with
   // exchange’s effective request URI (Section 5.5 of [RFC7230]), return
   // “invalid” [spec text]
-  const GURL validity_url = ret.signature().validity_url;
-  if (!url::IsSameOriginWith(request_url, validity_url)) {
+  const GURL validity_url = ret.signature().validity_url.url;
+  if (!url::IsSameOriginWith(request_url.url, validity_url)) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy, "Validity URL must be same-origin with request URL.");
     return base::nullopt;
diff --git a/content/browser/web_package/signed_exchange_envelope.h b/content/browser/web_package/signed_exchange_envelope.h
index 1b7026d..011c3d8f 100644
--- a/content/browser/web_package/signed_exchange_envelope.h
+++ b/content/browser/web_package/signed_exchange_envelope.h
@@ -36,7 +36,7 @@
   // This also performs the steps 1, 3 and 4 of "Cross-origin trust" validation.
   // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#cross-origin-trust
   static base::Optional<SignedExchangeEnvelope> Parse(
-      const GURL& fallback_url,
+      const signed_exchange_utils::URLWithRawString& fallback_url,
       base::StringPiece signature_header_field,
       base::span<const uint8_t> cbor_header,
       SignedExchangeDevToolsProxy* devtools_proxy);
@@ -56,8 +56,12 @@
   }
   void set_cbor_header(base::span<const uint8_t> data);
 
-  const GURL& request_url() const { return request_url_; };
-  void set_request_url(GURL url) { request_url_ = std::move(url); }
+  const signed_exchange_utils::URLWithRawString& request_url() const {
+    return request_url_;
+  };
+  void set_request_url(const signed_exchange_utils::URLWithRawString& url) {
+    request_url_ = url;
+  }
 
   const std::string& request_method() const { return request_method_; }
   void set_request_method(base::StringPiece s) {
@@ -80,7 +84,7 @@
  private:
   std::vector<uint8_t> cbor_header_;
 
-  GURL request_url_;
+  signed_exchange_utils::URLWithRawString request_url_;
   std::string request_method_;
 
   net::HttpStatusCode response_code_;
diff --git a/content/browser/web_package/signed_exchange_envelope_unittest.cc b/content/browser/web_package/signed_exchange_envelope_unittest.cc
index 10b39b8..26cf021f 100644
--- a/content/browser/web_package/signed_exchange_envelope_unittest.cc
+++ b/content/browser/web_package/signed_exchange_envelope_unittest.cc
@@ -34,7 +34,7 @@
 }
 
 base::Optional<SignedExchangeEnvelope> GenerateHeaderAndParse(
-    const GURL& fallback_url,
+    base::StringPiece fallback_url,
     base::StringPiece signature,
     const std::map<const char*, const char*>& request_map,
     const std::map<const char*, const char*>& response_map) {
@@ -51,7 +51,7 @@
 
   auto serialized = cbor::Writer::Write(cbor::Value(std::move(array)));
   return SignedExchangeEnvelope::Parse(
-      fallback_url, signature,
+      signed_exchange_utils::URLWithRawString(fallback_url), signature,
       base::make_span(serialized->data(), serialized->size()),
       nullptr /* devtools_proxy */);
 }
@@ -102,7 +102,8 @@
                                     signature_header_field, cbor_bytes,
                                     nullptr /* devtools_proxy */);
   ASSERT_TRUE(envelope.has_value());
-  EXPECT_EQ(envelope->request_url(), GURL("https://test.example.org/test/"));
+  EXPECT_EQ(envelope->request_url().url,
+            GURL("https://test.example.org/test/"));
   EXPECT_EQ(envelope->request_method(), "GET");
   EXPECT_EQ(envelope->response_code(), static_cast<net::HttpStatusCode>(200u));
   EXPECT_EQ(envelope->response_headers().size(), 3u);
@@ -112,44 +113,44 @@
 
 TEST(SignedExchangeEnvelopeTest, ValidHeader) {
   auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
+      "https://test.example.org/test/", kSignatureString,
       {
           {kMethodKey, "GET"},
       },
       {{kStatusKey, "200"}, {"content-type", "text/html"}});
   ASSERT_TRUE(header.has_value());
-  EXPECT_EQ(header->request_url(), GURL("https://test.example.org/test/"));
+  EXPECT_EQ(header->request_url().url, GURL("https://test.example.org/test/"));
   EXPECT_EQ(header->request_method(), "GET");
   EXPECT_EQ(header->response_code(), static_cast<net::HttpStatusCode>(200u));
   EXPECT_EQ(header->response_headers().size(), 1u);
 }
 
 TEST(SignedExchangeEnvelopeTest, UnsafeMethod) {
-  auto header = GenerateHeaderAndParse(GURL("https://test.example.org/test/"),
-                                       kSignatureString,
-                                       {
-                                           {kMethodKey, "POST"},
-                                       },
-                                       {
-                                           {kStatusKey, "200"},
-                                       });
+  auto header =
+      GenerateHeaderAndParse("https://test.example.org/test/", kSignatureString,
+                             {
+                                 {kMethodKey, "POST"},
+                             },
+                             {
+                                 {kStatusKey, "200"},
+                             });
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, InformationalResponseCode) {
-  auto header = GenerateHeaderAndParse(GURL("https://test.example.org/test/"),
-                                       kSignatureString,
-                                       {
-                                           {kMethodKey, "GET"},
-                                       },
-                                       {
-                                           {kStatusKey, "100"},
-                                       });
+  auto header =
+      GenerateHeaderAndParse("https://test.example.org/test/", kSignatureString,
+                             {
+                                 {kMethodKey, "GET"},
+                             },
+                             {
+                                 {kStatusKey, "100"},
+                             });
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, RelativeURL) {
-  auto header = GenerateHeaderAndParse(GURL("test/"), kSignatureString,
+  auto header = GenerateHeaderAndParse("test/", kSignatureString,
                                        {
                                            {kMethodKey, "GET"},
                                        },
@@ -160,59 +161,60 @@
 }
 
 TEST(SignedExchangeEnvelopeTest, HttpURLShouldFail) {
-  auto header = GenerateHeaderAndParse(GURL("http://test.example.org/test/"),
-                                       kSignatureString,
-                                       {
-                                           {kMethodKey, "GET"},
-                                       },
-                                       {
-                                           {kStatusKey, "200"},
-                                       });
+  auto header =
+      GenerateHeaderAndParse("http://test.example.org/test/", kSignatureString,
+                             {
+                                 {kMethodKey, "GET"},
+                             },
+                             {
+                                 {kStatusKey, "200"},
+                             });
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, RedirectStatusShouldFail) {
-  auto header = GenerateHeaderAndParse(GURL("https://test.example.org/test/"),
-                                       kSignatureString, {{kMethodKey, "GET"}},
-                                       {{kStatusKey, "302"}});
+  auto header =
+      GenerateHeaderAndParse("https://test.example.org/test/", kSignatureString,
+                             {{kMethodKey, "GET"}}, {{kStatusKey, "302"}});
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, Status300ShouldFail) {
   auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
-      {{kMethodKey, "GET"}},
+      "https://test.example.org/test/", kSignatureString, {{kMethodKey, "GET"}},
       {{kStatusKey, "300"}});  // 300 is not a redirect status.
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, StatefulRequestHeader) {
-  auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
-      {
-          {kMethodKey, "GET"}, {"authorization", "Basic Zm9vOmJhcg=="},
-      },
-      {
-          {kStatusKey, "200"},
-      });
+  auto header =
+      GenerateHeaderAndParse("https://test.example.org/test/", kSignatureString,
+                             {
+                                 {kMethodKey, "GET"},
+                                 {"authorization", "Basic Zm9vOmJhcg=="},
+                             },
+                             {
+                                 {kStatusKey, "200"},
+                             });
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, StatefulResponseHeader) {
-  auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
-      {
-          {kMethodKey, "GET"},
-      },
-      {
-          {kStatusKey, "200"}, {"set-cookie", "foo=bar"},
-      });
+  auto header =
+      GenerateHeaderAndParse("https://test.example.org/test/", kSignatureString,
+                             {
+                                 {kMethodKey, "GET"},
+                             },
+                             {
+                                 {kStatusKey, "200"},
+                                 {"set-cookie", "foo=bar"},
+                             });
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, UppercaseRequestMap) {
   auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
+      "https://test.example.org/test/", kSignatureString,
       {{kMethodKey, "GET"}, {"Accept-Language", "en-us"}},
       {
           {kStatusKey, "200"},
@@ -221,18 +223,18 @@
 }
 
 TEST(SignedExchangeEnvelopeTest, UppercaseResponseMap) {
-  auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
-      {
-          {kMethodKey, "GET"},
-      },
-      {{kStatusKey, "200"}, {"Content-Length", "123"}});
+  auto header =
+      GenerateHeaderAndParse("https://test.example.org/test/", kSignatureString,
+                             {
+                                 {kMethodKey, "GET"},
+                             },
+                             {{kStatusKey, "200"}, {"Content-Length", "123"}});
   ASSERT_FALSE(header.has_value());
 }
 
 TEST(SignedExchangeEnvelopeTest, InvalidValidityURLHeader) {
   auto header = GenerateHeaderAndParse(
-      GURL("https://test2.example.org/test/"), kSignatureString,
+      "https://test2.example.org/test/", kSignatureString,
       {
           {kMethodKey, "GET"},
       },
@@ -242,7 +244,7 @@
 
 TEST(SignedExchangeEnvelopeTest, InnerResponseIsSXG) {
   auto header = GenerateHeaderAndParse(
-      GURL("https://test.example.org/test/"), kSignatureString,
+      "https://test.example.org/test/", kSignatureString,
       {
           {kMethodKey, "GET"},
       },
diff --git a/content/browser/web_package/signed_exchange_error.h b/content/browser/web_package/signed_exchange_error.h
index 36343ce..408f476 100644
--- a/content/browser/web_package/signed_exchange_error.h
+++ b/content/browser/web_package/signed_exchange_error.h
@@ -41,7 +41,9 @@
   // Certificate Requirements aren't met.
   // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#cross-origin-cert-req
   kCertRequirementsNotMet,
-  kMaxValue = kCertRequirementsNotMet
+  // SXG was served without "X-Content-Type-Options: nosniff" header.
+  kSXGServedWithoutNosniff,
+  kMaxValue = kSXGServedWithoutNosniff
 };
 
 struct SignedExchangeError {
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 824152e7..e85c56d 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -60,6 +60,11 @@
     "SignedExchange.OCSPResponseStatus";
 constexpr char kHistogramOCSPRevocationStatus[] =
     "SignedExchange.OCSPRevocationStatus";
+constexpr char kSXGFromNonHTTPSErrorMessage[] =
+    "Signed exchange response from non secure origin is not supported.";
+constexpr char kSXGWithoutNoSniffErrorMessage[] =
+    "Signed exchange response without \"X-Content-Type-Options: nosniff\" "
+    "header is not supported.";
 
 network::mojom::NetworkContext* g_network_context_for_testing = nullptr;
 
@@ -170,6 +175,7 @@
 
 SignedExchangeHandler::SignedExchangeHandler(
     bool is_secure_transport,
+    bool has_nosniff,
     std::string content_type,
     std::unique_ptr<net::SourceStream> body,
     ExchangeHeadersCallback headers_callback,
@@ -178,6 +184,7 @@
     std::unique_ptr<SignedExchangeDevToolsProxy> devtools_proxy,
     base::RepeatingCallback<int(void)> frame_tree_node_id_getter)
     : is_secure_transport_(is_secure_transport),
+      has_nosniff_(has_nosniff),
       headers_callback_(std::move(headers_callback)),
       source_(std::move(body)),
       cert_fetcher_factory_(std::move(cert_fetcher_factory)),
@@ -197,8 +204,17 @@
   // without TLS. [spec text]
   if (!is_secure_transport_) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
-        devtools_proxy_.get(),
-        "Signed exchange response from non secure origin is not supported.");
+        devtools_proxy_.get(), kSXGFromNonHTTPSErrorMessage);
+    // Proceed to extract and redirect to the fallback URL.
+  }
+
+  // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#seccons-content-sniffing
+  // To encourage servers to include the `X-Content-Type-Options: nosniff`
+  // header field, clients SHOULD reject signed exchanges served without it.
+  // [spec text]
+  if (!has_nosniff_) {
+    signed_exchange_utils::ReportErrorAndTraceEvent(
+        devtools_proxy_.get(), kSXGWithoutNoSniffErrorMessage);
     // Proceed to extract and redirect to the fallback URL.
   }
 
@@ -226,11 +242,12 @@
 
 SignedExchangeHandler::SignedExchangeHandler()
     : is_secure_transport_(true),
+      has_nosniff_(true),
       load_flags_(net::LOAD_NORMAL),
       weak_factory_(this) {}
 
 const GURL& SignedExchangeHandler::GetFallbackUrl() const {
-  return prologue_fallback_url_and_after_.fallback_url();
+  return prologue_fallback_url_and_after_.fallback_url().url;
 }
 
 void SignedExchangeHandler::SetupBuffers(size_t size) {
@@ -359,6 +376,9 @@
   if (!is_secure_transport_)
     return SignedExchangeLoadResult::kSXGServedFromNonHTTPS;
 
+  if (!has_nosniff_)
+    return SignedExchangeLoadResult::kSXGServedWithoutNosniff;
+
   // If the signed exchange version from content-type is unsupported or the
   // prologue's magic string is incorrect, abort parsing and redirect to the
   // fallback URL.
@@ -390,9 +410,9 @@
       base::as_bytes(base::make_span(data.substr(
           prologue_fallback_url_and_after_.signature_header_field_length(),
           prologue_fallback_url_and_after_.cbor_header_length())));
-  envelope_ =
-      SignedExchangeEnvelope::Parse(GetFallbackUrl(), signature_header_field,
-                                    cbor_header, devtools_proxy_.get());
+  envelope_ = SignedExchangeEnvelope::Parse(
+      prologue_fallback_url_and_after_.fallback_url(), signature_header_field,
+      cbor_header, devtools_proxy_.get());
   header_read_buf_ = nullptr;
   header_buf_ = nullptr;
   if (!envelope_) {
@@ -483,7 +503,7 @@
   }
 
   auto certificate = unverified_cert_chain_->cert();
-  auto url = envelope_->request_url();
+  auto url = envelope_->request_url().url;
 
   // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#cross-origin-trust
   // Step 6.4 Validate that valid SCTs from trusted logs are available from any
@@ -652,8 +672,8 @@
   response_head.ssl_info = std::move(ssl_info);
   std::move(headers_callback_)
       .Run(SignedExchangeLoadResult::kSuccess, net::OK,
-           envelope_->request_url(), envelope_->request_method(), response_head,
-           std::move(mi_stream));
+           envelope_->request_url().url, envelope_->request_method(),
+           response_head, std::move(mi_stream));
   state_ = State::kHeadersCallbackCalled;
 }
 
diff --git a/content/browser/web_package/signed_exchange_handler.h b/content/browser/web_package/signed_exchange_handler.h
index dfff4f2..50608961 100644
--- a/content/browser/web_package/signed_exchange_handler.h
+++ b/content/browser/web_package/signed_exchange_handler.h
@@ -87,6 +87,7 @@
   // is used to create a SignedExchangeCertFetcher that fetches the certificate.
   SignedExchangeHandler(
       bool is_secure_transport,
+      bool has_nosniff,
       std::string content_type,
       std::unique_ptr<net::SourceStream> body,
       ExchangeHeadersCallback headers_callback,
@@ -129,6 +130,7 @@
                     const net::ct::CTVerifyResult& ct_result);
 
   const bool is_secure_transport_;
+  const bool has_nosniff_;
   ExchangeHeadersCallback headers_callback_;
   base::Optional<SignedExchangeVersion> version_;
   std::unique_ptr<net::SourceStream> source_;
diff --git a/content/browser/web_package/signed_exchange_handler_unittest.cc b/content/browser/web_package/signed_exchange_handler_unittest.cc
index 1047a7f..82c0148 100644
--- a/content/browser/web_package/signed_exchange_handler_unittest.cc
+++ b/content/browser/web_package/signed_exchange_handler_unittest.cc
@@ -266,7 +266,7 @@
     SignedExchangeHandler::SetNetworkContextForTesting(network_context_.get());
 
     handler_ = std::make_unique<SignedExchangeHandler>(
-        true /* is_secure_transport */, ContentType(),
+        true /* is_secure_transport */, true /* has_nosniff */, ContentType(),
         std::move(source_stream_),
         base::BindOnce(&SignedExchangeHandlerTest::OnHeaderFound,
                        base::Unretained(this)),
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index f168638..82256ea 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -35,6 +35,8 @@
 constexpr char kLoadResultHistogram[] = "SignedExchange.LoadResult";
 constexpr char kPrefetchLoadResultHistogram[] =
     "SignedExchange.Prefetch.LoadResult";
+constexpr char kContentTypeOptionsHeaderName[] = "x-content-type-options";
+constexpr char kNoSniffHeaderValue[] = "nosniff";
 
 net::RedirectInfo CreateRedirectInfo(const GURL& new_url,
                                      const GURL& outer_request_url) {
@@ -56,6 +58,13 @@
   return redirect_info;
 }
 
+bool HasNoSniffHeader(const network::ResourceResponseHead& response) {
+  std::string content_type_options;
+  response.headers->EnumerateHeader(nullptr, kContentTypeOptionsHeaderName,
+                                    &content_type_options);
+  return base::LowerCaseEqualsASCII(content_type_options, kNoSniffHeaderValue);
+}
+
 constexpr static int kDefaultBufferSize = 64 * 1024;
 
 SignedExchangeHandlerFactory* g_signed_exchange_factory_for_testing_ = nullptr;
@@ -213,8 +222,8 @@
   }
 
   signed_exchange_handler_ = std::make_unique<SignedExchangeHandler>(
-      IsOriginSecure(outer_request_url_), content_type_,
-      std::make_unique<DataPipeToSourceStream>(std::move(body)),
+      IsOriginSecure(outer_request_url_), HasNoSniffHeader(outer_response_),
+      content_type_, std::make_unique<DataPipeToSourceStream>(std::move(body)),
       base::BindOnce(&SignedExchangeLoader::OnHTTPExchangeFound,
                      weak_factory_.GetWeakPtr()),
       std::move(cert_fetcher_factory), load_flags_, std::move(devtools_proxy_),
diff --git a/content/browser/web_package/signed_exchange_prologue.cc b/content/browser/web_package/signed_exchange_prologue.cc
index c298b0b..db5f29c 100644
--- a/content/browser/web_package/signed_exchange_prologue.cc
+++ b/content/browser/web_package/signed_exchange_prologue.cc
@@ -5,6 +5,7 @@
 #include "content/browser/web_package/signed_exchange_prologue.h"
 
 #include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "content/browser/web_package/signed_exchange_utils.h"
@@ -76,8 +77,8 @@
 
 // static
 FallbackUrlAndAfter FallbackUrlAndAfter::ParseFailedButFallbackUrlAvailable(
-    GURL fallback_url) {
-  return FallbackUrlAndAfter(/*is_valid=*/false, std::move(fallback_url),
+    const signed_exchange_utils::URLWithRawString& fallback_url) {
+  return FallbackUrlAndAfter(/*is_valid=*/false, fallback_url,
                              /*signature_header_field_length=*/0,
                              /*cbor_header_length=*/0);
 }
@@ -100,21 +101,26 @@
   base::StringPiece fallback_url_str(
       reinterpret_cast<const char*>(input.data()),
       before_fallback_url.fallback_url_length());
-  GURL fallback_url(fallback_url_str);
+  if (!base::IsStringUTF8(fallback_url_str)) {
+    signed_exchange_utils::ReportErrorAndTraceEvent(
+        devtools_proxy, "`fallbackUrl` is not a valid UTF-8 sequence.");
+    return FallbackUrlAndAfter();
+  }
 
-  if (!fallback_url.is_valid()) {
+  signed_exchange_utils::URLWithRawString fallback_url(fallback_url_str);
+  if (!fallback_url.url.is_valid()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy, "Failed to parse `fallbackUrl`.");
     return FallbackUrlAndAfter();
   }
-  if (!fallback_url.SchemeIs(url::kHttpsScheme)) {
+  if (!fallback_url.url.SchemeIs(url::kHttpsScheme)) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy, "`fallbackUrl` in non-https scheme.");
     return FallbackUrlAndAfter();
   }
-  if (fallback_url.has_ref()) {
+  if (fallback_url.url.has_ref()) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
-        devtools_proxy, ":url can't have a fragment.");
+        devtools_proxy, "`fallbackUrl` can't have a fragment.");
     return FallbackUrlAndAfter();
   }
 
diff --git a/content/browser/web_package/signed_exchange_prologue.h b/content/browser/web_package/signed_exchange_prologue.h
index 1414e71..80bf829c 100644
--- a/content/browser/web_package/signed_exchange_prologue.h
+++ b/content/browser/web_package/signed_exchange_prologue.h
@@ -10,6 +10,7 @@
 #include "base/containers/span.h"
 #include "base/gtest_prod_util.h"
 #include "base/optional.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 
@@ -93,7 +94,9 @@
 
   // Note: fallback_url() may still be called even if |!is_valid()|,
   //       for trigering fallback redirect.
-  const GURL& fallback_url() const { return fallback_url_; }
+  const signed_exchange_utils::URLWithRawString& fallback_url() const {
+    return fallback_url_;
+  }
 
   size_t signature_header_field_length() const;
   size_t cbor_header_length() const;
@@ -102,14 +105,15 @@
 
  private:
   static FallbackUrlAndAfter ParseFailedButFallbackUrlAvailable(
-      GURL fallback_url);
+      const signed_exchange_utils::URLWithRawString& fallback_url);
 
-  FallbackUrlAndAfter(bool is_valid,
-                      GURL fallback_url,
-                      size_t signature_header_field_length,
-                      size_t cbor_header_length)
+  FallbackUrlAndAfter(
+      bool is_valid,
+      const signed_exchange_utils::URLWithRawString& fallback_url,
+      size_t signature_header_field_length,
+      size_t cbor_header_length)
       : is_valid_(is_valid),
-        fallback_url_(std::move(fallback_url)),
+        fallback_url_(fallback_url),
         signature_header_field_length_(signature_header_field_length),
         cbor_header_length_(cbor_header_length) {}
 
@@ -119,7 +123,7 @@
   // The URL to redirect navigation to when the signed exchange processing steps
   // has failed.
   // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#application-signed-exchange
-  GURL fallback_url_;
+  signed_exchange_utils::URLWithRawString fallback_url_;
 
   // Corresponds to `sigLength` in the spec text.
   // Encoded length of the Signature header field's value.
diff --git a/content/browser/web_package/signed_exchange_prologue_unittest.cc b/content/browser/web_package/signed_exchange_prologue_unittest.cc
index 03febae..c355ab8 100644
--- a/content/browser/web_package/signed_exchange_prologue_unittest.cc
+++ b/content/browser/web_package/signed_exchange_prologue_unittest.cc
@@ -72,7 +72,7 @@
 
   EXPECT_TRUE(fallback_url_and_after.is_valid());
   EXPECT_EQ("https://example.com/",
-            fallback_url_and_after.fallback_url().spec());
+            fallback_url_and_after.fallback_url().url.spec());
   EXPECT_EQ(0x1234u, fallback_url_and_after.signature_header_field_length());
   EXPECT_EQ(0x2345u, fallback_url_and_after.cbor_header_length());
 }
@@ -89,7 +89,7 @@
                                  nullptr /* devtools_proxy */);
 
   EXPECT_FALSE(fallback_url_and_after.is_valid());
-  EXPECT_FALSE(fallback_url_and_after.fallback_url().is_valid());
+  EXPECT_FALSE(fallback_url_and_after.fallback_url().url.is_valid());
 }
 
 TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_UrlWithFragment) {
@@ -104,7 +104,7 @@
                                  nullptr /* devtools_proxy */);
 
   EXPECT_FALSE(fallback_url_and_after.is_valid());
-  EXPECT_FALSE(fallback_url_and_after.fallback_url().is_valid());
+  EXPECT_FALSE(fallback_url_and_after.fallback_url().url.is_valid());
 }
 
 TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_LongSignatureHeader) {
@@ -120,7 +120,7 @@
 
   EXPECT_FALSE(fallback_url_and_after.is_valid());
   EXPECT_EQ("https://example.com/",
-            fallback_url_and_after.fallback_url().spec());
+            fallback_url_and_after.fallback_url().url.spec());
 }
 
 TEST(SignedExchangePrologueTest, FallbackUrlAndAfter_LongCBORHeader) {
@@ -136,7 +136,7 @@
 
   EXPECT_FALSE(fallback_url_and_after.is_valid());
   EXPECT_EQ("https://example.com/",
-            fallback_url_and_after.fallback_url().spec());
+            fallback_url_and_after.fallback_url().url.spec());
 }
 
 }  // namespace signed_exchange_prologue
diff --git a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
index f3e4a6b..a4f690b 100644
--- a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -284,6 +284,31 @@
 }
 
 IN_PROC_BROWSER_TEST_P(SignedExchangeRequestHandlerBrowserTest,
+                       MissingNosniff) {
+  InstallUrlInterceptor(GURL("https://test.example.org/test/"),
+                        "content/test/data/sxg/fallback.html");
+  InstallMockCert();
+
+  embedded_test_server()->ServeFilesFromSourceDirectory("content/test/data");
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL url = embedded_test_server()->GetURL(
+      "/sxg/test.example.org_test_missing_nosniff.sxg");
+  if (PrefetchIsEnabled())
+    TriggerPrefetch(url, false);
+
+  base::string16 title = base::ASCIIToUTF16("Fallback URL response");
+  TitleWatcher title_watcher(shell()->web_contents(), title);
+  RedirectObserver redirect_observer(shell()->web_contents());
+  NavigateToURL(shell(), url);
+  EXPECT_EQ(title, title_watcher.WaitAndGetTitle());
+  EXPECT_EQ(303, redirect_observer.response_code());
+  histogram_tester_.ExpectUniqueSample(
+      "SignedExchange.LoadResult",
+      SignedExchangeLoadResult::kSXGServedWithoutNosniff,
+      PrefetchIsEnabled() ? 2 : 1);
+}
+
+IN_PROC_BROWSER_TEST_P(SignedExchangeRequestHandlerBrowserTest,
                        InvalidContentType) {
   InstallUrlInterceptor(
       GURL("https://cert.example.org/cert.msg"),
diff --git a/content/browser/web_package/signed_exchange_signature_header_field.cc b/content/browser/web_package/signed_exchange_signature_header_field.cc
index 907e09e..07370ff 100644
--- a/content/browser/web_package/signed_exchange_signature_header_field.cc
+++ b/content/browser/web_package/signed_exchange_signature_header_field.cc
@@ -250,18 +250,19 @@
     sig.cert_sha256 = std::move(cert_sha256);
     // TODO(https://crbug.com/819467): Support ed25519key.
     // sig.ed25519_key = value.params["ed25519Key"];
-    sig.validity_url = GURL(value.params[kValidityUrlKey]);
-    if (!sig.validity_url.is_valid()) {
+    sig.validity_url =
+        signed_exchange_utils::URLWithRawString(value.params[kValidityUrlKey]);
+    if (!sig.validity_url.url.is_valid()) {
       signed_exchange_utils::ReportErrorAndTraceEvent(
           devtools_proxy, "'validity-url' parameter is not a valid URL.");
       return base::nullopt;
     }
-    if (sig.validity_url.has_ref()) {
+    if (sig.validity_url.url.has_ref()) {
       signed_exchange_utils::ReportErrorAndTraceEvent(
           devtools_proxy, "'validity-url' parameter can't have a fragment.");
       return base::nullopt;
     }
-    if (!sig.validity_url.SchemeIs("https")) {
+    if (!sig.validity_url.url.SchemeIs("https")) {
       signed_exchange_utils::ReportErrorAndTraceEvent(
           devtools_proxy, "'validity-url' should have 'https' scheme.");
       return base::nullopt;
diff --git a/content/browser/web_package/signed_exchange_signature_header_field.h b/content/browser/web_package/signed_exchange_signature_header_field.h
index c2603c4..45791b60 100644
--- a/content/browser/web_package/signed_exchange_signature_header_field.h
+++ b/content/browser/web_package/signed_exchange_signature_header_field.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/optional.h"
 #include "base/strings/string_piece.h"
+#include "content/browser/web_package/signed_exchange_utils.h"
 #include "content/common/content_export.h"
 #include "net/base/hash_value.h"
 #include "url/gurl.h"
@@ -38,7 +39,7 @@
     base::Optional<net::SHA256HashValue> cert_sha256;
     // TODO(https://crbug.com/819467): Support ed25519key.
     // std::string ed25519_key;
-    GURL validity_url;
+    signed_exchange_utils::URLWithRawString validity_url;
     uint64_t date;
     uint64_t expires;
   };
diff --git a/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc b/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc
index b6cacc1..786abff 100644
--- a/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc
+++ b/content/browser/web_package/signed_exchange_signature_header_field_unittest.cc
@@ -66,7 +66,7 @@
             std::string(reinterpret_cast<const char*>(decoded_sig1),
                         sizeof(decoded_sig1)));
   EXPECT_EQ(signatures->at(0).integrity, "mi-draft2");
-  EXPECT_EQ(signatures->at(0).validity_url,
+  EXPECT_EQ(signatures->at(0).validity_url.url,
             "https://example.com/resource.validity.1511128380");
   EXPECT_EQ(signatures->at(0).cert_url, "https://example.com/oldcerts");
   EXPECT_EQ(signatures->at(0).cert_sha256, decoded_cert_sha256_1);
@@ -78,7 +78,7 @@
             std::string(reinterpret_cast<const char*>(decoded_sig2),
                         sizeof(decoded_sig2)));
   EXPECT_EQ(signatures->at(1).integrity, "mi-draft2");
-  EXPECT_EQ(signatures->at(1).validity_url,
+  EXPECT_EQ(signatures->at(1).validity_url.url,
             "https://example.com/resource.validity.1511128380");
   EXPECT_EQ(signatures->at(1).cert_url, "https://example.com/newcerts");
   EXPECT_EQ(signatures->at(1).cert_sha256, decoded_cert_sha256_2);
diff --git a/content/browser/web_package/signed_exchange_signature_verifier.cc b/content/browser/web_package/signed_exchange_signature_verifier.cc
index 7ef75c7..d1ab700 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier.cc
+++ b/content/browser/web_package/signed_exchange_signature_verifier.cc
@@ -161,10 +161,10 @@
 
   // Step 5.5. "The 8-byte big-endian encoding of the length in bytes of
   // validity-url, followed by the bytes of validity-url." [spec text]
-  const auto& validity_url_spec = signature.validity_url.spec();
-  AppendToBuf8BytesBigEndian(&message, validity_url_spec.size());
-  message.insert(message.end(), std::begin(validity_url_spec),
-                 std::end(validity_url_spec));
+  const auto& validity_url_bytes = signature.validity_url.raw_string;
+  AppendToBuf8BytesBigEndian(&message, validity_url_bytes.size());
+  message.insert(message.end(), std::begin(validity_url_bytes),
+                 std::end(validity_url_bytes));
 
   // Step 5.6. "The 8-byte big-endian encoding of date." [spec text]
   AppendToBuf8BytesBigEndian(&message, signature.date);
@@ -174,11 +174,11 @@
 
   // Step 5.8. "The 8-byte big-endian encoding of the length in bytes of
   // requestUrl, followed by the bytes of requestUrl." [spec text]
-  const auto& request_url_spec = envelope.request_url().spec();
+  const auto& request_url_bytes = envelope.request_url().raw_string;
 
-  AppendToBuf8BytesBigEndian(&message, request_url_spec.size());
-  message.insert(message.end(), std::begin(request_url_spec),
-                 std::end(request_url_spec));
+  AppendToBuf8BytesBigEndian(&message, request_url_bytes.size());
+  message.insert(message.end(), std::begin(request_url_bytes),
+                 std::end(request_url_bytes));
 
   // Step 5.9. "The 8-byte big-endian encoding of the length in bytes of
   // headers, followed by the bytes of headers." [spec text]
diff --git a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
index d99caa35..7f43981 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
+++ b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
@@ -190,7 +190,8 @@
                   ));
 
     SignedExchangeEnvelope corrupted_envelope(envelope);
-    corrupted_envelope.set_request_url(GURL("https://example.com/bad.html"));
+    corrupted_envelope.set_request_url(signed_exchange_utils::URLWithRawString(
+        "https://example.com/bad.html"));
     EXPECT_EQ(SignedExchangeSignatureVerifier::Result::
                   kErrSignatureVerificationFailed,
               SignedExchangeSignatureVerifier::Verify(
@@ -237,7 +238,8 @@
 
   SignedExchangeEnvelope envelope;
   envelope.set_request_method("GET");
-  envelope.set_request_url(GURL("https://test.example.org/test/"));
+  envelope.set_request_url(signed_exchange_utils::URLWithRawString(
+      "https://test.example.org/test/"));
   envelope.set_response_code(net::HTTP_OK);
   envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
   envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
@@ -264,7 +266,8 @@
 
   SignedExchangeEnvelope envelope;
   envelope.set_request_method("GET");
-  envelope.set_request_url(GURL("https://test.example.org/test/"));
+  envelope.set_request_url(signed_exchange_utils::URLWithRawString(
+      "https://test.example.org/test/"));
   envelope.set_response_code(net::HTTP_OK);
   envelope.AddResponseHeader("content-type", "text/html; charset=utf-8");
   envelope.AddResponseHeader("content-encoding", "mi-sha256-03");
diff --git a/content/browser/web_package/signed_exchange_utils.h b/content/browser/web_package/signed_exchange_utils.h
index bbcad0a..c2f8cddc 100644
--- a/content/browser/web_package/signed_exchange_utils.h
+++ b/content/browser/web_package/signed_exchange_utils.h
@@ -12,8 +12,7 @@
 #include "content/browser/web_package/signed_exchange_consts.h"
 #include "content/browser/web_package/signed_exchange_error.h"
 #include "content/common/content_export.h"
-
-class GURL;
+#include "url/gurl.h"
 
 namespace url {
 class Origin;
@@ -29,6 +28,15 @@
 
 namespace signed_exchange_utils {
 
+// URLWithRawString holds a parsed URL along with its raw bytes.
+struct URLWithRawString {
+  GURL url;
+  std::string raw_string;
+  URLWithRawString() = default;
+  URLWithRawString(base::StringPiece url_string)
+      : url(url_string), raw_string(url_string.as_string()) {}
+};
+
 // Utility method to call SignedExchangeDevToolsProxy::ReportError() and
 // TRACE_EVENT_INSTANT1 to report the error to both DevTools and about:tracing.
 // If |devtools_proxy| is nullptr, it just calls TRACE_EVENT_INSTANT1().
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 9ef5ba2..80885f9c 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -476,6 +476,7 @@
 
 IPC_STRUCT_TRAITS_BEGIN(content::CommonNavigationParams)
   IPC_STRUCT_TRAITS_MEMBER(url)
+  IPC_STRUCT_TRAITS_MEMBER(initiator_origin)
   IPC_STRUCT_TRAITS_MEMBER(referrer)
   IPC_STRUCT_TRAITS_MEMBER(transition)
   IPC_STRUCT_TRAITS_MEMBER(navigation_type)
@@ -562,6 +563,7 @@
 // process should look for an existing history item for the frame.
 IPC_STRUCT_BEGIN(FrameHostMsg_OpenURL_Params)
   IPC_STRUCT_MEMBER(GURL, url)
+  IPC_STRUCT_MEMBER(url::Origin, initiator_origin)
   IPC_STRUCT_MEMBER(bool, uses_post)
   IPC_STRUCT_MEMBER(scoped_refptr<network::ResourceRequestBody>,
                     resource_request_body)
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index bd88e48e..f27cfbd1 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -54,6 +54,7 @@
 
 CommonNavigationParams::CommonNavigationParams(
     const GURL& url,
+    const base::Optional<url::Origin>& initiator_origin,
     const Referrer& referrer,
     ui::PageTransition transition,
     FrameMsg_Navigate_Type::Value navigation_type,
@@ -72,6 +73,7 @@
     const std::string& href_translate,
     base::TimeTicks input_start)
     : url(url),
+      initiator_origin(initiator_origin),
       referrer(referrer),
       transition(transition),
       navigation_type(navigation_type),
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index 328867f..42885d5 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -125,6 +125,7 @@
   CommonNavigationParams();
   CommonNavigationParams(
       const GURL& url,
+      const base::Optional<url::Origin>& initiator_origin,
       const Referrer& referrer,
       ui::PageTransition transition,
       FrameMsg_Navigate_Type::Value navigation_type,
@@ -149,6 +150,11 @@
   // PlzNavigate: May be modified when the navigation is ready to commit.
   GURL url;
 
+  // When a frame navigates another frame, this is the origin of the document
+  // which initiated the navigation. This parameter can be null for
+  // browser-initiated navigations.
+  base::Optional<url::Origin> initiator_origin;
+
   // The URL to send in the "Referer" header field. Can be empty if there is
   // no referrer.
   Referrer referrer;
diff --git a/content/common/navigation_params.mojom b/content/common/navigation_params.mojom
index e43f80a..634e3b7 100644
--- a/content/common/navigation_params.mojom
+++ b/content/common/navigation_params.mojom
@@ -45,14 +45,6 @@
   url.mojom.Url searchable_form_url;
   string searchable_form_encoding;
 
-  // Indicates the initiator of the request. In auxilliary navigations, this is
-  // the origin of the document that triggered the navigation. This parameter
-  // can be null during browser-initiated navigations.
-  // TODO(ahemery): Remove optional when BeginNav is used only for
-  // renderer-initiated navigations. For details see comments from dcheng@ in
-  // review 763529.
-  url.mojom.Origin? initiator_origin;
-
   // If the transition type is a client side redirect, then this holds the URL
   // of the page that had the client side redirect.
   url.mojom.Url client_side_redirect_url;
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index 4a9ba1f..f5bf19a 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -111,6 +111,9 @@
     // The url to load. This field is required.
     GURL url;
 
+    // The origin of the initiator of the navigation.
+    base::Optional<url::Origin> initiator_origin;
+
     // SiteInstance of the frame that initiated the navigation or null if we
     // don't know it.
     scoped_refptr<SiteInstance> source_site_instance;
diff --git a/content/public/browser/page_navigator.h b/content/public/browser/page_navigator.h
index cb1cac3..d387561 100644
--- a/content/public/browser/page_navigator.h
+++ b/content/public/browser/page_navigator.h
@@ -56,6 +56,9 @@
   GURL url;
   Referrer referrer;
 
+  // The origin of the initiator of the navigation.
+  base::Optional<url::Origin> initiator_origin;
+
   // SiteInstance of the frame that initiated the navigation or null if we
   // don't know it.
   scoped_refptr<content::SiteInstance> source_site_instance;
diff --git a/content/public/common/referrer.cc b/content/public/common/referrer.cc
index 58cc39c..d1128fc 100644
--- a/content/public/common/referrer.cc
+++ b/content/public/common/referrer.cc
@@ -150,9 +150,6 @@
       return network::mojom::ReferrerPolicy::kStrictOrigin;
     case net::URLRequest::NO_REFERRER:
       return network::mojom::ReferrerPolicy::kNever;
-    case net::URLRequest::MAX_REFERRER_POLICY:
-      NOTREACHED();
-      return network::mojom::ReferrerPolicy::kDefault;
   }
   NOTREACHED();
   return network::mojom::ReferrerPolicy::kDefault;
diff --git a/content/public/test/navigation_simulator.cc b/content/public/test/navigation_simulator.cc
index 97c50f8..69384fd 100644
--- a/content/public/test/navigation_simulator.cc
+++ b/content/public/test/navigation_simulator.cc
@@ -946,7 +946,7 @@
           blink::mojom::RequestContextType::HYPERLINK,
           blink::WebMixedContentContextType::kBlockable,
           false /* is_form_submission */, GURL() /* searchable_form_url */,
-          std::string() /* searchable_form_encoding */, url::Origin(),
+          std::string() /* searchable_form_encoding */,
           GURL() /* client_side_redirect_url */,
           base::nullopt /* detools_initiator_info */);
   CommonNavigationParams common_params;
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 3d29793..3588950 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -567,11 +567,12 @@
 
 void RenderViewTest::Reload(const GURL& url) {
   CommonNavigationParams common_params(
-      url, Referrer(), ui::PAGE_TRANSITION_LINK, FrameMsg_Navigate_Type::RELOAD,
-      NavigationDownloadPolicy::kAllow, false, GURL(), GURL(),
-      PREVIEWS_UNSPECIFIED, base::TimeTicks::Now(), "GET", nullptr,
-      base::Optional<SourceLocation>(), false /* started_from_context_menu */,
-      false /* has_user_gesture */, InitiatorCSPInfo(), std::string());
+      url, base::nullopt, Referrer(), ui::PAGE_TRANSITION_LINK,
+      FrameMsg_Navigate_Type::RELOAD, NavigationDownloadPolicy::kAllow, false,
+      GURL(), GURL(), PREVIEWS_UNSPECIFIED, base::TimeTicks::Now(), "GET",
+      nullptr, base::Optional<SourceLocation>(),
+      false /* started_from_context_menu */, false /* has_user_gesture */,
+      InitiatorCSPInfo(), std::string());
   RenderViewImpl* impl = static_cast<RenderViewImpl*>(view_);
   TestRenderFrame* frame =
       static_cast<TestRenderFrame*>(impl->GetMainRenderFrame());
@@ -710,7 +711,7 @@
   int pending_offset = offset + impl->history_list_offset_;
 
   CommonNavigationParams common_params(
-      url, Referrer(), ui::PAGE_TRANSITION_FORWARD_BACK,
+      url, base::nullopt, Referrer(), ui::PAGE_TRANSITION_FORWARD_BACK,
       FrameMsg_Navigate_Type::HISTORY_DIFFERENT_DOCUMENT,
       NavigationDownloadPolicy::kAllow, false, GURL(), GURL(),
       PREVIEWS_UNSPECIFIED, base::TimeTicks::Now(), "GET", nullptr,
diff --git a/content/public/test/test_navigation_observer.cc b/content/public/test/test_navigation_observer.cc
index d0966de..ab1fa25 100644
--- a/content/public/test/test_navigation_observer.cc
+++ b/content/public/test/test_navigation_observer.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
+#include "content/browser/frame_host/navigation_request.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -47,7 +48,7 @@
     if (navigation_handle->IsSameDocument())
       return;
 
-    parent_->OnDidStartNavigation();
+    parent_->OnDidStartNavigation(navigation_handle);
   }
 
   void DidFinishNavigation(NavigationHandle* navigation_handle) override {
@@ -178,8 +179,19 @@
     EventTriggered();
 }
 
-void TestNavigationObserver::OnDidStartNavigation() {
+void TestNavigationObserver::OnDidStartNavigation(
+    NavigationHandle* navigation_handle) {
   last_navigation_succeeded_ = false;
+  NavigationHandleImpl* nav_handle =
+      static_cast<NavigationHandleImpl*>(navigation_handle);
+  if (nav_handle->frame_tree_node()->navigation_request()) {
+    last_initiator_origin_ = nav_handle->frame_tree_node()
+                                 ->navigation_request()
+                                 ->common_params()
+                                 .initiator_origin;
+  } else {
+    last_initiator_origin_.reset();
+  }
 }
 
 void TestNavigationObserver::OnDidFinishNavigation(
diff --git a/content/public/test/test_navigation_observer.h b/content/public/test/test_navigation_observer.h
index fdbfae4..ced3c2e 100644
--- a/content/public/test/test_navigation_observer.h
+++ b/content/public/test/test_navigation_observer.h
@@ -67,6 +67,10 @@
 
   bool last_navigation_succeeded() const { return last_navigation_succeeded_; }
 
+  const base::Optional<url::Origin>& last_initiator_origin() const {
+    return last_initiator_origin_;
+  }
+
   net::Error last_net_error_code() const { return last_net_error_code_; }
 
   NavigationType last_navigation_type() const { return last_navigation_type_; }
@@ -99,7 +103,7 @@
   void OnDidAttachInterstitialPage(WebContents* web_contents);
   void OnDidStartLoading(WebContents* web_contents);
   void OnDidStopLoading(WebContents* web_contents);
-  void OnDidStartNavigation();
+  void OnDidStartNavigation(NavigationHandle* navigation_handle);
   void EventTriggered();
 
   // The event that once triggered will quit the run loop.
@@ -123,6 +127,9 @@
   // True if the last navigation succeeded.
   bool last_navigation_succeeded_;
 
+  // The initiator origin of the last observed navigation.
+  base::Optional<url::Origin> last_initiator_origin_;
+
   // The net error code of the last navigation.
   net::Error last_net_error_code_;
 
diff --git a/content/renderer/loader/resource_dispatcher.h b/content/renderer/loader/resource_dispatcher.h
index 12ea227..bfc5505 100644
--- a/content/renderer/loader/resource_dispatcher.h
+++ b/content/renderer/loader/resource_dispatcher.h
@@ -134,7 +134,7 @@
 
   // Removes a request from the |pending_requests_| list, returning true if the
   // request was found and removed.
-  bool RemovePendingRequest(
+  virtual bool RemovePendingRequest(
       int request_id,
       scoped_refptr<base::SingleThreadTaskRunner> task_runner);
 
diff --git a/content/renderer/loader/sync_load_context.cc b/content/renderer/loader/sync_load_context.cc
index 95bea94..51e2de13 100644
--- a/content/renderer/loader/sync_load_context.cc
+++ b/content/renderer/loader/sync_load_context.cc
@@ -121,12 +121,16 @@
     blink::mojom::BlobRegistryPtrInfo download_to_blob_registry,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
     : response_(response),
+      body_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
       download_to_blob_registry_(std::move(download_to_blob_registry)),
       task_runner_(std::move(task_runner)),
       signals_(std::make_unique<SignalHelper>(this,
                                               redirect_or_response_event,
                                               abort_event,
                                               timeout)) {
+  if (download_to_blob_registry_)
+    mode_ = Mode::kBlob;
+
   url_loader_factory_ =
       network::SharedURLLoaderFactory::Create(std::move(url_loader_factory));
 
@@ -182,20 +186,37 @@
 
 void SyncLoadContext::OnStartLoadingResponseBody(
     mojo::ScopedDataPipeConsumerHandle body) {
-  DCHECK(download_to_blob_registry_);
-  DCHECK(!blob_response_started_);
+  if (mode_ == Mode::kBlob) {
+    DCHECK(download_to_blob_registry_);
+    DCHECK(!blob_response_started_);
 
-  blob_response_started_ = true;
+    blob_response_started_ = true;
 
-  download_to_blob_registry_->RegisterFromStream(
-      response_->info.mime_type, "",
-      std::max<int64_t>(0, response_->info.content_length), std::move(body),
-      nullptr,
-      base::BindOnce(&SyncLoadContext::OnFinishCreatingBlob,
-                     base::Unretained(this)));
+    download_to_blob_registry_->RegisterFromStream(
+        response_->info.mime_type, "",
+        std::max<int64_t>(0, response_->info.content_length), std::move(body),
+        nullptr,
+        base::BindOnce(&SyncLoadContext::OnFinishCreatingBlob,
+                       base::Unretained(this)));
+    return;
+  }
+  DCHECK_EQ(Mode::kInitial, mode_);
+  mode_ = Mode::kDataPipe;
+  // setup datapipe to read.
+  body_handle_ = std::move(body);
+  body_watcher_.Watch(
+      body_handle_.get(),
+      MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+      MOJO_TRIGGER_CONDITION_SIGNALS_SATISFIED,
+      base::BindRepeating(&SyncLoadContext::OnBodyReadable,
+                          base::Unretained(this)));
+  body_watcher_.ArmOrNotify();
 }
 
 void SyncLoadContext::OnReceivedData(std::unique_ptr<ReceivedData> data) {
+  if (mode_ == Mode::kInitial)
+    mode_ = Mode::kNonDataPipe;
+  DCHECK_EQ(Mode::kNonDataPipe, mode_);
   DCHECK(!Completed());
   response_->data.append(data->payload(), data->length());
 }
@@ -204,14 +225,20 @@
 
 void SyncLoadContext::OnCompletedRequest(
     const network::URLLoaderCompletionStatus& status) {
-  DCHECK(!Completed());
+  if (Completed()) {
+    // It means the response has been aborted due to an error before finishing
+    // the response.
+    return;
+  }
+  request_completed_ = true;
   response_->error_code = status.error_code;
   response_->extended_error_code = status.extended_error_code;
   response_->cors_error = status.cors_error_status;
   response_->info.encoded_data_length = status.encoded_data_length;
   response_->info.encoded_body_length = status.encoded_body_length;
-  if (blob_response_started_ && !blob_finished_) {
-    request_completed_ = true;
+  if ((blob_response_started_ && !blob_finished_) || body_handle_.is_valid()) {
+    // The body is still begin downloaded as a Blob, or being read through the
+    // handle. Wait until it's completed.
     return;
   }
   CompleteRequest();
@@ -230,6 +257,40 @@
     CompleteRequest();
 }
 
+void SyncLoadContext::OnBodyReadable(MojoResult,
+                                     const mojo::HandleSignalsState&) {
+  DCHECK_EQ(Mode::kDataPipe, mode_);
+  DCHECK(body_handle_.is_valid());
+  const void* buffer = nullptr;
+  uint32_t read_bytes = 0;
+  MojoResult result = body_handle_->BeginReadData(&buffer, &read_bytes,
+                                                  MOJO_READ_DATA_FLAG_NONE);
+  if (result == MOJO_RESULT_SHOULD_WAIT) {
+    body_watcher_.ArmOrNotify();
+    return;
+  }
+  if (result == MOJO_RESULT_FAILED_PRECONDITION) {
+    // Whole body has been read.
+    body_handle_.reset();
+    body_watcher_.Cancel();
+    if (request_completed_)
+      CompleteRequest();
+    return;
+  }
+  if (result != MOJO_RESULT_OK) {
+    // Something went wrong.
+    body_handle_.reset();
+    body_watcher_.Cancel();
+    response_->error_code = net::ERR_FAILED;
+    CompleteRequest();
+    return;
+  }
+
+  response_->data.append(static_cast<const char*>(buffer), read_bytes);
+  body_handle_->EndReadData(read_bytes);
+  body_watcher_.ArmOrNotify();
+}
+
 void SyncLoadContext::OnAbort(base::WaitableEvent* event) {
   DCHECK(!Completed());
   response_->error_code = net::ERR_ABORTED;
@@ -245,6 +306,8 @@
 }
 
 void SyncLoadContext::CompleteRequest() {
+  DCHECK(blob_finished_ || (mode_ != Mode::kBlob));
+  DCHECK(!body_handle_.is_valid());
   signals_->SignalRedirectOrResponseComplete();
   signals_ = nullptr;
   response_ = nullptr;
diff --git a/content/renderer/loader/sync_load_context.h b/content/renderer/loader/sync_load_context.h
index eef5d30..d98ec9bf 100644
--- a/content/renderer/loader/sync_load_context.h
+++ b/content/renderer/loader/sync_load_context.h
@@ -10,8 +10,11 @@
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event_watcher.h"
 #include "base/timer/timer.h"
+#include "content/common/content_export.h"
 #include "content/public/renderer/request_peer.h"
 #include "content/renderer/loader/resource_dispatcher.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/blink/public/mojom/blob/blob_registry.mojom.h"
@@ -30,7 +33,15 @@
 
 // This class owns the context necessary to perform an asynchronous request
 // while the main thread is blocked so that it appears to be synchronous.
-class SyncLoadContext : public RequestPeer {
+// There are a few mode to load a request:
+//   1) kNonDataPipe: body is received on OnReceivedData(), and the body is set
+//      to response_.data.
+//   2) kDataPipe; body is received on a data pipe passed on
+//      OnStartLoadingResponseBody(), and the body is set to response_.data.
+//   3) kBlob: body is received on a data pipe passed on
+//      OnStartLoadingResponseBody(), and wraps the data pipe with a
+//      SerializedBlobPtr.
+class CONTENT_EXPORT SyncLoadContext : public RequestPeer {
  public:
   // Begins a new asynchronous request on whatever sequence this method is
   // called on. |completed_event| will be signalled when the request is complete
@@ -59,6 +70,8 @@
   void CancelRedirect();
 
  private:
+  friend class SyncLoadContextTest;
+
   SyncLoadContext(
       network::ResourceRequest* request,
       std::unique_ptr<network::SharedURLLoaderFactoryInfo> url_loader_factory,
@@ -83,6 +96,8 @@
 
   void OnFinishCreatingBlob(blink::mojom::SerializedBlobPtr blob);
 
+  void OnBodyReadable(MojoResult, const mojo::HandleSignalsState&);
+
   void OnAbort(base::WaitableEvent* event);
   void OnTimeout();
 
@@ -94,6 +109,13 @@
   // Set to null after CompleteRequest() is called.
   SyncLoadResponse* response_;
 
+  enum class Mode { kInitial, kNonDataPipe, kDataPipe, kBlob };
+  Mode mode_ = Mode::kInitial;
+
+  // Used when Mode::kDataPipe.
+  mojo::ScopedDataPipeConsumerHandle body_handle_;
+  mojo::SimpleWatcher body_watcher_;
+
   // State necessary to run a request on an independent thread.
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   std::unique_ptr<ResourceDispatcher> resource_dispatcher_;
diff --git a/content/renderer/loader/sync_load_context_unittest.cc b/content/renderer/loader/sync_load_context_unittest.cc
new file mode 100644
index 0000000..83ce44aa
--- /dev/null
+++ b/content/renderer/loader/sync_load_context_unittest.cc
@@ -0,0 +1,250 @@
+// 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/renderer/loader/sync_load_context.h"
+#include "base/bind.h"
+#include "base/threading/thread.h"
+#include "content/public/renderer/fixed_received_data.h"
+#include "content/renderer/loader/sync_load_response.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+namespace {
+
+class TestSharedURLLoaderFactory : public network::TestURLLoaderFactory,
+                                   public network::SharedURLLoaderFactory {
+ public:
+  // mojom::URLLoaderFactory implementation.
+  void CreateLoaderAndStart(network::mojom::URLLoaderRequest request,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const network::ResourceRequest& url_request,
+                            network::mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override {
+    network::TestURLLoaderFactory::CreateLoaderAndStart(
+        std::move(request), routing_id, request_id, options, url_request,
+        std::move(client), traffic_annotation);
+  }
+
+  void Clone(network::mojom::URLLoaderFactoryRequest) override { NOTREACHED(); }
+
+  std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override {
+    NOTREACHED();
+    return nullptr;
+  }
+
+ private:
+  friend class base::RefCounted<TestSharedURLLoaderFactory>;
+  ~TestSharedURLLoaderFactory() override = default;
+};
+
+class MockSharedURLLoaderFactoryInfo
+    : public network::SharedURLLoaderFactoryInfo {
+ public:
+  explicit MockSharedURLLoaderFactoryInfo()
+      : factory_(base::MakeRefCounted<TestSharedURLLoaderFactory>()) {}
+
+  scoped_refptr<TestSharedURLLoaderFactory> factory() const { return factory_; }
+
+ protected:
+  scoped_refptr<network::SharedURLLoaderFactory> CreateFactory() override {
+    return factory_;
+  }
+
+  scoped_refptr<TestSharedURLLoaderFactory> factory_;
+};
+
+class MockResourceDispatcher : public ResourceDispatcher {
+ public:
+  int CreatePendingRequest(std::unique_ptr<RequestPeer> peer) {
+    peers_.push_back(std::move(peer));
+    return peers_.size() - 1;
+  }
+
+  bool RemovePendingRequest(
+      int request_id,
+      scoped_refptr<base::SingleThreadTaskRunner>) override {
+    if (request_id < 0 || static_cast<int>(peers_.size()) <= request_id)
+      return false;
+    peers_[request_id].reset();
+    return true;
+  }
+
+ private:
+  std::vector<std::unique_ptr<RequestPeer>> peers_;
+};
+
+}  // namespace
+
+class SyncLoadContextTest : public testing::Test {
+ public:
+  SyncLoadContextTest() : loading_thread_("loading thread") {}
+
+  void SetUp() override {
+    ASSERT_TRUE(loading_thread_.StartAndWaitForTesting());
+  }
+
+  void StartAsyncWithWaitableEventOnLoadingThread(
+      std::unique_ptr<network::ResourceRequest> request,
+      std::unique_ptr<network::SharedURLLoaderFactoryInfo> factory_info,
+      SyncLoadResponse* out_response,
+      base::WaitableEvent* redirect_or_response_event) {
+    loading_thread_.task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &SyncLoadContext::StartAsyncWithWaitableEvent, std::move(request),
+            MSG_ROUTING_NONE, loading_thread_.task_runner(),
+            TRAFFIC_ANNOTATION_FOR_TESTS, std::move(factory_info),
+            std::vector<std::unique_ptr<URLLoaderThrottle>>(), out_response,
+            redirect_or_response_event, nullptr /* terminate_sync_load_event */,
+            base::TimeDelta::FromSeconds(60) /* timeout */,
+            nullptr /* download_to_blob_registry */));
+  }
+
+  static void RunSyncLoadContextViaNonDataPipe(
+      network::ResourceRequest* request,
+      SyncLoadResponse* response,
+      std::string expected_data,
+      base::WaitableEvent* redirect_or_response_event,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    DCHECK(task_runner->BelongsToCurrentThread());
+    auto* context = new SyncLoadContext(
+        request, std::make_unique<MockSharedURLLoaderFactoryInfo>(), response,
+        redirect_or_response_event, nullptr /* terminate_sync_load_event */,
+        base::TimeDelta::FromSeconds(60) /* timeout */,
+        nullptr /* download_to_blob_registry */, task_runner);
+
+    // Override |resource_dispatcher_| for testing.
+    auto dispatcher = std::make_unique<MockResourceDispatcher>();
+    context->request_id_ =
+        dispatcher->CreatePendingRequest(base::WrapUnique(context));
+    context->resource_dispatcher_ = std::move(dispatcher);
+
+    // Simulate the response.
+    context->OnReceivedResponse(network::ResourceResponseInfo());
+    context->OnReceivedData(std::make_unique<FixedReceivedData>(
+        expected_data.data(), expected_data.size()));
+    context->OnCompletedRequest(network::URLLoaderCompletionStatus(net::OK));
+  }
+
+  static void RunSyncLoadContextViaDataPipe(
+      network::ResourceRequest* request,
+      SyncLoadResponse* response,
+      std::string expected_data,
+      base::WaitableEvent* redirect_or_response_event,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    DCHECK(task_runner->BelongsToCurrentThread());
+    auto* context = new SyncLoadContext(
+        request, std::make_unique<MockSharedURLLoaderFactoryInfo>(), response,
+        redirect_or_response_event, nullptr /* terminate_sync_load_event */,
+        base::TimeDelta::FromSeconds(60) /* timeout */,
+        nullptr /* download_to_blob_registry */, task_runner);
+
+    // Override |resource_dispatcher_| for testing.
+    auto dispatcher = std::make_unique<MockResourceDispatcher>();
+    context->request_id_ =
+        dispatcher->CreatePendingRequest(base::WrapUnique(context));
+    context->resource_dispatcher_ = std::move(dispatcher);
+
+    // Simulate the response.
+    context->OnReceivedResponse(network::ResourceResponseInfo());
+    mojo::ScopedDataPipeProducerHandle producer_handle;
+    mojo::ScopedDataPipeConsumerHandle consumer_handle;
+    EXPECT_EQ(MOJO_RESULT_OK,
+              mojo::CreateDataPipe(nullptr /* options */, &producer_handle,
+                                   &consumer_handle));
+    context->OnStartLoadingResponseBody(std::move(consumer_handle));
+    context->OnCompletedRequest(network::URLLoaderCompletionStatus(net::OK));
+
+    mojo::BlockingCopyFromString(expected_data, producer_handle);
+  }
+
+  base::Thread loading_thread_;
+};
+
+TEST_F(SyncLoadContextTest, StartAsyncWithWaitableEvent) {
+  GURL expected_url = GURL("https://example.com");
+  std::string expected_data = "foobarbaz";
+
+  // Create and exercise SyncLoadContext on the |loading_thread_|.
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = expected_url;
+  auto factory_info = std::make_unique<MockSharedURLLoaderFactoryInfo>();
+  factory_info->factory()->AddResponse(expected_url.spec(), expected_data);
+  SyncLoadResponse response;
+  base::WaitableEvent redirect_or_response_event(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  StartAsyncWithWaitableEventOnLoadingThread(std::move(request),
+                                             std::move(factory_info), &response,
+                                             &redirect_or_response_event);
+
+  // Wait until the response is received.
+  redirect_or_response_event.Wait();
+
+  // Check if |response| is set properly after the WaitableEvent fires.
+  EXPECT_EQ(net::OK, response.error_code);
+  EXPECT_EQ(expected_data, response.data);
+}
+
+TEST_F(SyncLoadContextTest, ResponseBodyViaNonDataPipe) {
+  GURL expected_url = GURL("https://example.com");
+  std::string expected_data = "foobarbaz";
+
+  // Create and exercise SyncLoadContext on the |loading_thread_|.
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = expected_url;
+  SyncLoadResponse response;
+  base::WaitableEvent redirect_or_response_event(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  loading_thread_.task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SyncLoadContextTest::RunSyncLoadContextViaNonDataPipe,
+                     request.get(), &response, expected_data,
+                     &redirect_or_response_event,
+                     loading_thread_.task_runner()));
+
+  // Wait until the response is received.
+  redirect_or_response_event.Wait();
+
+  // Check if |response| is set properly after the WaitableEvent fires.
+  EXPECT_EQ(net::OK, response.error_code);
+  EXPECT_EQ(expected_data, response.data);
+}
+
+TEST_F(SyncLoadContextTest, ResponseBodyViaDataPipe) {
+  GURL expected_url = GURL("https://example.com");
+  std::string expected_data = "foobarbaz";
+
+  // Create and exercise SyncLoadContext on the |loading_thread_|.
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = expected_url;
+  SyncLoadResponse response;
+  base::WaitableEvent redirect_or_response_event(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+  loading_thread_.task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&SyncLoadContextTest::RunSyncLoadContextViaDataPipe,
+                     request.get(), &response, expected_data,
+                     &redirect_or_response_event,
+                     loading_thread_.task_runner()));
+
+  // Wait until the response is received.
+  redirect_or_response_event.Wait();
+
+  // Check if |response| is set properly after the WaitableEvent fires.
+  EXPECT_EQ(net::OK, response.error_code);
+  EXPECT_EQ(expected_data, response.data);
+}
+
+}  // namespace content
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index eb89a7c..a69e8c11 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -475,6 +475,14 @@
 
   request.SetOriginPolicy(WebString::FromUTF8(common_params.origin_policy));
 
+  // Set the request initiator origin, which is supplied by the browser
+  // process. It is present in cases such as navigating a frame in a different
+  // process, which is routed through RenderFrameProxy and the origin is
+  // required to correctly compute the effective origin in which the
+  // navigation will commit.
+  if (common_params.initiator_origin)
+    request.SetRequestorOrigin(common_params.initiator_origin.value());
+
   auto extra_data = std::make_unique<RequestExtraData>();
   extra_data->set_navigation_response_override(std::move(response_override));
   extra_data->set_navigation_initiated_by_renderer(
@@ -510,6 +518,9 @@
     std::unique_ptr<blink::WebNavigationInfo> info,
     int load_flags,
     bool prevent_sandboxed_download) {
+  // A valid RequestorOrigin is always expected to be present.
+  DCHECK(!info->url_request.RequestorOrigin().IsNull());
+
   Referrer referrer(
       GURL(info->url_request.HttpHeaderField(WebString::FromUTF8("Referer"))
                .Latin1()),
@@ -549,8 +560,8 @@
       GetDownloadPolicy(prevent_sandboxed_download, info->is_opener_navigation,
                         info->url_request, current_origin);
   return CommonNavigationParams(
-      info->url_request.Url(), referrer, extra_data->transition_type(),
-      navigation_type, download_policy,
+      info->url_request.Url(), info->url_request.RequestorOrigin(), referrer,
+      extra_data->transition_type(), navigation_type, download_policy,
       info->frame_load_type == WebFrameLoadType::kReplaceCurrentItem, GURL(),
       GURL(), static_cast<PreviewsState>(info->url_request.GetPreviewsState()),
       base::TimeTicks::Now(), info->url_request.HttpMethod().Latin1(),
@@ -6382,9 +6393,13 @@
 
 void RenderFrameImpl::OpenURL(std::unique_ptr<blink::WebNavigationInfo> info,
                               bool is_history_navigation_in_new_child) {
+  // A valid RequestorOrigin is always expected to be present.
+  DCHECK(!info->url_request.RequestorOrigin().IsNull());
+
   WebNavigationPolicy policy = info->navigation_policy;
   FrameHostMsg_OpenURL_Params params;
   params.url = info->url_request.Url();
+  params.initiator_origin = info->url_request.RequestorOrigin();
   params.uses_post = IsHttpPost(info->url_request);
   params.resource_request_body =
       GetRequestBodyForWebURLRequest(info->url_request);
@@ -6733,10 +6748,6 @@
          info->url_request.GetFrameType() ==
              network::mojom::RequestContextFrameType::kNested);
 
-  DCHECK(!info->url_request.RequestorOrigin().IsNull());
-  base::Optional<url::Origin> initiator_origin =
-      base::Optional<url::Origin>(info->url_request.RequestorOrigin());
-
   bool is_form_submission =
       info->navigation_type == blink::kWebNavigationTypeFormSubmitted ||
       info->navigation_type == blink::kWebNavigationTypeFormResubmitted;
@@ -6766,7 +6777,7 @@
           GetRequestContextTypeForWebURLRequest(info->url_request),
           GetMixedContentContextTypeForWebURLRequest(info->url_request),
           is_form_submission, searchable_form_url, searchable_form_encoding,
-          initiator_origin, client_side_redirect_url,
+          client_side_redirect_url,
           initiator ? base::make_optional<base::Value>(std::move(*initiator))
                     : base::nullopt);
 
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index ca11093..4c94207 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -788,8 +788,12 @@
 void RenderFrameProxy::Navigate(const blink::WebURLRequest& request,
                                 bool should_replace_current_entry,
                                 mojo::ScopedMessagePipeHandle blob_url_token) {
+  // The request must always have a valid initiator origin.
+  DCHECK(!request.RequestorOrigin().IsNull());
+
   FrameHostMsg_OpenURL_Params params;
   params.url = request.Url();
+  params.initiator_origin = request.RequestorOrigin();
   params.uses_post = request.HttpMethod().Utf8() == "POST";
   params.resource_request_body = GetRequestBodyForWebURLRequest(request);
   params.extra_headers = GetWebURLRequestHeadersAsString(request);
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 8e1979d..c01abf5 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -660,6 +660,9 @@
   WebUITestWebUIControllerFactory factory;
   WebUIControllerFactory::RegisterFactory(&factory);
 
+  blink::WebSecurityOrigin requestor_origin =
+      blink::WebSecurityOrigin::Create(GURL("http://foo.com"));
+
   // Navigations to normal HTTP URLs can be handled locally.
   blink::WebURLRequest request(GURL("http://foo.com"));
   request.SetFetchRequestMode(network::mojom::FetchRequestMode::kNavigate);
@@ -668,12 +671,12 @@
   request.SetFetchRedirectMode(network::mojom::FetchRedirectMode::kManual);
   request.SetFrameType(network::mojom::RequestContextFrameType::kTopLevel);
   request.SetRequestContext(blink::mojom::RequestContextType::INTERNAL);
-  request.SetRequestorOrigin(
-      blink::WebSecurityOrigin::Create(GURL("http://foo.com")));
+  request.SetRequestorOrigin(requestor_origin);
   auto navigation_info = std::make_unique<blink::WebNavigationInfo>();
   navigation_info->url_request = request;
   navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   navigation_info->navigation_policy = blink::kWebNavigationPolicyCurrentTab;
+  DCHECK(!navigation_info->url_request.RequestorOrigin().IsNull());
   frame()->BeginNavigation(std::move(navigation_info));
   // If this is a renderer-initiated navigation that just begun, it should
   // stop and be sent to the browser.
@@ -684,6 +687,7 @@
   form_navigation_info->url_request =
       blink::WebURLRequest(GURL("chrome://foo"));
   form_navigation_info->url_request.SetHTTPMethod("POST");
+  form_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   form_navigation_info->navigation_type =
       blink::kWebNavigationTypeFormSubmitted;
   form_navigation_info->navigation_policy =
@@ -698,6 +702,7 @@
   auto popup_navigation_info = std::make_unique<blink::WebNavigationInfo>();
   popup_navigation_info->url_request =
       blink::WebURLRequest(GURL("chrome://foo"));
+  popup_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   popup_navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   popup_navigation_info->navigation_policy =
       blink::kWebNavigationPolicyNewForegroundTab;
@@ -724,6 +729,8 @@
   for (size_t i = 0; i < arraysize(kNavTypes); ++i) {
     auto navigation_info = std::make_unique<blink::WebNavigationInfo>();
     navigation_info->url_request = blink::WebURLRequest(GURL("http://foo.com"));
+    navigation_info->url_request.SetRequestorOrigin(
+        blink::WebSecurityOrigin::Create(GURL("http://foo.com")));
     navigation_info->navigation_policy = blink::kWebNavigationPolicyCurrentTab;
     navigation_info->navigation_type = kNavTypes[i];
 
@@ -738,9 +745,13 @@
   // Enable bindings to simulate a WebUI view.
   view()->GetMainRenderFrame()->AllowBindings(BINDINGS_POLICY_WEB_UI);
 
+  blink::WebSecurityOrigin requestor_origin =
+      blink::WebSecurityOrigin::Create(GURL("http://foo.com"));
+
   // Navigations to normal HTTP URLs will be sent to browser process.
   auto navigation_info = std::make_unique<blink::WebNavigationInfo>();
   navigation_info->url_request = blink::WebURLRequest(GURL("http://foo.com"));
+  navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   navigation_info->navigation_policy = blink::kWebNavigationPolicyCurrentTab;
 
@@ -753,6 +764,7 @@
   auto webui_navigation_info = std::make_unique<blink::WebNavigationInfo>();
   webui_navigation_info->url_request =
       blink::WebURLRequest(GURL("chrome://foo"));
+  webui_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   webui_navigation_info->navigation_type = blink::kWebNavigationTypeLinkClicked;
   webui_navigation_info->navigation_policy =
       blink::kWebNavigationPolicyCurrentTab;
@@ -765,6 +777,7 @@
   auto data_navigation_info = std::make_unique<blink::WebNavigationInfo>();
   data_navigation_info->url_request =
       blink::WebURLRequest(GURL("data:text/html,foo"));
+  data_navigation_info->url_request.SetRequestorOrigin(requestor_origin);
   data_navigation_info->url_request.SetHTTPMethod("POST");
   data_navigation_info->navigation_type =
       blink::kWebNavigationTypeFormSubmitted;
@@ -779,6 +792,7 @@
   // normal HTTP URL will be sent to the browser process, even though the
   // new view does not have any enabled_bindings_.
   blink::WebURLRequest popup_request(GURL("http://foo.com"));
+  popup_request.SetRequestorOrigin(requestor_origin);
   blink::WebView* new_web_view = view()->CreateView(
       GetMainFrame(), popup_request, blink::WebWindowFeatures(), "foo",
       blink::kWebNavigationPolicyNewForegroundTab, false,
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
index 961fbe17..f13145a 100644
--- a/content/shell/browser/shell.cc
+++ b/content/shell/browser/shell.cc
@@ -441,6 +441,7 @@
   }
 
   NavigationController::LoadURLParams load_url_params(params.url);
+  load_url_params.initiator_origin = params.initiator_origin;
   load_url_params.source_site_instance = params.source_site_instance;
   load_url_params.transition_type = params.transition;
   load_url_params.frame_tree_node_id = params.frame_tree_node_id;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index e82a810..b4567a8 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1717,6 +1717,7 @@
     "../renderer/input/main_thread_event_queue_unittest.cc",
     "../renderer/loader/resource_dispatcher_unittest.cc",
     "../renderer/loader/shared_memory_data_consumer_handle_unittest.cc",
+    "../renderer/loader/sync_load_context_unittest.cc",
     "../renderer/loader/test_request_peer.cc",
     "../renderer/loader/test_request_peer.h",
     "../renderer/loader/url_loader_client_impl_unittest.cc",
diff --git a/content/test/data/accessibility/html/audio-expected-auralinux.txt b/content/test/data/accessibility/html/audio-expected-auralinux.txt
index 1c70d30e..d0201060 100644
--- a/content/test/data/accessibility/html/audio-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/audio-expected-auralinux.txt
@@ -8,4 +8,6 @@
 ++++++++++++[text] name='0:00'
 ++++++++++++[text] name='/ 0:00'
 ++++++++++++[slider] description='audio time scrubber' horizontal xml-roles:slider
-++++++++++++[push button] name='mute' xml-roles:button
+++++++++++++[section]
+++++++++++++++[section]
+++++++++++++++[push button] name='mute' xml-roles:button
diff --git a/content/test/data/accessibility/html/source-expected-auralinux.txt b/content/test/data/accessibility/html/source-expected-auralinux.txt
index ab0b222..c9866f0a 100644
--- a/content/test/data/accessibility/html/source-expected-auralinux.txt
+++ b/content/test/data/accessibility/html/source-expected-auralinux.txt
@@ -8,4 +8,6 @@
 ++++++++++++[text] name='0:00'
 ++++++++++++[text] name='/ 0:00'
 ++++++++++++[slider] description='audio time scrubber' focusable horizontal
-++++++++++++[push button] name='mute'
+++++++++++++[section]
+++++++++++++++[section]
+++++++++++++++[push button] name='mute'
diff --git a/content/test/data/sxg/generate-test-sxgs.sh b/content/test/data/sxg/generate-test-sxgs.sh
index 50f82c4..e1b7920 100755
--- a/content/test/data/sxg/generate-test-sxgs.sh
+++ b/content/test/data/sxg/generate-test-sxgs.sh
@@ -48,6 +48,9 @@
   -o test.example.org_test.sxg \
   -miRecordSize 100
 
+# Generate the signed exchange for the missing nosniff header test case.
+cp test.example.org_test.sxg test.example.org_test_missing_nosniff.sxg
+
 # Generate the signed exchange for the invalid content-type test case.
 cp test.example.org_test.sxg test.example.org_test_invalid_content_type.sxg
 
diff --git a/content/test/data/sxg/test.example.org_test.sxg.mock-http-headers b/content/test/data/sxg/test.example.org_test.sxg.mock-http-headers
index 9617855..f481dcf3 100644
--- a/content/test/data/sxg/test.example.org_test.sxg.mock-http-headers
+++ b/content/test/data/sxg/test.example.org_test.sxg.mock-http-headers
@@ -1,2 +1,3 @@
 HTTP/1.1 200 OK
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/content/test/data/sxg/test.example.org_test_download.sxg.mock-http-headers b/content/test/data/sxg/test.example.org_test_download.sxg.mock-http-headers
index aa7dca6..4bb0ce56 100644
--- a/content/test/data/sxg/test.example.org_test_download.sxg.mock-http-headers
+++ b/content/test/data/sxg/test.example.org_test_download.sxg.mock-http-headers
@@ -1,3 +1,4 @@
 HTTP/1.1 200 OK
 Content-Type: application/signed-exchange;v=b2
 Content-Disposition: attachment; filename=test.sxg
+X-Content-Type-Options: nosniff
diff --git a/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg.mock-http-headers b/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg.mock-http-headers
index 9617855..f481dcf3 100644
--- a/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg.mock-http-headers
+++ b/content/test/data/sxg/test.example.org_test_invalid_cbor_header.sxg.mock-http-headers
@@ -1,2 +1,3 @@
 HTTP/1.1 200 OK
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg.mock-http-headers b/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg.mock-http-headers
index fa28f64..81f80fb 100644
--- a/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg.mock-http-headers
+++ b/content/test/data/sxg/test.example.org_test_invalid_content_type.sxg.mock-http-headers
@@ -1,2 +1,3 @@
 HTTP/1.1 200 OK
 Content-Type: application/signed-exchange
+X-Content-Type-Options: nosniff
diff --git a/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg.mock-http-headers b/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg.mock-http-headers
index 9617855..f481dcf3 100644
--- a/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg.mock-http-headers
+++ b/content/test/data/sxg/test.example.org_test_invalid_magic_string.sxg.mock-http-headers
@@ -1,2 +1,3 @@
 HTTP/1.1 200 OK
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg b/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg
new file mode 100644
index 0000000..9d8d772
--- /dev/null
+++ b/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg
Binary files differ
diff --git a/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg.mock-http-headers b/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg.mock-http-headers
new file mode 100644
index 0000000..9617855
--- /dev/null
+++ b/content/test/data/sxg/test.example.org_test_missing_nosniff.sxg.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Content-Type: application/signed-exchange;v=b2
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 43b358f..34d4ca9 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -136,6 +136,9 @@
     self.Fail('conformance2/rendering/' +
         'framebuffer-texture-changing-base-level.html',
         ['win'], bug=2291) # angle bug ID
+    self.Fail('conformance2/textures/misc/' +
+        'generate-mipmap-with-large-base-level.html',
+        ['win', 'no_passthrough'], bug=3033) # angle bug ID
 
     # Win / NVidia
     self.Flaky('deqp/functional/gles3/fbomultisample*',
@@ -896,6 +899,8 @@
     self.Flaky('conformance2/textures/image_bitmap_from_image_data/' +
         'tex-2d-srgb8-rgb-unsigned_byte.html',
         ['linux', 'no_passthrough', 'nvidia'], bug=694354)
+    self.Flaky('conformance2/transform_feedback/switching-objects.html',
+        ['linux', 'no_passthrough', 'nvidia'], bug=832238)
 
     # Linux NVIDIA Quadro P400
     self.Skip('conformance2/rendering/blitframebuffer-size-overflow.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
index 6b338de..43bce18 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
+++ b/content/test/gpu/gpu_tests/webgl_conformance_revision.txt
@@ -1,3 +1,3 @@
 # AUTOGENERATED FILE - DO NOT EDIT
 # SEE roll_webgl_conformance.py
-Current webgl revision 5b6cbd789b9b91b4e46dde883c9f2ecb31eddade
+Current webgl revision a2b35635aaef3e9301d69f77f9a0a3fd99291b08
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 124d8b1..35c6037 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -376,7 +376,6 @@
   // initialized. Do it if it hasn't happened yet.
   InitializeRenderFrameIfNeeded();
 
-  // TODO(mkwst): The initiator origin here is incorrect.
   mojom::BeginNavigationParamsPtr begin_params =
       mojom::BeginNavigationParams::New(
           std::string() /* headers */, net::LOAD_NORMAL,
@@ -384,9 +383,10 @@
           blink::mojom::RequestContextType::HYPERLINK,
           blink::WebMixedContentContextType::kBlockable,
           false /* is_form_submission */, GURL() /* searchable_form_url */,
-          std::string() /* searchable_form_encoding */, url::Origin(),
+          std::string() /* searchable_form_encoding */,
           GURL() /* client_side_redirect_url */,
           base::nullopt /* devtools_initiator_info */);
+  // TODO(mkwst): The initiator origin in |common_params| is missing/incorrect.
   CommonNavigationParams common_params;
   common_params.url = url;
   common_params.referrer =
diff --git a/docs/gpu/webgl_bug_triage.md b/docs/gpu/webgl_bug_triage.md
new file mode 100644
index 0000000..2612815e
--- /dev/null
+++ b/docs/gpu/webgl_bug_triage.md
@@ -0,0 +1,93 @@
+# WebGL Bug Triage Rotation
+
+The WebGL team receives many bug reports from users of Chrome, and web
+developers in particular. In order to maintain a high quality product, and
+enable customers to deploy successful 3D web applications, it's important that
+these reports be evaluated in a timely manner.
+
+In order to better scale the team's efforts, a bug triage rotation has been
+introduced. The specifics of the rotation follow:
+
+* Each rotation is one week long.
+
+* The current triager is responsible for:
+
+  * Monitoring the incoming new bugs to the Blink>WebGL component, per the
+    following query:
+
+    * [Open bugs not needing feedback, and in the Unconfirmed or Unassigned
+      state](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=is%3Aopen+component%3ABlink%3EWebGL+status%3AUnconfirmed%2CUntriaged+-label%3ANeeds-Feedback%2CNeeds-Bisect%2CNeeds-TestConfirmation&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+  * If the query above doesn't turn up anything, it's possible that the bug was
+    already moved into a different state by the GPU triage rotation. In this
+    case please look into the following queries. Please note that these will
+    turn up much larger lists, so only focus on the new bugs.
+
+    * [Same query as above, but including Available and Assigned bugs](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=is%3Aopen+component%3ABlink%3EWebGL+status%3AUnconfirmed%2CUntriaged%2CAvailable%2CAssigned+-label%3ANeeds-Feedback%2CNeeds-Bisect%2CNeeds-TestConfirmation&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+    * [Open bugs which haven't been
+      started](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=is%3Aopen+component%3ABlink%3EWebGL+-status%3AStarted&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+    * [All open
+      bugs](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=is%3Aopen+component%3ABlink%3EWebGL&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+  * Please also monitor these candidates for closing as WontFix:
+
+    * [Open bugs needing feedback of some sort, not updated in the last 30
+      days](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=is%3Aopen+component%3ABlink%3EWebGL+label%3ANeeds+modified%3Ctoday-30&colspec=ID+Pri+M+Stars+ReleaseBlock+Component+Status+Owner+Summary+OS+Modified&x=m&y=releaseblock&cells=ids)
+
+  * If an issue interacts with other components, add those components. (e.g. V8
+    via Blink>JavaScript or sub-components, media usually via
+    Internals>GPU>Video or Internals>Media>Video)
+
+  * Determining on what graphics hardware the bug occurs, and assigning GPU- and
+    OS- labels.
+
+  * Reproducing these bugs, as best as possible, given the graphics hardware at
+    the team's disposal.
+
+  * Figuring out whether it's a bug in the application, and, if so, closing the
+    bug with an explanation.
+
+  * Figuring out whether the bug is a regression. If it's appropriate to ask the
+    submitter to [run a
+    bisect](https://www.chromium.org/developers/bisect-builds-py), please do so;
+    if it would be easy for Chrome's Test Engineering team to run it, add the
+    Needs-Bisect label; or run a [per-revision
+    bisect](https://sites.google.com/a/google.com/chrome-te/home/tools/bisect_builds?pli=1)
+    (Google internal, sorry) manually.
+
+  * If the Summary is undescriptive or imprecise, rewriting it.
+
+  * Determining a Type and Priority for the bug, and assigning
+    ReleaseBlock-(Stable/Beta/Dev) if appropriate.
+
+  * Working with the submitter to produce a reduced test case if at all
+    possible, and, if so, integrating that test into the WebGL conformance
+    suite. Add the Needs-Feedback label as appropriate to remove the bug from
+    the queries above.
+
+  * Marking the bug as duplicate if necessary.
+
+  * Finding potentially-related bugs and recent changes, adding
+    Blocking/Blocked-on links.
+
+  * Assigning to the owner of a likely-related bug or recent change.
+
+Prefer to use the "Available" state to indicate that a bug's been triaged,
+rather than assigning bugs to yourself, to avoid having a big bug backlog. For
+any new bug that's not related to a recent or existing issue, there should be no
+owner.
+
+It's the triager's responsibility to do the above steps for all of the incoming
+bugs during that shift. Bugs that aren't handled during a given shift stay with
+the triager; they don't spill over to the next shift, unless there's agreement
+with the person next on the triage rotation.
+
+This is intended to be a lightweight rotation that shouldn't take too much of
+the triager's time. For this reason it's scheduled independently of other shifts
+like [pixel wrangling](pixel_wrangling.md), and may overlap. If any conflicts do
+arise, please reach out or [swap
+shifts](https://www.chromium.org/developers/tree-sheriffs#TOC-How-to-swap).
+
+(TODO(kbr): link to the rotation tool.)
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 92c895e..04e61b0 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -8,7 +8,7 @@
 
 // Enables the use of C++-based extension bindings (instead of JS generation).
 const base::Feature kNativeCrxBindings{"NativeCrxBindings",
-                                       base::FEATURE_DISABLED_BY_DEFAULT};
+                                       base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables new extension updater service.
 const base::Feature kNewExtensionUpdaterService{
diff --git a/extensions/test/data/api_test/printer_provider/request_capability/test.js b/extensions/test/data/api_test/printer_provider/request_capability/test.js
index 3ed58ea..23a209f6 100644
--- a/extensions/test/data/api_test/printer_provider/request_capability/test.js
+++ b/extensions/test/data/api_test/printer_provider/request_capability/test.js
@@ -31,9 +31,7 @@
             var jsBindingsError =
                 'Invalid value for argument 1. Expected \'object\'' +
                 ' but got \'string\'.';
-            var nativeBindingsError =
-                'Error at parameter \'capabilities\': ' +
-                'Invalid type: expected object, found string.';
+            var nativeBindingsError = 'No matching signature.';
             var regexp =
                 new RegExp(nativeBindingsError + '|' + jsBindingsError);
             chrome.test.assertThrows(callback, ['XXX'], regexp);
diff --git a/extensions/test/data/api_test/printer_provider/request_printers/test.js b/extensions/test/data/api_test/printer_provider/request_printers/test.js
index 8878753..dc334939 100644
--- a/extensions/test/data/api_test/printer_provider/request_printers/test.js
+++ b/extensions/test/data/api_test/printer_provider/request_printers/test.js
@@ -38,9 +38,7 @@
             var jsBindingsError =
                 'Invalid value for argument 1. ' +
                 'Expected \'array\' but got \'string\'.'
-            var nativeBindingsError =
-                'Error at parameter \'printerInfo\': ' +
-                'Invalid type: expected array, found string.'
+            var nativeBindingsError = 'No matching signature';
             chrome.test.assertThrows(
                 callback, ['XXX'],
                 eitherError(jsBindingsError, nativeBindingsError));
diff --git a/infra/config/PRESUBMIT.py b/infra/config/PRESUBMIT.py
index 4a8e36a..253d7f7 100644
--- a/infra/config/PRESUBMIT.py
+++ b/infra/config/PRESUBMIT.py
@@ -2,11 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-
 def _CommonChecks(input_api, output_api):
   commands = []
-  # TODO(martiniss): Move this check to the root presubmit. It checks to ensure
-  # that path regexps in cq.cfg reference something locally.
   touches_cq = False
   for f in input_api.AffectedFiles():
     local_path = f.LocalPath()
@@ -17,21 +14,23 @@
     commands.append(
       input_api.Command(
         name='cq.cfg presubmit', cmd=[
-            input_api.python_executable, 'branch/cq_cfg_presubmit.py',
+            input_api.python_executable, input_api.os_path.join(
+                'branch', 'cq_cfg_presubmit.py'),
             '--check'],
         kwargs={}, message=output_api.PresubmitError),
     )
 
-  results = []
-
-  results.extend(input_api.canned_checks.CheckChangedLUCIConfigs(
-      input_api, output_api))
-
   commands.extend(input_api.canned_checks.GetUnitTestsRecursively(
       input_api, output_api,
       input_api.os_path.join(input_api.PresubmitLocalPath()),
       whitelist=[r'.+_unittest\.py$'], blacklist=[]))
+
+  results = []
+
   results.extend(input_api.RunTests(commands))
+  results.extend(input_api.canned_checks.CheckChangedLUCIConfigs(
+      input_api, output_api))
+
   return results
 
 def CheckChangeOnUpload(input_api, output_api):
diff --git a/infra/config/global/PRESUBMIT.py b/infra/config/global/PRESUBMIT.py
index 796181e2..4dcd129 100644
--- a/infra/config/global/PRESUBMIT.py
+++ b/infra/config/global/PRESUBMIT.py
@@ -9,20 +9,29 @@
 """
 
 
-def _CheckLintLuciMiloCfg(input_api, output_api):
+def _CheckLuciMiloCfg(input_api, output_api):
   if ('infra/config/global/luci-milo.cfg' not in input_api.LocalPaths() and
       'infra/config/global/lint-luci-milo.py' not in input_api.LocalPaths()):
     return []
-  return input_api.RunTests([input_api.Command(
-      name='lint-luci-milo',
-      cmd=[input_api.python_executable, 'lint-luci-milo.py'],
-      kwargs={},
-      message=output_api.PresubmitError)])
 
+  return input_api.RunTests([
+      input_api.Command(
+          name='lint-luci-milo',
+          cmd=[input_api.python_executable, 'lint-luci-milo.py'],
+          kwargs={},
+          message=output_api.PresubmitError),
+      # Technically doesn't rely on lint-luci-milo.py, but is a lightweight
+      # enough check it should be fine to trigger.
+      input_api.Command(
+        name='testing/buildbot config checks',
+        cmd=[input_api.python_executable, input_api.os_path.join(
+                '..', '..', 'testing', 'buildbot',
+                'generate_buildbot_json.py',),
+            '--check'],
+        kwargs={}, message=output_api.PresubmitError)])
 
 def CheckChangeOnUpload(input_api, output_api):
-  return _CheckLintLuciMiloCfg(input_api, output_api)
-
+  return _CheckLuciMiloCfg(input_api, output_api)
 
 def CheckChangeOnCommit(input_api, output_api):
-  return _CheckLintLuciMiloCfg(input_api, output_api)
+  return _CheckLuciMiloCfg(input_api, output_api)
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 7264136..e45e58a 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -3154,7 +3154,9 @@
     }
     builders { mixins: "linux-try" name: "fuchsia_arm64" }
     builders { mixins: "linux-try" name: "fuchsia-arm64-cast" }
+    builders { mixins: "linux-try" name: "fuchsia-fyi-arm64-rel" }
     builders { mixins: "linux-try" name: "fuchsia-fyi-x64-dbg" }
+    builders { mixins: "linux-try" name: "fuchsia-fyi-x64-rel" }
     builders { mixins: "linux-try" name: "fuchsia_x64" }
     builders { mixins: "linux-try" name: "fuchsia-x64-cast" }
     builders { mixins: "linux-try" name: "leak_detection_linux" }
@@ -3340,6 +3342,8 @@
       mixins: "win-try"
       mixins: "goma-j300"
       name: "win7_chromium_rel_ng"
+      # TODO(crbug.com/914104): Remove once pool has sufficient capacity
+      execution_timeout_secs: 16200  # 4.5h
     }
     builders {
       mixins: "win-try"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 0985f0ca..9dd8016 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -3447,6 +3447,11 @@
     short_name: "bld"
   }
   builders {
+    name: "buildbucket/luci.chromium.webrtc/WebRTC Chromium Linux Builder (RBE)"
+    category: "linux"
+    short_name: "rbe"
+  }
+  builders {
     name: "buildbucket/luci.chromium.webrtc/WebRTC Chromium Linux Tester"
     category: "linux"
     short_name: "tst"
@@ -3521,11 +3526,21 @@
     short_name: "bld"
   }
   builders {
+    name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Builder (dbg) (RBE)"
+    category: "linux|debug"
+    short_name: "rbe"
+  }
+  builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Builder"
     category: "linux|release"
     short_name: "bld"
   }
   builders {
+    name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Builder (RBE)"
+    category: "linux|release"
+    short_name: "rbe"
+  }
+  builders {
     name: "buildbucket/luci.chromium.webrtc.fyi/WebRTC Chromium FYI Linux Tester"
     category: "linux|release"
     short_name: "tst"
@@ -3939,9 +3954,15 @@
     name: "buildbucket/luci.chromium.try/fuchsia-arm64-cast"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/fuchsia-fyi-arm64-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/fuchsia-fyi-x64-dbg"
   }
   builders {
+    name: "buildbucket/luci.chromium.try/fuchsia-fyi-x64-rel"
+  }
+  builders {
     name: "buildbucket/luci.chromium.try/fuchsia_x64"
   }
   builders {
diff --git a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
index c6acf36..4433005 100644
--- a/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
+++ b/ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.cc
@@ -28,8 +28,6 @@
 
   init_params.identity_manager =
       IdentityManagerFactory::GetForBrowserState(browser_state);
-  init_params.signin_scoped_device_id_callback =
-      base::BindRepeating([]() { return std::string(); });
   init_params.start_behavior = browser_sync::ProfileSyncService::MANUAL_START;
   init_params.sync_client =
       sync_client ? std::move(sync_client)
@@ -40,7 +38,9 @@
   init_params.local_device_info_provider =
       std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
           ::GetChannel(), ::GetVersionString(),
-          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET);
+          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET,
+          /*signin_scoped_device_id_callback=*/
+          base::BindRepeating([]() { return std::string(); }));
 
   return init_params;
 }
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index 42c06cf..22fcccf1 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -143,8 +143,6 @@
   ProfileSyncService::InitParams init_params;
   init_params.identity_manager =
       IdentityManagerFactory::GetForBrowserState(browser_state);
-  init_params.signin_scoped_device_id_callback = base::BindRepeating(
-      &signin::GetSigninScopedDeviceId, browser_state->GetPrefs());
   init_params.start_behavior = ProfileSyncService::MANUAL_START;
   init_params.sync_client =
       std::make_unique<IOSChromeSyncClient>(browser_state);
@@ -156,7 +154,10 @@
   init_params.local_device_info_provider =
       std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
           ::GetChannel(), ::GetVersionString(),
-          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET);
+          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET,
+          /*signin_scoped_device_id_callback=*/
+          base::BindRepeating(&signin::GetSigninScopedDeviceId,
+                              browser_state->GetPrefs()));
 
   bool use_fcm_invalidations =
       base::FeatureList::IsEnabled(invalidation::switches::kFCMInvalidations);
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 7da9a84c..24294363 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -373,6 +373,7 @@
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/voice",
     "//ios/chrome/browser/upgrade",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/voice:voice",
     "//ios/chrome/browser/web",
     "//ios/chrome/browser/web:tab_helper_delegates",
diff --git a/ios/chrome/browser/ui/activity_services/activity_service_controller.mm b/ios/chrome/browser/ui/activity_services/activity_service_controller.mm
index 9e68e4f..abc4a66 100644
--- a/ios/chrome/browser/ui/activity_services/activity_service_controller.mm
+++ b/ios/chrome/browser/ui/activity_services/activity_service_controller.mm
@@ -8,6 +8,8 @@
 
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #import "ios/chrome/browser/passwords/password_form_filler.h"
@@ -416,6 +418,8 @@
                    message:IDS_IOS_SHARE_TO_SIGN_IN_ERROR_ALERT];
       break;
     case ShareTo::SHARE_CANCEL:
+      base::RecordAction(base::UserMetricsAction("MobileShareMenuCancel"));
+      break;
     case ShareTo::SHARE_UNKNOWN_RESULT:
       break;
   }
diff --git a/ios/chrome/browser/ui/activity_services/activity_type_util.mm b/ios/chrome/browser/ui/activity_services/activity_type_util.mm
index d38aa59..bfb92c9b 100644
--- a/ios/chrome/browser/ui/activity_services/activity_type_util.mm
+++ b/ios/chrome/browser/ui/activity_services/activity_type_util.mm
@@ -88,7 +88,6 @@
     {GOOGLE_GOOGLEPLUS, @"com.google.GooglePlus.", false},
     {GOOGLE_HANGOUTS, @"com.google.hangouts.", false},
     {GOOGLE_INBOX, @"com.google.inbox.", false},
-    {GOOGLE_UNKNOWN, @"com.google.", false},
     {READ_LATER, @"com.google.chrome.readingListActivity", true},
     {REQUEST_DESKTOP_MOBILE_SITE,
      @"com.google.chrome.requestDesktopOrMobileSiteActivity", true},
@@ -104,7 +103,11 @@
     {THIRD_PARTY_PINTEREST, @"pinterest.", false},
     {THIRD_PARTY_POCKET, @"com.ideashower.ReadItLaterPro.", false},
     {THIRD_PARTY_READABILITY, @"com.readability.ReadabilityMobile.", false},
-    {THIRD_PARTY_INSTAPAPER, @"com.marcoarment.instapaperpro.", false}};
+    {THIRD_PARTY_INSTAPAPER, @"com.marcoarment.instapaperpro.", false},
+    // Put Google Unknown at the end to make sure it doesn't prevent anything
+    // else from being recorded.
+    {GOOGLE_UNKNOWN, @"com.google.", false},
+};
 
 ActivityType TypeFromString(NSString* activityString) {
   DCHECK(activityString);
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 468bceac..7c16ccb 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -95,6 +95,8 @@
     "//ios/chrome/browser/ui/table_view:styler",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/undo",
+    "//ios/chrome/browser/url_loading",
+    "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common/favicon",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/ui",
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
index 45ba00a..efdf3870 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_H_
+#ifndef IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_HOME_VIEW_CONTROLLER_H_
+#define IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_HOME_VIEW_CONTROLLER_H_
 
 #import <UIKit/UIKit.h>
 
@@ -13,18 +13,16 @@
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 
 @protocol ApplicationCommands;
-@protocol UrlLoader;
-class GURL;
-
-namespace ios {
-class ChromeBrowserState;
-}  // namespace ios
-
+@class BookmarkHomeViewController;
 namespace bookmarks {
 class BookmarkNode;
 }  // namespace bookmarks
-
-@class BookmarkHomeViewController;
+class GURL;
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+@protocol UrlLoader;
+class WebStateList;
 
 @protocol BookmarkHomeViewControllerDelegate
 // The view controller wants to be dismissed. If |urls| is not empty, then
@@ -55,6 +53,7 @@
 - (instancetype)initWithLoader:(id<UrlLoader>)loader
                   browserState:(ios::ChromeBrowserState*)browserState
                     dispatcher:(id<ApplicationCommands>)dispatcher
+                  webStateList:(WebStateList*)webStateList
     NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithTableViewStyle:(UITableViewStyle)tableViewStyle
                            appBarStyle:
@@ -73,4 +72,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_HOME_VIEW_CONTROLLER_H_
+#endif  // IOS_CHROME_BROWSER_UI_BOOKMARKS_BOOKMARK_HOME_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index 7393d86..0f23b2c 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -190,31 +190,12 @@
 @property(nonatomic, strong)
     BookmarkInteractionController* bookmarkInteractionController;
 
+@property(nonatomic, assign) WebStateList* webStateList;
+
 @end
 
 @implementation BookmarkHomeViewController
 
-@synthesize bookmarks = _bookmarks;
-@synthesize browserState = _browserState;
-@synthesize folderSelector = _folderSelector;
-@synthesize loader = _loader;
-@synthesize homeDelegate = _homeDelegate;
-@synthesize contextBarState = _contextBarState;
-@synthesize dispatcher = _dispatcher;
-@synthesize cachedIndexPathRow = _cachedIndexPathRow;
-@synthesize isReconstructingFromCache = _isReconstructingFromCache;
-@synthesize sharedState = _sharedState;
-@synthesize mediator = _mediator;
-@synthesize searchController = _searchController;
-@synthesize searchTerm = _searchTerm;
-@synthesize deleteButton = _deleteButton;
-@synthesize moreButton = _moreButton;
-@synthesize scrimView = _scrimView;
-@synthesize spinnerView = _spinnerView;
-@synthesize emptyTableBackgroundView = _emptyTableBackgroundView;
-@synthesize actionSheetCoordinator = _actionSheetCoordinator;
-@synthesize bookmarkInteractionController = _bookmarkInteractionController;
-
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
@@ -223,7 +204,8 @@
 
 - (instancetype)initWithLoader:(id<UrlLoader>)loader
                   browserState:(ios::ChromeBrowserState*)browserState
-                    dispatcher:(id<ApplicationCommands>)dispatcher {
+                    dispatcher:(id<ApplicationCommands>)dispatcher
+                  webStateList:(WebStateList*)webStateList {
   DCHECK(browserState);
   self = [super initWithTableViewStyle:UITableViewStylePlain
                            appBarStyle:ChromeTableViewControllerStyleNoAppBar];
@@ -231,6 +213,7 @@
     _browserState = browserState->GetOriginalChromeBrowserState();
     _loader = loader;
     _dispatcher = dispatcher;
+    _webStateList = webStateList;
 
     _faviconLoader =
         IOSChromeFaviconLoaderFactory::GetForBrowserState(_browserState);
@@ -663,7 +646,8 @@
         initWithBrowserState:self.browserState
                       loader:self.loader
             parentController:self
-                  dispatcher:self.dispatcher];
+                  dispatcher:self.dispatcher
+                webStateList:self.webStateList];
     self.bookmarkInteractionController.delegate = self;
   }
 
@@ -1126,7 +1110,8 @@
   BookmarkHomeViewController* controller =
       [[BookmarkHomeViewController alloc] initWithLoader:_loader
                                             browserState:self.browserState
-                                              dispatcher:self.dispatcher];
+                                              dispatcher:self.dispatcher
+                                            webStateList:self.webStateList];
   [controller setRootNode:folder];
   controller.homeDelegate = self.homeDelegate;
   return controller;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
index ae6f27ac..b2ed35b 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller_unittest.mm
@@ -23,7 +23,8 @@
     BookmarkHomeViewController* controller = [[BookmarkHomeViewController alloc]
         initWithLoader:nil
           browserState:chrome_browser_state_.get()
-            dispatcher:nil];
+            dispatcher:nil
+          webStateList:nullptr];
 
     [controller setRootNode:_bookmarkModel->mobile_node()];
     // Two sections: Messages and Bookmarks.
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
index d74f779..4d760964 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.h
@@ -17,7 +17,9 @@
 
 namespace ios {
 class ChromeBrowserState;
-}  // namespace ios
+}
+
+class WebStateList;
 
 // The BookmarkInteractionController abstracts the management of the various
 // UIViewControllers used to create, remove and edit a bookmark.
@@ -30,6 +32,7 @@
                               loader:(id<UrlLoader>)loader
                     parentController:(UIViewController*)parentController
                           dispatcher:(id<ApplicationCommands>)dispatcher
+                        webStateList:(WebStateList*)webStateList
     NS_DESIGNATED_INITIALIZER;
 - (instancetype)init NS_UNAVAILABLE;
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index c2a7a7c..9d79d5c 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -10,7 +10,6 @@
 #include "base/mac/foundation_util.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
-#include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "components/bookmarks/browser/bookmark_model.h"
@@ -37,6 +36,8 @@
 #import "ios/chrome/browser/ui/table_view/table_view_presentation_controller_delegate.h"
 #include "ios/chrome/browser/ui/url_loader.h"
 #include "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/url_loading/url_loading_util.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/third_party/material_components_ios/src/components/Snackbar/src/MaterialSnackbar.h"
 #import "ios/web/public/navigation_manager.h"
@@ -79,6 +80,9 @@
 
   // The parent controller on top of which the UI needs to be presented.
   __weak UIViewController* _parentController;
+
+  // The web state list currently in use.
+  WebStateList* _webStateList;
 }
 
 // The type of view controller that is being presented.
@@ -153,7 +157,8 @@
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState
                               loader:(id<UrlLoader>)loader
                     parentController:(UIViewController*)parentController
-                          dispatcher:(id<ApplicationCommands>)dispatcher {
+                          dispatcher:(id<ApplicationCommands>)dispatcher
+                        webStateList:(WebStateList*)webStateList {
   self = [super init];
   if (self) {
     // Bookmarks are always opened with the main browser state, even in
@@ -163,6 +168,7 @@
     _loader = loader;
     _parentController = parentController;
     _dispatcher = dispatcher;
+    _webStateList = webStateList;
     _bookmarkModel =
         ios::BookmarkModelFactory::GetForBrowserState(_browserState);
     _mediator = [[BookmarkMediator alloc] initWithBrowserState:_browserState];
@@ -220,7 +226,8 @@
   self.bookmarkBrowser =
       [[BookmarkHomeViewController alloc] initWithLoader:_loader
                                             browserState:_currentBrowserState
-                                              dispatcher:self.dispatcher];
+                                              dispatcher:self.dispatcher
+                                            webStateList:_webStateList];
   self.bookmarkBrowser.homeDelegate = self;
 
   NSArray<BookmarkHomeViewController*>* replacementViewControllers = nil;
@@ -532,10 +539,8 @@
 }
 
 - (void)openURLInCurrentTab:(const GURL&)url {
-  if (url.SchemeIs(url::kJavaScriptScheme)) {  // bookmarklet
-    NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
-        stringByRemovingPercentEncoding];
-    [_loader loadJavaScriptFromLocationBar:jsToEval];
+  if (url.SchemeIs(url::kJavaScriptScheme) && _webStateList) {  // bookmarklet
+    LoadJavaScriptURL(url, _browserState, _webStateList->GetActiveWebState());
     return;
   }
   web::NavigationManager::WebLoadParams params(url);
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index f071f3c4..f8fb2f4b7 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -200,6 +200,7 @@
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h"
 #import "ios/chrome/browser/ui/voice/text_to_speech_playback_controller_factory.h"
 #include "ios/chrome/browser/upgrade/upgrade_center.h"
+#import "ios/chrome/browser/url_loading/url_loading_util.h"
 #import "ios/chrome/browser/voice/voice_search_navigations_tab_helper.h"
 #import "ios/chrome/browser/web/blocked_popup_tab_helper.h"
 #import "ios/chrome/browser/web/image_fetch_tab_helper.h"
@@ -1228,9 +1229,8 @@
   // existing snapshot for the tab. This can happen when a new regular tab is
   // opened from an incognito tab. A different BVC is displayed, which may not
   // have enough time to finish appearing before a snapshot is requested.
-  Tab* currentTab = self.tabModel.currentTab;
-  if (currentTab && self.viewVisible) {
-    SnapshotTabHelper::FromWebState(currentTab.webState)->UpdateSnapshot();
+  if (self.currentWebState && self.viewVisible) {
+    SnapshotTabHelper::FromWebState(self.currentWebState)->UpdateSnapshot();
   }
 
   [self.tabModel insertTabWithLoadParams:CreateWebLoadParams(
@@ -1328,13 +1328,13 @@
   if (active) {
     // Make sure the tab (if any; it's possible to get here without a current
     // tab if the caller is about to create one) ends up on screen completely.
-    Tab* currentTab = [self.tabModel currentTab];
     // Force loading the view in case it was not loaded yet.
     [self loadViewIfNeeded];
-    if (currentTab && _expectingForegroundTab) {
-      PagePlaceholderTabHelper::FromWebState(currentTab.webState)
+    if (self.currentWebState && _expectingForegroundTab) {
+      PagePlaceholderTabHelper::FromWebState(self.currentWebState)
           ->AddPlaceholderForNextNavigation();
     }
+    Tab* currentTab = self.tabModel.currentTab;
     if (currentTab)
       [self displayTab:currentTab];
   } else {
@@ -1359,16 +1359,16 @@
   if (_voiceSearchController)
     _voiceSearchController->DismissMicPermissionsHelp();
 
-  Tab* currentTab = self.tabModel.currentTab;
-  [currentTab dismissModals];
+  web::WebState* webState = self.currentWebState;
+  [self.tabModel.currentTab dismissModals];
 
-  if (currentTab) {
+  if (webState) {
     NewTabPageTabHelper* NTPHelper =
-        NewTabPageTabHelper::FromWebState(currentTab.webState);
+        NewTabPageTabHelper::FromWebState(webState);
     if (NTPHelper && NTPHelper->IsActive()) {
-      [_ntpCoordinatorsForWebStates[currentTab.webState] dismissModals];
+      [_ntpCoordinatorsForWebStates[webState] dismissModals];
     }
-    auto* findHelper = FindTabHelper::FromWebState(currentTab.webState);
+    auto* findHelper = FindTabHelper::FromWebState(webState);
     if (findHelper) {
       findHelper->StopFinding(^{
         [self updateFindBar:NO shouldFocus:NO];
@@ -1501,9 +1501,8 @@
   // If there is no first responder, try to make the webview the first
   // responder.
   if (!GetFirstResponder()) {
-    web::WebState* webState = self.tabModel.currentTab.webState;
-    if (webState)
-      [webState->GetWebViewProxy() becomeFirstResponder];
+    if (self.currentWebState)
+      [self.currentWebState->GetWebViewProxy() becomeFirstResponder];
   }
 
   return YES;
@@ -2274,7 +2273,7 @@
                     browserState:_browserState
                       dispatcher:self.dispatcher];
   [_paymentRequestManager setLocationBarModel:_locationBarModel.get()];
-  [_paymentRequestManager setActiveWebState:self.tabModel.currentTab.webState];
+  [_paymentRequestManager setActiveWebState:self.currentWebState];
 }
 
 // Set the frame for the various views. View must be loaded.
@@ -2451,7 +2450,8 @@
       initWithBrowserState:_browserState
                     loader:self
           parentController:self
-                dispatcher:self.dispatcher];
+                dispatcher:self.dispatcher
+              webStateList:self.tabModel.webStateList];
 }
 
 - (void)setOverScrollActionControllerToStaticNativeContent:
@@ -2718,10 +2718,10 @@
   // TODO(crbug.com/731045): This early return temporarily replaces a DCHECK.
   // For unknown reasons, this DCHECK sometimes was hit in the wild, resulting
   // in a crash.
-  if (!self.tabModel.currentTab) {
+  if (!self.currentWebState) {
     return;
   }
-  auto* helper = FindTabHelper::FromWebState(self.tabModel.currentTab.webState);
+  auto* helper = FindTabHelper::FromWebState(self.currentWebState);
   if (helper && helper->IsFindUIActive()) {
     if (initialUpdate && !_isOffTheRecord) {
       helper->RestoreSearchTerm();
@@ -3136,12 +3136,11 @@
     // cause both snapshot and real infobars to appear at the same time.
     return nil;
   }
-  Tab* currentTab = self.tabModel.currentTab;
-  if (currentTab && tab == currentTab) {
-    DCHECK(currentTab.webState);
+  if (tab && self.tabModel.currentTab == tab) {
+    DCHECK(self.currentWebState);
     DCHECK(self.infobarContainerCoordinator);
     if ([self.infobarContainerCoordinator
-            isInfobarPresentingForWebState:currentTab.webState]) {
+            isInfobarPresentingForWebState:self.currentWebState]) {
       return [self.infobarContainerCoordinator view];
     }
   }
@@ -3295,7 +3294,7 @@
     handleContextMenu:(const web::ContextMenuParams&)params {
   // Prevent context menu from displaying for a tab which is no longer the
   // current one.
-  if (webState != self.tabModel.currentTab.webState) {
+  if (webState != self.currentWebState) {
     return;
   }
 
@@ -3528,9 +3527,9 @@
 - (void)openJavascript:(NSString*)javascript {
   DCHECK(javascript);
   javascript = [javascript stringByRemovingPercentEncoding];
-  web::WebState* webState = self.tabModel.currentTab.webState;
-  if (webState) {
-    webState->ExecuteJavaScript(base::SysNSStringToUTF16(javascript));
+  if (self.currentWebState) {
+    self.currentWebState->ExecuteJavaScript(
+        base::SysNSStringToUTF16(javascript));
   }
 }
 
@@ -3690,7 +3689,7 @@
   }
   if (host == kChromeUIExternalFileHost) {
     id<CRWNativeContent> controller =
-        [self controllerForURL:url webState:self.tabModel.currentTab.webState];
+        [self controllerForURL:url webState:self.currentWebState];
     return controller ? YES : NO;
   }
 
@@ -3770,8 +3769,8 @@
   // TODO(crbug.com/498568): To reduce complexity here, refactor the flow so
   // that native controllers vended here always correspond to the current tab.
   Tab* currentTab = self.tabModel.currentTab;
-  if (!currentTab.webState ||
-      currentTab.webState->GetLastCommittedURL() != url ||
+  if (!self.currentWebState ||
+      self.currentWebState->GetLastCommittedURL() != url ||
       [currentTab.webController.nativeController
           isKindOfClass:[nativeController class]]) {
     _temporaryNativeController = nativeController;
@@ -4034,12 +4033,11 @@
 }
 
 - (BOOL)isFindInPageAvailable {
-  Tab* tab = self.tabModel.currentTab;
-  if (!tab) {
+  if (!self.currentWebState) {
     return NO;
   }
 
-  auto* helper = FindTabHelper::FromWebState(tab.webState);
+  auto* helper = FindTabHelper::FromWebState(self.currentWebState);
   return (helper && helper->CurrentPageSupportsFindInPage());
 }
 
@@ -4124,10 +4122,9 @@
   [_bookmarkInteractionController dismissBookmarkModalControllerAnimated:YES];
   if (params.transition_type & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) {
     BOOL isExpectingVoiceSearch = NO;
-    web::WebState* webState = self.tabModel.currentTab.webState;
-    if (webState) {
+    if (self.currentWebState) {
       isExpectingVoiceSearch =
-          VoiceSearchNavigationTabHelper::FromWebState(webState)
+          VoiceSearchNavigationTabHelper::FromWebState(self.currentWebState)
               ->IsExpectingVoiceSearch();
     }
     new_tab_page_uma::RecordActionFromOmnibox(_browserState, params.url,
@@ -4220,7 +4217,7 @@
   }
 
   if (typed_or_generated_transition) {
-    LoadTimingTabHelper::FromWebState(self.tabModel.currentTab.webState)
+    LoadTimingTabHelper::FromWebState(self.currentWebState)
         ->DidInitiatePageLoad();
   }
 
@@ -4242,27 +4239,15 @@
   // calling -LoadURLWithParams.  Otherwise, if the webState has never been
   // visible (such as during startup with an NTP), it's possible the webView can
   // trigger a unnecessary load for chrome://newtab.
-  web::WebState* webState = self.tabModel.currentTab.webState;
-  if (webState && params.url.GetOrigin() != kChromeUINewTabURL) {
+  if (self.currentWebState && params.url.GetOrigin() != kChromeUINewTabURL) {
     NewTabPageTabHelper* NTPHelper =
-        NewTabPageTabHelper::FromWebState(webState);
+        NewTabPageTabHelper::FromWebState(self.currentWebState);
     if (NTPHelper && NTPHelper->IsActive()) {
       NTPHelper->Deactivate();
     }
   }
 }
 
-- (void)loadJavaScriptFromLocationBar:(NSString*)script {
-  PrerenderService* prerenderService =
-      PrerenderServiceFactory::GetForBrowserState(self.browserState);
-  if (prerenderService) {
-    prerenderService->CancelPrerender();
-  }
-  DCHECK(self.tabModel.currentTab);
-  if (self.currentWebState)
-    self.currentWebState->ExecuteUserJavaScript(script);
-}
-
 - (void)webPageOrderedOpen:(OpenNewTabCommand*)command {
   // Send either the "New Tab Opened" or "New Incognito Tab" opened to the
   // feature_engagement::Tracker based on |inIncognito|.
@@ -4348,8 +4333,7 @@
                     object:nil];
   [self.sideSwipeController setEnabled:NO];
 
-  web::WebState* webState = self.tabModel.currentTab.webState;
-  if (!IsVisibleURLNewTabPage(webState)) {
+  if (!IsVisibleURLNewTabPage(self.currentWebState)) {
     // Tapping on web content area should dismiss the keyboard. Tapping on NTP
     // gesture should propagate to NTP view.
     [self.view insertSubview:self.typingShield aboveSubview:self.contentArea];
@@ -4393,7 +4377,7 @@
   if (_locationBarEditCancelledLoad) {
     _locationBarEditCancelledLoad = NO;
 
-    web::WebState* webState = self.tabModel.currentTab.webState;
+    web::WebState* webState = self.currentWebState;
     if (webState && ![self.helper isToolbarLoading:webState])
       webState->GetNavigationManager()->Reload(web::ReloadType::NORMAL,
                                                false /* check_for_repost */);
@@ -4425,16 +4409,15 @@
 }
 
 - (void)stopLoading {
-  self.tabModel.currentTab.webState->Stop();
+  self.currentWebState->Stop();
 }
 
 - (void)reload {
-  web::WebState* webState = self.tabModel.currentTab.webState;
-  if (webState) {
+  if (self.currentWebState) {
     // |check_for_repost| is true because the reload is explicitly initiated
     // by the user.
-    webState->GetNavigationManager()->Reload(web::ReloadType::NORMAL,
-                                             true /* check_for_repost */);
+    self.currentWebState->GetNavigationManager()->Reload(
+        web::ReloadType::NORMAL, true /* check_for_repost */);
   }
 }
 
@@ -4511,17 +4494,16 @@
 
 - (void)closeFindInPage {
   __weak BrowserViewController* weakSelf = self;
-  Tab* currentTab = self.tabModel.currentTab;
-  if (currentTab) {
-    FindTabHelper::FromWebState(currentTab.webState)->StopFinding(^{
+  if (self.currentWebState) {
+    FindTabHelper::FromWebState(self.currentWebState)->StopFinding(^{
       [weakSelf updateFindBar:NO shouldFocus:NO];
     });
   }
 }
 
 - (void)searchFindInPage {
-  DCHECK(self.tabModel.currentTab);
-  auto* helper = FindTabHelper::FromWebState(self.tabModel.currentTab.webState);
+  DCHECK(self.currentWebState);
+  auto* helper = FindTabHelper::FromWebState(self.currentWebState);
   __weak BrowserViewController* weakSelf = self;
   helper->StartFinding(
       [_findBarController searchTerm], ^(FindInPageModel* model) {
@@ -4537,20 +4519,18 @@
 }
 
 - (void)findNextStringInPage {
-  Tab* currentTab = self.tabModel.currentTab;
-  DCHECK(currentTab);
+  DCHECK(self.currentWebState);
   // TODO(crbug.com/603524): Reshow find bar if necessary.
-  FindTabHelper::FromWebState(currentTab.webState)
+  FindTabHelper::FromWebState(self.currentWebState)
       ->ContinueFinding(FindTabHelper::FORWARD, ^(FindInPageModel* model) {
         [_findBarController updateResultsCount:model];
       });
 }
 
 - (void)findPreviousStringInPage {
-  Tab* currentTab = self.tabModel.currentTab;
-  DCHECK(currentTab);
+  DCHECK(self.currentWebState);
   // TODO(crbug.com/603524): Reshow find bar if necessary.
-  FindTabHelper::FromWebState(currentTab.webState)
+  FindTabHelper::FromWebState(self.currentWebState)
       ->ContinueFinding(FindTabHelper::REVERSE, ^(FindInPageModel* model) {
         [_findBarController updateResultsCount:model];
       });
@@ -4590,7 +4570,7 @@
   // iPad.
   UIImageView* exitingPage = [self pageOpenCloseAnimationView];
   exitingPage.image =
-      SnapshotTabHelper::FromWebState(currentTab.webState)->UpdateSnapshot();
+      SnapshotTabHelper::FromWebState(self.currentWebState)->UpdateSnapshot();
 
   // Close the actual tab, and add its image as a subview.
   [self.tabModel closeTabAtIndex:tabIndex];
@@ -4641,7 +4621,7 @@
 - (void)reloadWithUserAgentType:(web::UserAgentType)userAgentType {
   if (self.userAgentType == userAgentType)
     return;
-  web::WebState* webState = self.tabModel.currentTab.webState;
+  web::WebState* webState = self.currentWebState;
   web::NavigationManager* navigationManager = webState->GetNavigationManager();
   navigationManager->ReloadWithUserAgentType(userAgentType);
 }
@@ -4978,7 +4958,7 @@
   [[self.infobarContainerCoordinator view] setHidden:NO];
 
   if (base::FeatureList::IsEnabled(kPresentSadTabInViewController)) {
-    web::WebState* webState = self.tabModel.currentTab.webState;
+    web::WebState* webState = self.currentWebState;
     if (webState && webState->IsVisible()) {
       // Side swipe did not change the tab represented by |webState|.
       SadTabTabHelper* sadTabHelper = SadTabTabHelper::FromWebState(webState);
@@ -5200,7 +5180,7 @@
 #pragma mark - WebStatePrinter
 
 - (void)printWebState:(web::WebState*)webState {
-  if (webState == self.tabModel.currentTab.webState)
+  if (webState == self.currentWebState)
     [self.dispatcher printTab];
 }
 
@@ -5287,7 +5267,6 @@
 
 - (void)newTabPageHelperDidChangeVisibility:(NewTabPageTabHelper*)NTPHelper
                                 forWebState:(web::WebState*)webState {
-  Tab* currentTab = self.tabModel.currentTab;
   if (NTPHelper->IsActive()) {
     DCHECK(!_ntpCoordinatorsForWebStates[webState]);
     NewTabPageCoordinator* newTabPageCoordinator =
@@ -5301,8 +5280,8 @@
     DCHECK(_ntpCoordinatorsForWebStates[webState]);
     _ntpCoordinatorsForWebStates.erase(webState);
   }
-  if (self.active && currentTab.webState == webState) {
-    [self displayTab:currentTab];
+  if (self.active && self.currentWebState == webState) {
+    [self displayTab:self.tabModel.currentTab];
   }
 }
 
diff --git a/ios/chrome/browser/ui/location_bar/BUILD.gn b/ios/chrome/browser/ui/location_bar/BUILD.gn
index ab961250..81ee66d3 100644
--- a/ios/chrome/browser/ui/location_bar/BUILD.gn
+++ b/ios/chrome/browser/ui/location_bar/BUILD.gn
@@ -56,6 +56,7 @@
     "//ios/chrome/browser/ui/toolbar/public:feature_flags",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/voice",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common:timing",
     "//ios/public/provider/chrome/browser:browser",
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
index 4d27becb..0d5d4928 100644
--- a/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
+++ b/ios/chrome/browser/ui/location_bar/location_bar_coordinator.mm
@@ -37,6 +37,7 @@
 #import "ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h"
 #import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/chrome/browser/ui/util/pasteboard_util.h"
+#import "ios/chrome/browser/url_loading/url_loading_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
@@ -226,10 +227,8 @@
                      transition:(ui::PageTransition)transition
                     disposition:(WindowOpenDisposition)disposition {
   if (url.SchemeIs(url::kJavaScriptScheme)) {
-    // Evaluate the URL as JavaScript if its scheme is JavaScript.
-    NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
-        stringByRemovingPercentEncoding];
-    [self.URLLoader loadJavaScriptFromLocationBar:jsToEval];
+    LoadJavaScriptURL(url, self.browserState,
+                      self.webStateList->GetActiveWebState());
   } else {
     // When opening a URL, force the omnibox to resign first responder.  This
     // will also close the popup.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm
index e23f68c..3200257 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_url_loader.mm
@@ -118,8 +118,4 @@
                                    WindowOpenDisposition::NEW_FOREGROUND_TAB);
 }
 
-- (void)loadJavaScriptFromLocationBar:(NSString*)script {
-  NOTREACHED() << "This is intentionally NO-OP in TabGridURLLoader.";
-}
-
 @end
diff --git a/ios/chrome/browser/ui/url_loader.h b/ios/chrome/browser/ui/url_loader.h
index f74717f2..17392626 100644
--- a/ios/chrome/browser/ui/url_loader.h
+++ b/ios/chrome/browser/ui/url_loader.h
@@ -38,9 +38,6 @@
 // Restores a closed tab with |sessionID|.
 - (void)restoreTabWithSessionID:(const SessionID)sessionID;
 
-// Loads the text entered in the location bar as javascript.
-- (void)loadJavaScriptFromLocationBar:(NSString*)script;
-
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_URL_LOADER_H_
diff --git a/ios/chrome/browser/url_loading/BUILD.gn b/ios/chrome/browser/url_loading/BUILD.gn
new file mode 100644
index 0000000..5418c47
--- /dev/null
+++ b/ios/chrome/browser/url_loading/BUILD.gn
@@ -0,0 +1,17 @@
+# 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.
+
+source_set("url_loading") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  sources = [
+    "url_loading_util.h",
+    "url_loading_util.mm",
+  ]
+  deps = [
+    "//base",
+    "//ios/chrome/browser/prerender",
+    "//ios/web/public",
+    "//url",
+  ]
+}
diff --git a/ios/chrome/browser/url_loading/url_loading_util.h b/ios/chrome/browser/url_loading/url_loading_util.h
new file mode 100644
index 0000000..cc9f752
--- /dev/null
+++ b/ios/chrome/browser/url_loading/url_loading_util.h
@@ -0,0 +1,25 @@
+// 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 IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_UTIL_H_
+#define IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_UTIL_H_
+
+#import <Foundation/Foundation.h>
+
+class GURL;
+namespace ios {
+class ChromeBrowserState;
+}
+namespace web {
+class WebState;
+}
+
+// Loads |url| in |webState|, performing any necessary updates to
+// |browserState|. It is an error to pass a value of GURL that doesn't have a
+// javascript: scheme.
+void LoadJavaScriptURL(const GURL& url,
+                       ios::ChromeBrowserState* browserState,
+                       web::WebState* webState);
+
+#endif  // IOS_CHROME_BROWSER_URL_LOADING_URL_LOADING_UTIL_H_
diff --git a/ios/chrome/browser/url_loading/url_loading_util.mm b/ios/chrome/browser/url_loading/url_loading_util.mm
new file mode 100644
index 0000000..40a864f
--- /dev/null
+++ b/ios/chrome/browser/url_loading/url_loading_util.mm
@@ -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.
+
+#import "ios/chrome/browser/url_loading/url_loading_util.h"
+
+#include "base/strings/sys_string_conversions.h"
+#import "ios/chrome/browser/prerender/prerender_service.h"
+#import "ios/chrome/browser/prerender/prerender_service_factory.h"
+#import "ios/web/public/web_state/web_state.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+void LoadJavaScriptURL(const GURL& url,
+                       ios::ChromeBrowserState* browserState,
+                       web::WebState* webState) {
+  DCHECK(url.SchemeIs(url::kJavaScriptScheme));
+  DCHECK(webState);
+  PrerenderService* prerenderService =
+      PrerenderServiceFactory::GetForBrowserState(browserState);
+  if (prerenderService) {
+    prerenderService->CancelPrerender();
+  }
+  NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
+      stringByRemovingPercentEncoding];
+  if (webState)
+    webState->ExecuteUserJavaScript(jsToEval);
+}
diff --git a/ios/chrome/test/fakes/fake_url_loader.mm b/ios/chrome/test/fakes/fake_url_loader.mm
index c07a5ca..eeafceb 100644
--- a/ios/chrome/test/fakes/fake_url_loader.mm
+++ b/ios/chrome/test/fakes/fake_url_loader.mm
@@ -51,9 +51,6 @@
 - (void)restoreTabWithSessionID:(const SessionID)sessionID {
 }
 
-- (void)loadJavaScriptFromLocationBar:(NSString*)script {
-}
-
 - (const GURL&)url {
   return _url;
 }
diff --git a/ios/web/public/referrer_util_unittest.cc b/ios/web/public/referrer_util_unittest.cc
index 24260a8..2330ec80 100644
--- a/ios/web/public/referrer_util_unittest.cc
+++ b/ios/web/public/referrer_util_unittest.cc
@@ -233,9 +233,6 @@
       case net::URLRequest::NO_REFERRER:
         EXPECT_EQ(ReferrerPolicyNever, policy);
         break;
-      case net::URLRequest::MAX_REFERRER_POLICY:
-        FAIL();
-        break;
     }
   }
 }
diff --git a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
index bd6ca7e..0749f98e 100644
--- a/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
+++ b/ios/web_view/internal/sync/cwv_sync_controller_unittest.mm
@@ -75,8 +75,6 @@
     init_params.sync_client = std::make_unique<syncer::FakeSyncClient>();
     init_params.url_loader_factory = browser_state_.GetSharedURLLoaderFactory();
     init_params.network_time_update_callback = base::DoNothing();
-    init_params.signin_scoped_device_id_callback = base::BindRepeating(
-        &signin::GetSigninScopedDeviceId, browser_state_.GetPrefs());
     init_params.local_device_info_provider =
         std::make_unique<syncer::LocalDeviceInfoProviderMock>();
     profile_sync_service_ =
diff --git a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
index 5867b39..aa3e8834 100644
--- a/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
+++ b/ios/web_view/internal/sync/web_view_profile_sync_service_factory.mm
@@ -92,8 +92,6 @@
   init_params.url_loader_factory = browser_state->GetSharedURLLoaderFactory();
   // ios/web_view has no need to update network time.
   init_params.network_time_update_callback = base::DoNothing();
-  init_params.signin_scoped_device_id_callback = base::BindRepeating(
-      &signin::GetSigninScopedDeviceId, browser_state->GetPrefs());
   init_params.network_connection_tracker =
       ApplicationContext::GetInstance()->GetNetworkConnectionTracker();
   init_params.invalidations_identity_providers.push_back(
@@ -103,7 +101,10 @@
   init_params.local_device_info_provider =
       std::make_unique<syncer::LocalDeviceInfoProviderImpl>(
           version_info::Channel::UNKNOWN, version_info::GetVersionNumber(),
-          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET);
+          ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET,
+          /*signin_scoped_device_id_callback=*/
+          base::BindRepeating(&signin::GetSigninScopedDeviceId,
+                              browser_state->GetPrefs()));
 
   auto profile_sync_service =
       std::make_unique<ProfileSyncService>(std::move(init_params));
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc
index 5f82b1df..4a866067 100644
--- a/media/base/pipeline_impl.cc
+++ b/media/base/pipeline_impl.cc
@@ -188,7 +188,9 @@
   // Series of tasks to Start(), Seek(), and Resume().
   std::unique_ptr<SerialRunner> pending_callbacks_;
 
-  base::WeakPtr<RendererWrapper> weak_this_;
+  // Called from non-media threads when an error occurs.
+  PipelineStatusCB error_cb_;
+
   base::WeakPtrFactory<RendererWrapper> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(RendererWrapper);
 };
@@ -209,7 +211,6 @@
       renderer_ended_(false),
       text_renderer_ended_(false),
       weak_factory_(this) {
-  weak_this_ = weak_factory_.GetWeakPtr();
 }
 
 PipelineImpl::RendererWrapper::~RendererWrapper() {
@@ -248,26 +249,32 @@
   }
   weak_pipeline_ = weak_pipeline;
 
+  // Setup |error_cb_| on the media thread.
+  error_cb_ = base::BindRepeating(&RendererWrapper::OnPipelineError,
+                                  weak_factory_.GetWeakPtr());
+
   // Queue asynchronous actions required to start.
   DCHECK(!pending_callbacks_);
   SerialRunner::Queue fns;
 
   // Initialize demuxer.
-  fns.Push(base::Bind(&RendererWrapper::InitializeDemuxer, weak_this_));
+  fns.Push(base::BindRepeating(&RendererWrapper::InitializeDemuxer,
+                               weak_factory_.GetWeakPtr()));
 
   // Once the demuxer is initialized successfully, media metadata must be
   // available - report the metadata to client. If starting without a renderer
   // we'll complete initialization at this point.
-  fns.Push(
-      base::Bind(&RendererWrapper::ReportMetadata, weak_this_, start_type));
+  fns.Push(base::BindRepeating(&RendererWrapper::ReportMetadata,
+                               weak_factory_.GetWeakPtr(), start_type));
 
   // Initialize renderer.
-  fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_));
+  fns.Push(base::BindRepeating(&RendererWrapper::InitializeRenderer,
+                               weak_factory_.GetWeakPtr()));
 
   // Run tasks.
-  pending_callbacks_ =
-      SerialRunner::Run(fns, base::Bind(&RendererWrapper::CompleteSeek,
-                                        weak_this_, base::TimeDelta()));
+  pending_callbacks_ = SerialRunner::Run(
+      fns, base::BindRepeating(&RendererWrapper::CompleteSeek,
+                               weak_factory_.GetWeakPtr(), base::TimeDelta()));
 }
 
 void PipelineImpl::RendererWrapper::Stop() {
@@ -286,6 +293,7 @@
   // the pipeline is stopped before it had a chance to complete outstanding
   // tasks.
   pending_callbacks_.reset();
+  weak_factory_.InvalidateWeakPtrs();
 
   DestroyRenderer();
 
@@ -328,17 +336,18 @@
 
   // Flush.
   DCHECK(shared_state_.renderer);
-  bound_fns.Push(base::Bind(&Renderer::Flush,
-                            base::Unretained(shared_state_.renderer.get())));
+  bound_fns.Push(base::BindRepeating(
+      &Renderer::Flush, base::Unretained(shared_state_.renderer.get())));
 
   // Seek demuxer.
-  bound_fns.Push(
-      base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), seek_timestamp));
+  bound_fns.Push(base::BindRepeating(&Demuxer::Seek, base::Unretained(demuxer_),
+                                     seek_timestamp));
 
   // Run tasks.
   pending_callbacks_ = SerialRunner::Run(
       bound_fns,
-      base::Bind(&RendererWrapper::CompleteSeek, weak_this_, seek_timestamp));
+      base::BindRepeating(&RendererWrapper::CompleteSeek,
+                          weak_factory_.GetWeakPtr(), seek_timestamp));
 }
 
 void PipelineImpl::RendererWrapper::Suspend() {
@@ -369,7 +378,8 @@
 
   // No need to flush the renderer since it's going to be destroyed.
   pending_callbacks_ = SerialRunner::Run(
-      fns, base::Bind(&RendererWrapper::CompleteSuspend, weak_this_));
+      fns, base::BindRepeating(&RendererWrapper::CompleteSuspend,
+                               weak_factory_.GetWeakPtr()));
 }
 
 void PipelineImpl::RendererWrapper::Resume(std::unique_ptr<Renderer> renderer,
@@ -404,14 +414,15 @@
   // Queue the asynchronous actions required to start playback.
   SerialRunner::Queue fns;
 
-  fns.Push(
-      base::Bind(&Demuxer::Seek, base::Unretained(demuxer_), start_timestamp));
+  fns.Push(base::BindRepeating(&Demuxer::Seek, base::Unretained(demuxer_),
+                               start_timestamp));
 
-  fns.Push(base::Bind(&RendererWrapper::InitializeRenderer, weak_this_));
+  fns.Push(base::BindRepeating(&RendererWrapper::InitializeRenderer,
+                               weak_factory_.GetWeakPtr()));
 
   pending_callbacks_ = SerialRunner::Run(
-      fns,
-      base::Bind(&RendererWrapper::CompleteSeek, weak_this_, start_timestamp));
+      fns, base::BindRepeating(&RendererWrapper::CompleteSeek,
+                               weak_factory_.GetWeakPtr(), start_timestamp));
 }
 
 void PipelineImpl::RendererWrapper::SetPlaybackRate(double playback_rate) {
@@ -476,8 +487,9 @@
   }
 
   shared_state_.renderer->SetCdm(
-      cdm_context, base::Bind(&RendererWrapper::OnCdmAttached, weak_this_,
-                              cdm_attached_cb, cdm_context));
+      cdm_context, base::BindRepeating(&RendererWrapper::OnCdmAttached,
+                                       weak_factory_.GetWeakPtr(),
+                                       cdm_attached_cb, cdm_context));
 }
 
 void PipelineImpl::RendererWrapper::OnBufferedTimeRangesChanged(
@@ -499,24 +511,21 @@
       base::TimeDelta::FromDays(1), 50 /* bucket_count */);
 
   main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&PipelineImpl::OnDurationChange, weak_pipeline_, duration));
+      FROM_HERE, base::BindOnce(&PipelineImpl::OnDurationChange, weak_pipeline_,
+                                duration));
 }
 
 void PipelineImpl::RendererWrapper::OnDemuxerError(PipelineStatus error) {
   // TODO(alokp): Add thread DCHECK after ensuring that all Demuxer
   // implementations call DemuxerHost on the media thread.
-  media_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&RendererWrapper::OnPipelineError, weak_this_, error));
+  DCHECK(error_cb_);
+  media_task_runner_->PostTask(FROM_HERE, base::BindOnce(error_cb_, error));
 }
 
 void PipelineImpl::RendererWrapper::OnError(PipelineStatus error) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
-
-  media_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&RendererWrapper::OnPipelineError, weak_this_, error));
+  DCHECK(error_cb_);
+  media_task_runner_->PostTask(FROM_HERE, base::BindOnce(error_cb_, error));
 }
 
 void PipelineImpl::RendererWrapper::OnEnded() {
@@ -578,7 +587,8 @@
   demuxer_->OnEnabledAudioTracksChanged(
       enabled_track_ids, GetCurrentTimestamp(),
       base::BindOnce(&RendererWrapper::OnDemuxerCompletedTrackChange,
-                     weak_this_, base::Passed(&change_completed_cb)));
+                     weak_factory_.GetWeakPtr(),
+                     base::Passed(&change_completed_cb)));
 }
 
 void PipelineImpl::OnSelectedVideoTrackChanged(
@@ -617,7 +627,8 @@
   demuxer_->OnSelectedVideoTrackChanged(
       tracks, GetCurrentTimestamp(),
       base::BindOnce(&RendererWrapper::OnDemuxerCompletedTrackChange,
-                     weak_this_, base::Passed(&change_completed_cb)));
+                     weak_factory_.GetWeakPtr(),
+                     base::Passed(&change_completed_cb)));
 }
 
 void PipelineImpl::RendererWrapper::OnDemuxerCompletedTrackChange(
@@ -693,8 +704,8 @@
       old_key_frame_distance_average) {
     main_task_runner_->PostTask(
         FROM_HERE,
-        base::Bind(&PipelineImpl::OnVideoAverageKeyframeDistanceUpdate,
-                   weak_pipeline_));
+        base::BindOnce(&PipelineImpl::OnVideoAverageKeyframeDistanceUpdate,
+                       weak_pipeline_));
   }
 }
 
@@ -704,15 +715,16 @@
   DVLOG(2) << __func__ << "(" << state << ") ";
 
   main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&PipelineImpl::OnBufferingStateChange, weak_pipeline_, state));
+      FROM_HERE, base::BindOnce(&PipelineImpl::OnBufferingStateChange,
+                                weak_pipeline_, state));
 }
 
 void PipelineImpl::RendererWrapper::OnWaiting(WaitingReason reason) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
   main_task_runner_->PostTask(
-      FROM_HERE, base::Bind(&PipelineImpl::OnWaiting, weak_pipeline_, reason));
+      FROM_HERE,
+      base::BindOnce(&PipelineImpl::OnWaiting, weak_pipeline_, reason));
 }
 
 void PipelineImpl::RendererWrapper::OnVideoNaturalSizeChange(
@@ -728,26 +740,26 @@
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
   main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&PipelineImpl::OnVideoOpacityChange, weak_pipeline_, opaque));
+      FROM_HERE, base::BindOnce(&PipelineImpl::OnVideoOpacityChange,
+                                weak_pipeline_, opaque));
 }
 
 void PipelineImpl::RendererWrapper::OnAudioConfigChange(
     const AudioDecoderConfig& config) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&PipelineImpl::OnAudioConfigChange, weak_pipeline_, config));
+  main_task_runner_->PostTask(FROM_HERE,
+                              base::BindOnce(&PipelineImpl::OnAudioConfigChange,
+                                             weak_pipeline_, config));
 }
 
 void PipelineImpl::RendererWrapper::OnVideoConfigChange(
     const VideoDecoderConfig& config) {
   DCHECK(media_task_runner_->BelongsToCurrentThread());
 
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&PipelineImpl::OnVideoConfigChange, weak_pipeline_, config));
+  main_task_runner_->PostTask(FROM_HERE,
+                              base::BindOnce(&PipelineImpl::OnVideoConfigChange,
+                                             weak_pipeline_, config));
 }
 
 void PipelineImpl::RendererWrapper::OnDurationChange(base::TimeDelta duration) {
@@ -904,7 +916,7 @@
 
   if (cdm_context_) {
     shared_state_.renderer->SetCdm(cdm_context_,
-                                   base::Bind(&IgnoreCdmAttached));
+                                   base::BindRepeating(&IgnoreCdmAttached));
   }
 
   shared_state_.renderer->Initialize(demuxer_, this, done_cb);
@@ -1027,10 +1039,10 @@
   seek_time_ = kNoTimestamp;
 
   media_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&RendererWrapper::Start,
-                 base::Unretained(renderer_wrapper_.get()), start_type, demuxer,
-                 base::Passed(&renderer), weak_factory_.GetWeakPtr()));
+      FROM_HERE, base::BindOnce(&RendererWrapper::Start,
+                                base::Unretained(renderer_wrapper_.get()),
+                                start_type, demuxer, base::Passed(&renderer),
+                                weak_factory_.GetWeakPtr()));
 }
 
 void PipelineImpl::Stop() {
@@ -1142,9 +1154,9 @@
 
   playback_rate_ = playback_rate;
   media_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&RendererWrapper::SetPlaybackRate,
-                 base::Unretained(renderer_wrapper_.get()), playback_rate_));
+      FROM_HERE, base::BindOnce(&RendererWrapper::SetPlaybackRate,
+                                base::Unretained(renderer_wrapper_.get()),
+                                playback_rate_));
 }
 
 float PipelineImpl::GetVolume() const {
@@ -1162,8 +1174,8 @@
   volume_ = volume;
   media_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&RendererWrapper::SetVolume,
-                 base::Unretained(renderer_wrapper_.get()), volume_));
+      base::BindOnce(&RendererWrapper::SetVolume,
+                     base::Unretained(renderer_wrapper_.get()), volume_));
 }
 
 base::TimeDelta PipelineImpl::GetMediaTime() const {
@@ -1225,9 +1237,9 @@
 
   media_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&RendererWrapper::SetCdm,
-                 base::Unretained(renderer_wrapper_.get()), cdm_context,
-                 media::BindToCurrentLoop(cdm_attached_cb)));
+      base::BindOnce(&RendererWrapper::SetCdm,
+                     base::Unretained(renderer_wrapper_.get()), cdm_context,
+                     BindToCurrentLoop(cdm_attached_cb)));
 }
 
 #define RETURN_STRING(state) \
diff --git a/media/base/serial_runner.h b/media/base/serial_runner.h
index 31cb5ce..e2cd593 100644
--- a/media/base/serial_runner.h
+++ b/media/base/serial_runner.h
@@ -26,6 +26,7 @@
 // the completion callback as the series progresses.
 class MEDIA_EXPORT SerialRunner {
  public:
+  // TODO(dalecurtis): Change SerialRunner to use OnceCallback.
   typedef base::Callback<void(const base::Closure&)> BoundClosure;
   typedef base::Callback<void(const PipelineStatusCB&)> BoundPipelineStatusCB;
 
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index c36b547..c1cde04f 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -276,6 +276,9 @@
 }
 
 bool VADisplayState::InitializeOnce() {
+  static_assert(VA_MAJOR_VERSION >= 1 && VA_MINOR_VERSION >= 1,
+                "Requires VA-API >= 1.1.0");
+
   switch (gl::GetGLImplementation()) {
     case gl::kGLImplementationEGLGLES2:
       va_display_ = vaGetDisplayDRM(drm_fd_.get());
diff --git a/mojo/public/cpp/bindings/README.md b/mojo/public/cpp/bindings/README.md
index 51cbb3c..399428d 100644
--- a/mojo/public/cpp/bindings/README.md
+++ b/mojo/public/cpp/bindings/README.md
@@ -327,7 +327,9 @@
 As before, both clients and implementations of this interface use the same
 signature for the `GetTail` method: implementations use the `callback` argument
 to *respond* to the request, while clients pass a `callback` argument to
-asynchronously `receive` the response. Here's an updated implementation:
+asynchronously `receive` the response. A client's `callback` runs on the same
+sequence on which they invoked `GetTail` (the sequence to which their `logger`
+is bound). Here's an updated implementation:
 
 ```cpp
 class LoggerImpl : public sample::mojom::Logger {
diff --git a/mojo/public/cpp/system/simple_watcher.cc b/mojo/public/cpp/system/simple_watcher.cc
index 26f99c93..d4963526 100644
--- a/mojo/public/cpp/system/simple_watcher.cc
+++ b/mojo/public/cpp/system/simple_watcher.cc
@@ -215,6 +215,8 @@
   // notification, in which case the watch may have already been implicitly
   // cancelled.
   DCHECK(rv == MOJO_RESULT_OK || rv == MOJO_RESULT_NOT_FOUND);
+
+  weak_factory_.InvalidateWeakPtrs();
 }
 
 MojoResult SimpleWatcher::Arm(MojoResult* ready_result,
diff --git a/mojo/public/tools/bindings/generators/js_templates/lite/struct_externs.tmpl b/mojo/public/tools/bindings/generators/js_templates/lite/struct_externs.tmpl
index c3322e1..cc22de4 100644
--- a/mojo/public/tools/bindings/generators/js_templates/lite/struct_externs.tmpl
+++ b/mojo/public/tools/bindings/generators/js_templates/lite/struct_externs.tmpl
@@ -2,14 +2,18 @@
    Closure base library is unavailable. See https://crbug.com/898692 #}
 goog.provide('{{module.namespace}}.{{struct.name}}');
 
-{{module.namespace}}.{{struct.name}} = class {
-  constructor() {
+{% if struct.packed.packed_fields %}
+/**
+ * @typedef { {
 {%- for packed_field in struct.packed.packed_fields %}
-    /** @type { {{packed_field.field.kind|lite_closure_type_with_nullability}} } */
-    this.{{packed_field.field.name}};
+ *   {{packed_field.field.name}}: {{packed_field.field.kind|lite_closure_field_type}},
 {%-  endfor %}
-  }
-};
+ * } }
+ */
+{% else %}
+/** @typedef {Object} */
+{% endif %}
+{{module.namespace}}.{{struct.name}};
 
 {#--- Enum definitions #}
 {% for enum in struct.enums %}
diff --git a/mojo/public/tools/bindings/generators/mojom_js_generator.py b/mojo/public/tools/bindings/generators/mojom_js_generator.py
index b9e3656..231ea60 100644
--- a/mojo/public/tools/bindings/generators/mojom_js_generator.py
+++ b/mojo/public/tools/bindings/generators/mojom_js_generator.py
@@ -305,6 +305,7 @@
       "lite_closure_param_type": self._LiteClosureParamType,
       "lite_closure_type_with_nullability":
           self._LiteClosureTypeWithNullability,
+      "lite_closure_field_type": self._LiteClosureFieldType,
       "payload_size": JavaScriptPayloadSize,
       "to_camel": generator.ToCamel,
       "union_decode_snippet": self._JavaScriptUnionDecodeSnippet,
@@ -420,17 +421,17 @@
     if kind in mojom.PRIMITIVES:
       return _kind_to_closure_type[kind]
     if mojom.IsArrayKind(kind):
-      return "Array<%s>" % self._ClosureType(kind.kind)
+      return "Array<%s>" % self._LiteClosureTypeWithNullability(kind.kind)
     if mojom.IsMapKind(kind) and self._IsStringableKind(kind.key_kind):
-      return "Map<%s, %s>|Object<%s, %s>" % (
-          self._LiteClosureType(kind.key_kind),
-          self._LiteClosureType(kind.value_kind),
-          self._LiteClosureType(kind.key_kind),
-          self._LiteClosureType(kind.value_kind))
+      return "(Map<%s, %s>|Object<%s, %s>)" % (
+          self._LiteClosureTypeWithNullability(kind.key_kind),
+          self._LiteClosureTypeWithNullability(kind.value_kind),
+          self._LiteClosureTypeWithNullability(kind.key_kind),
+          self._LiteClosureTypeWithNullability(kind.value_kind))
     if mojom.IsMapKind(kind):
       return "Map<%s, %s>" % (
-          self._LiteClosureType(kind.key_kind),
-          self._LiteClosureType(kind.value_kind))
+          self._LiteClosureTypeWithNullability(kind.key_kind),
+          self._LiteClosureTypeWithNullability(kind.value_kind))
 
     if mojom.IsAssociatedKind(kind) or mojom.IsInterfaceRequestKind(kind):
       named_kind = kind.kind
@@ -471,7 +472,8 @@
     if mojom.IsStructKind(kind) or mojom.IsUnionKind(kind):
       return prefix + "Object"
     if mojom.IsArrayKind(kind):
-      return prefix + ("Array<%s>" % self._LiteClosureParamType(kind.kind))
+      return prefix + ("Array<%s>" %
+                       self._LiteClosureParamType(kind.kind))
     if mojom.IsMapKind(kind):
       return "%sMap<%s, %s>|%sObject<%s, %s>" % (
           prefix, self._LiteClosureParamType(kind.key_kind),
@@ -482,9 +484,15 @@
     return prefix + self._LiteClosureType(kind)
 
   def _LiteClosureTypeWithNullability(self, kind):
-    return (("" if mojom.IsNullableKind(kind) else "!") +
+    return (("?" if mojom.IsNullableKind(kind) else "!") +
         self._LiteClosureType(kind))
 
+  def _LiteClosureFieldType(self, kind):
+    if mojom.IsNullableKind(kind):
+      return "(" + self._LiteClosureType(kind) + "|undefined)"
+    else:
+      return "!" + self._LiteClosureType(kind)
+
   def _NamespaceDeclarations(self, namespace):
     pieces = namespace.split('.')
     declarations = []
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 2b2d65c..85eba84 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -373,6 +373,29 @@
   }
   write_file(target_sources_list, sources_list)
 
+  # Sanity check that either all input files have a .mojom extension, or
+  # all input files have a .test-mojom extension AND |testonly| is |true|.
+  sources_list_filenames =
+      process_file_template(sources_list, "{{source_file_part}}")
+  sources_list_filenames_with_mojom_extension =
+      process_file_template(sources_list, "{{source_name_part}}.mojom")
+  if (sources_list_filenames != sources_list_filenames_with_mojom_extension) {
+    sources_list_filenames_with_test_mojom_extension =
+        process_file_template(sources_list, "{{source_name_part}}.test-mojom")
+    if (sources_list_filenames ==
+        sources_list_filenames_with_test_mojom_extension) {
+      assert(
+          defined(invoker.testonly) && invoker.testonly,
+          "mojom targets for .test-mojom files must set |testonly| to |true|")
+    } else {
+      assert(
+          false,
+          "One or more mojom files has an invalid extension. The only " +
+              "allowed extensions are .mojom and .test-mojom, and any given " +
+              "mojom target must use one or the other exclusively.")
+    }
+  }
+
   # a target implicitly depends on its own sources
   deps_sources = [ rebase_path(target_sources_list, root_build_dir) ]
   foreach(d, all_deps) {
@@ -594,9 +617,9 @@
     }
 
     generator_shared_cpp_outputs = [
-      "{{source_gen_dir}}/{{source_name_part}}.mojom-shared-internal.h",
-      "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.cc",
-      "{{source_gen_dir}}/{{source_name_part}}.mojom-shared.h",
+      "{{source_gen_dir}}/{{source_file_part}}-shared-internal.h",
+      "{{source_gen_dir}}/{{source_file_part}}-shared.cc",
+      "{{source_gen_dir}}/{{source_file_part}}-shared.h",
     ]
     generator_shared_target_name = "${target_name}_shared__generator"
     action(generator_shared_target_name) {
@@ -729,8 +752,8 @@
         variant_dash_suffix = "-${variant}"
       }
       generator_cpp_outputs += [
-        "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.cc",
-        "{{source_gen_dir}}/{{source_name_part}}.mojom${variant_dash_suffix}.h",
+        "{{source_gen_dir}}/{{source_file_part}}${variant_dash_suffix}.cc",
+        "{{source_gen_dir}}/{{source_file_part}}${variant_dash_suffix}.h",
       ]
       enabled_sources = []
       if (defined(bindings_configuration.blacklist)) {
@@ -1073,7 +1096,7 @@
       java_generator_target_name = target_name + "_java__generator"
       if (enabled_sources != []) {
         generator_java_outputs =
-            [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ]
+            [ "{{source_gen_dir}}/{{source_file_part}}.srcjar" ]
         action(java_generator_target_name) {
           script = mojom_generator_script
           inputs = mojom_generator_sources + jinja2_sources
@@ -1164,10 +1187,9 @@
     if (defined(invoker.sources)) {
       generator_js_target_name = "${target_name}_js__generator"
       generator_js_lite_outputs =
-          [ "{{source_gen_dir}}/{{source_name_part}}.mojom-lite.js" ]
-      generator_js_outputs =
-          [ "{{source_gen_dir}}/{{source_name_part}}.mojom.js" ] +
-          generator_js_lite_outputs
+          [ "{{source_gen_dir}}/{{source_file_part}}-lite.js" ]
+      generator_js_outputs = [ "{{source_gen_dir}}/{{source_file_part}}.js" ] +
+                             generator_js_lite_outputs
       action(generator_js_target_name) {
         script = mojom_generator_script
         inputs = mojom_generator_sources + jinja2_sources
@@ -1267,9 +1289,8 @@
       js_library_for_compile_target_name =
           "${target_name}_js_library_for_compile"
       if (defined(invoker.sources)) {
-        generator_js_lite_for_compile_outputs = [
-          "{{source_gen_dir}}/{{source_name_part}}.mojom-lite-for-compile.js",
-        ]
+        generator_js_lite_for_compile_outputs =
+            [ "{{source_gen_dir}}/{{source_file_part}}-lite-for-compile.js" ]
         js_library(js_library_for_compile_target_name) {
           extra_public_deps = [ ":$generator_js_target_name" ]
           sources = process_file_template(invoker.sources,
@@ -1296,7 +1317,7 @@
         externs_list = [ "${externs_path}/mojo.js" ]
         externs_list += process_file_template(
                 invoker.sources,
-                [ "{{source_gen_dir}}/{{source_name_part}}.mojom-lite.externs.js" ])
+                [ "{{source_gen_dir}}/{{source_file_part}}-lite.externs.js" ])
 
         deps = []
         foreach(d, all_deps) {
diff --git a/net/base/network_config_watcher_mac.cc b/net/base/network_config_watcher_mac.cc
index 4e3f5e83..f324969a 100644
--- a/net/base/network_config_watcher_mac.cc
+++ b/net/base/network_config_watcher_mac.cc
@@ -115,6 +115,8 @@
 }
 #endif  // !defined(OS_IOS)
 
+}  // namespace
+
 class NetworkConfigWatcherMacThread : public base::Thread {
  public:
   NetworkConfigWatcherMacThread(NetworkConfigWatcherMac::Delegate* delegate);
@@ -154,10 +156,8 @@
 }
 
 NetworkConfigWatcherMacThread::~NetworkConfigWatcherMacThread() {
-  // Allow IO because Stop() calls PlatformThread::Join(), which is a blocking
-  // operation. This is expected during shutdown.
-  base::ThreadRestrictions::ScopedAllowIO allow_io;
-
+  // This is expected to be invoked during shutdown.
+  base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_thread_join;
   Stop();
 }
 
@@ -259,8 +259,6 @@
   return true;
 }
 
-}  // namespace
-
 NetworkConfigWatcherMac::NetworkConfigWatcherMac(Delegate* delegate)
     : notifier_thread_(new NetworkConfigWatcherMacThread(delegate)) {
   // We create this notifier thread because the notification implementation
diff --git a/net/proxy_resolution/multi_threaded_proxy_resolver.cc b/net/proxy_resolution/multi_threaded_proxy_resolver.cc
index c05969df..ae41f4f 100644
--- a/net/proxy_resolution/multi_threaded_proxy_resolver.cc
+++ b/net/proxy_resolution/multi_threaded_proxy_resolver.cc
@@ -28,6 +28,11 @@
 #include "net/proxy_resolution/proxy_resolver.h"
 
 namespace net {
+
+// http://crbug.com/69710
+class MultiThreadedProxyResolverScopedAllowJoinOnIO
+    : public base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope {};
+
 namespace {
 class Job;
 
@@ -370,8 +375,9 @@
   DCHECK(coordinator_);
 
   {
-    // See http://crbug.com/69710.
-    base::ThreadRestrictions::ScopedAllowIO allow_io;
+    // TODO(http://crbug.com/69710): Use TaskScheduler instead of creating a
+    // base::Thread.
+    MultiThreadedProxyResolverScopedAllowJoinOnIO allow_thread_join;
 
     // Join the worker thread.
     thread_.reset();
diff --git a/net/test/embedded_test_server/embedded_test_server.cc b/net/test/embedded_test_server/embedded_test_server.cc
index 371e73ab0..6578877c 100644
--- a/net/test/embedded_test_server/embedded_test_server.cc
+++ b/net/test/embedded_test_server/embedded_test_server.cc
@@ -67,9 +67,7 @@
   }
 
   {
-    // Thread::Join induced by test code should cause an assert.
-    base::ScopedAllowBlockingForTesting allow_blocking;
-
+    base::ScopedAllowBaseSyncPrimitivesForTesting allow_wait_for_thread_join;
     io_thread_.reset();
   }
 }
diff --git a/net/test/spawned_test_server/local_test_server_win.cc b/net/test/spawned_test_server/local_test_server_win.cc
index 5addf0be..bc78e77c 100644
--- a/net/test/spawned_test_server/local_test_server_win.cc
+++ b/net/test/spawned_test_server/local_test_server_win.cc
@@ -72,7 +72,7 @@
     bytes_read += num_bytes;
   }
 
-  base::ScopedAllowBlockingForTesting allow_thread_join;
+  base::ScopedAllowBaseSyncPrimitivesForTesting allow_thread_join;
   thread.Stop();
 
   // If the timeout kicked in, abort.
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 64fcb0c..804efd5a 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -119,7 +119,7 @@
     ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
     // Always clear the referrer regardless of the request destination.
     NO_REFERRER,
-    MAX_REFERRER_POLICY
+    MAX_REFERRER_POLICY = NO_REFERRER
   };
 
   // First-party URL redirect policy: During server redirects, the first-party
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 2422a0b..2c55a0eb 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -349,9 +349,6 @@
       return referrer_origin.GetURL();
     case URLRequest::NO_REFERRER:
       return GURL();
-    case URLRequest::MAX_REFERRER_POLICY:
-      NOTREACHED();
-      return GURL();
   }
 
   NOTREACHED();
diff --git a/pdf/out_of_process_instance.cc b/pdf/out_of_process_instance.cc
index ef12260..64b4b62 100644
--- a/pdf/out_of_process_instance.cc
+++ b/pdf/out_of_process_instance.cc
@@ -102,6 +102,7 @@
 // Save (Page -> Plugin)
 constexpr char kJSSaveType[] = "save";
 constexpr char kJSToken[] = "token";
+constexpr char kJSForce[] = "force";
 // Save Data (Plugin -> Page)
 constexpr char kJSSaveDataType[] = "saveData";
 constexpr char kJSFileName[] = "fileName";
@@ -666,11 +667,17 @@
   } else if (type == kJSPrintType) {
     Print();
   } else if (type == kJSSaveType) {
-    if (!dict.Get(pp::Var(kJSToken)).is_string()) {
+    if (!(dict.Get(pp::Var(kJSToken)).is_string() &&
+          dict.Get(pp::Var(kJSForce)).is_bool())) {
       NOTREACHED();
       return;
     }
-    Save(dict.Get(pp::Var(kJSToken)).AsString());
+    const bool force = dict.Get(pp::Var(kJSForce)).AsBool();
+    if (force) {
+      SaveToBuffer(dict.Get(pp::Var(kJSToken)).AsString());
+    } else {
+      SaveToFile(dict.Get(pp::Var(kJSToken)).AsString());
+    }
   } else if (type == kJSRotateClockwiseType) {
     RotateClockwise();
   } else if (type == kJSRotateCounterclockwiseType) {
@@ -1473,37 +1480,58 @@
   PostMessage(message);
 }
 
-void OutOfProcessInstance::Save(const std::string& token) {
-  engine_->KillFormFocus();
+bool OutOfProcessInstance::ShouldSaveEdits() const {
+  return edit_mode_ &&
+         base::FeatureList::IsEnabled(features::kSaveEditedPDFForm);
+}
 
-  if (!base::FeatureList::IsEnabled(features::kSaveEditedPDFForm) ||
-      !edit_mode_) {
-    ConsumeSaveToken(token);
-    pp::PDF::SaveAs(this);
-    return;
-  }
+void OutOfProcessInstance::SaveToBuffer(const std::string& token) {
+  engine_->KillFormFocus();
 
   GURL url(url_);
   std::string file_name = url.ExtractFileName();
   file_name = net::UnescapeURLComponent(file_name, net::UnescapeRule::SPACES);
-  std::vector<uint8_t> data = engine_->GetSaveData();
-
-  if (data.size() == 0u || data.size() > kMaximumSavedFileSize) {
-    // TODO(thestig): Add feedback to the user that a failure occurred.
-    ConsumeSaveToken(token);
-    return;
-  }
 
   pp::VarDictionary message;
   message.Set(kType, kJSSaveDataType);
   message.Set(kJSToken, pp::Var(token));
   message.Set(kJSFileName, pp::Var(file_name));
-  pp::VarArrayBuffer buffer(data.size());
-  std::copy(data.begin(), data.end(), reinterpret_cast<char*>(buffer.Map()));
-  message.Set(kJSDataToSave, buffer);
+  // This will be overwritten if the save is successful.
+  message.Set(kJSDataToSave, pp::Var(pp::Var::Null()));
+
+  if (ShouldSaveEdits()) {
+    std::vector<uint8_t> data = engine_->GetSaveData();
+    if (data.size() > 0 && data.size() <= kMaximumSavedFileSize) {
+      pp::VarArrayBuffer buffer(data.size());
+      std::copy(data.begin(), data.end(),
+                reinterpret_cast<char*>(buffer.Map()));
+      message.Set(kJSDataToSave, buffer);
+    }
+  } else {
+    DCHECK(base::FeatureList::IsEnabled(features::kPDFAnnotations));
+    uint32_t length = engine_->GetLoadedByteSize();
+    if (length > 0 && length <= kMaximumSavedFileSize) {
+      pp::VarArrayBuffer buffer(length);
+      if (engine_->ReadLoadedBytes(length, buffer.Map())) {
+        message.Set(kJSDataToSave, buffer);
+      }
+    }
+  }
+
   PostMessage(message);
 }
 
+void OutOfProcessInstance::SaveToFile(const std::string& token) {
+  if (!ShouldSaveEdits()) {
+    engine_->KillFormFocus();
+    ConsumeSaveToken(token);
+    pp::PDF::SaveAs(this);
+    return;
+  }
+
+  SaveToBuffer(token);
+}
+
 void OutOfProcessInstance::ConsumeSaveToken(const std::string& token) {
   pp::VarDictionary message;
   message.Set(kType, kJSConsumeSaveTokenType);
diff --git a/pdf/out_of_process_instance.h b/pdf/out_of_process_instance.h
index 2c91f54..851003b4 100644
--- a/pdf/out_of_process_instance.h
+++ b/pdf/out_of_process_instance.h
@@ -186,7 +186,9 @@
   // frame's origin.
   pp::URLLoader CreateURLLoaderInternal();
 
-  void Save(const std::string& token);
+  bool ShouldSaveEdits() const;
+  void SaveToFile(const std::string& token);
+  void SaveToBuffer(const std::string& token);
   void ConsumeSaveToken(const std::string& token);
 
   void FormDidOpen(int32_t result);
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index 64ed8ee..f8d2822 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -412,6 +412,9 @@
 
   // Remove focus from form widgets, consolidating the user input.
   virtual void KillFormFocus() = 0;
+
+  virtual uint32_t GetLoadedByteSize() = 0;
+  virtual bool ReadLoadedBytes(uint32_t length, void* buffer) = 0;
 };
 
 // Interface for exports that wrap the PDF engine.
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 189ec996..8c3a4691 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -535,7 +535,6 @@
 void SetUpV8() {
   const char* recommended = FPDF_GetRecommendedV8Flags();
   v8::V8::SetFlagsFromString(recommended, strlen(recommended));
-
   gin::IsolateHolder::Initialize(gin::IsolateHolder::kNonStrictMode,
                                  gin::IsolateHolder::kStableV8Extras,
                                  gin::ArrayBufferAllocator::SharedInstance());
@@ -1227,6 +1226,15 @@
   SetInFormTextArea(false);
 }
 
+uint32_t PDFiumEngine::GetLoadedByteSize() {
+  return doc_loader_->GetDocumentSize();
+}
+
+bool PDFiumEngine::ReadLoadedBytes(uint32_t length, void* buffer) {
+  DCHECK_LE(length, GetLoadedByteSize());
+  return doc_loader_->GetBlock(0, length, buffer);
+}
+
 void PDFiumEngine::SetFormSelectedText(FPDF_FORMHANDLE form_handle,
                                        FPDF_PAGE page) {
   unsigned long form_sel_text_len =
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 792b054..13952100 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -136,6 +136,8 @@
   void OnDocumentCanceled() override;
   void CancelBrowserDownload() override;
   void KillFormFocus() override;
+  uint32_t GetLoadedByteSize() override;
+  bool ReadLoadedBytes(uint32_t length, void* buffer) override;
 
 #if defined(PDF_ENABLE_XFA)
   void UpdatePageCount();
diff --git a/services/network/public/cpp/net_ipc_param_traits.h b/services/network/public/cpp/net_ipc_param_traits.h
index 9bfa614..80d7cd4 100644
--- a/services/network/public/cpp/net_ipc_param_traits.h
+++ b/services/network/public/cpp/net_ipc_param_traits.h
@@ -232,7 +232,7 @@
                           net::SSLInfo::HANDSHAKE_FULL)
 
 IPC_ENUM_TRAITS_MAX_VALUE(net::URLRequest::ReferrerPolicy,
-                          net::URLRequest::MAX_REFERRER_POLICY - 1)
+                          net::URLRequest::MAX_REFERRER_POLICY)
 
 IPC_STRUCT_TRAITS_BEGIN(net::HttpRequestHeaders::HeaderKeyValuePair)
   IPC_STRUCT_TRAITS_MEMBER(key)
diff --git a/services/service_manager/BUILD.gn b/services/service_manager/BUILD.gn
index dfb6061..efd375a 100644
--- a/services/service_manager/BUILD.gn
+++ b/services/service_manager/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//services/service_manager/public/service_manifest.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
 
diff --git a/services/service_manager/background/tests/BUILD.gn b/services/service_manager/background/tests/BUILD.gn
index 971b93c..c571e68 100644
--- a/services/service_manager/background/tests/BUILD.gn
+++ b/services/service_manager/background/tests/BUILD.gn
@@ -3,9 +3,7 @@
 # found in the LICENSE file.
 
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//services/catalog/public/tools/catalog.gni")
 import("//services/service_manager/public/cpp/service_executable.gni")
-import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 source_set("unittests") {
@@ -20,7 +18,6 @@
     "//base/test:test_support",
     "//services/service_manager/background:lib",
     "//services/service_manager/public/cpp",
-    "//services/service_manager/tests:catalog_source",
     "//testing/gtest",
     "//url",
   ]
@@ -31,12 +28,14 @@
 }
 
 mojom("test_service_interfaces") {
+  testonly = true
   sources = [
-    "test.mojom",
+    "background.test-mojom",
   ]
 }
 
 service_executable("background_service_manager_test_service") {
+  testonly = true
   sources = [
     "test_service.cc",
   ]
@@ -48,19 +47,3 @@
     "//services/service_manager/public/mojom",
   ]
 }
-
-service_manifest("test_manifest") {
-  name = "background_service_manager_unittest"
-  source = "test_manifest.json"
-}
-
-service_manifest("test_service_manifest") {
-  name = "background_service_manager_test_service"
-  source = "test_service_manifest.json"
-}
-
-catalog("catalog") {
-  embedded_services = [ ":test_manifest" ]
-
-  standalone_services = [ ":test_service_manifest" ]
-}
diff --git a/services/service_manager/background/tests/OWNERS b/services/service_manager/background/tests/OWNERS
deleted file mode 100644
index c2a0013..0000000
--- a/services/service_manager/background/tests/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file test_manifest.json=set noparent
-per-file test_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file test_service_manifest.json=set noparent
-per-file test_service_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/background/tests/test.mojom b/services/service_manager/background/tests/background.test-mojom
similarity index 100%
rename from services/service_manager/background/tests/test.mojom
rename to services/service_manager/background/tests/background.test-mojom
diff --git a/services/service_manager/background/tests/background_service_manager_unittest.cc b/services/service_manager/background/tests/background_service_manager_unittest.cc
index 9d748bf..07c39b3 100644
--- a/services/service_manager/background/tests/background_service_manager_unittest.cc
+++ b/services/service_manager/background/tests/background_service_manager_unittest.cc
@@ -5,16 +5,19 @@
 #include "services/service_manager/background/background_service_manager.h"
 
 #include <memory>
+#include <vector>
 
+#include "base/no_destructor.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/values.h"
-#include "services/service_manager/background/tests/test.mojom.h"
+#include "services/service_manager/background/tests/background.test-mojom.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/constants.h"
+#include "services/service_manager/public/cpp/manifest.h"
+#include "services/service_manager/public/cpp/manifest_builder.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
-#include "services/service_manager/tests/catalog_source.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace service_manager {
@@ -23,6 +26,22 @@
 const char kTestName[] = "background_service_manager_unittest";
 const char kAppName[] = "background_service_manager_test_service";
 
+const char kTestServiceCapability[] = "test_service";
+
+const std::vector<Manifest>& GetTestManifests() {
+  static base::NoDestructor<std::vector<Manifest>> manifests{
+      {ManifestBuilder()
+           .WithServiceName(kTestName)
+           .RequireCapability(kAppName, kTestServiceCapability)
+           .Build(),
+       service_manager::ManifestBuilder()
+           .WithServiceName(kAppName)
+           .ExposeCapability(kTestServiceCapability,
+                             Manifest::InterfaceList<mojom::TestService>())
+           .Build()}};
+  return *manifests;
+}
+
 // The parent unit test suite service, not the underlying test service.
 class ServiceImpl : public Service {
  public:
@@ -55,8 +74,8 @@
 #endif
 TEST(BackgroundServiceManagerTest, MAYBE_Basic) {
   base::test::ScopedTaskEnvironment scoped_task_environment;
-  BackgroundServiceManager background_service_manager(
-      nullptr, test::CreateTestCatalog());
+  BackgroundServiceManager background_service_manager(nullptr,
+                                                      GetTestManifests());
   mojom::ServicePtr service;
   ServiceImpl service_impl(mojo::MakeRequest(&service));
   background_service_manager.RegisterService(
diff --git a/services/service_manager/background/tests/test_manifest.json b/services/service_manager/background/tests/test_manifest.json
deleted file mode 100644
index de217f1..0000000
--- a/services/service_manager/background/tests/test_manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "name": "background_service_manager_unittest",
-  "display_name": "Background Service Manager Unittest",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "requires": {
-        "background_service_manager_test_service": [
-          "background_service_manager_unittest:test_service"
-        ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/background/tests/test_service.cc b/services/service_manager/background/tests/test_service.cc
index 7929689..d1af14a 100644
--- a/services/service_manager/background/tests/test_service.cc
+++ b/services/service_manager/background/tests/test_service.cc
@@ -5,7 +5,7 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/background/tests/test.mojom.h"
+#include "services/service_manager/background/tests/background.test-mojom.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
diff --git a/services/service_manager/background/tests/test_service_manifest.json b/services/service_manager/background/tests/test_service_manifest.json
deleted file mode 100644
index fbe5fc4..0000000
--- a/services/service_manager/background/tests/test_service_manifest.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "name": "background_service_manager_test_service",
-  "display_name": "Background Service Manager Test Service",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "background_service_manager_unittest:test_service": [
-          "service_manager.mojom.TestService"
-        ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/runner/host/BUILD.gn b/services/service_manager/runner/host/BUILD.gn
index 6a9ebb0..234fd8a 100644
--- a/services/service_manager/runner/host/BUILD.gn
+++ b/services/service_manager/runner/host/BUILD.gn
@@ -4,7 +4,6 @@
 
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//services/service_manager/public/cpp/service_executable.gni")
-import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 source_set("lib") {
@@ -75,9 +74,4 @@
       "host_test_service_main.cc",
     ]
   }
-
-  service_manifest("host_test_service_manifest") {
-    name = "host_test_service"
-    source = "host_test_service_manifest.json"
-  }
 }
diff --git a/services/service_manager/runner/host/OWNERS b/services/service_manager/runner/host/OWNERS
index d162e8d..90a1836b 100644
--- a/services/service_manager/runner/host/OWNERS
+++ b/services/service_manager/runner/host/OWNERS
@@ -1,4 +1,2 @@
 per-file linux_sandbox*=rickyz@chromium.org
 
-per-file host_test_service_manifest.json=set noparent
-per-file host_test_service_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/runner/host/host_test_service_manifest.json b/services/service_manager/runner/host/host_test_service_manifest.json
deleted file mode 100644
index 1307358..0000000
--- a/services/service_manager/runner/host/host_test_service_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
-  "name": "host_test_service",
-  "display_name": "Service Host Test Service"
-}
diff --git a/services/service_manager/tests/BUILD.gn b/services/service_manager/tests/BUILD.gn
index 1481b88..b3cc60a 100644
--- a/services/service_manager/tests/BUILD.gn
+++ b/services/service_manager/tests/BUILD.gn
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//services/catalog/public/tools/catalog.gni")
 import("//services/service_manager/public/cpp/service_executable.gni")
 import("//testing/test.gni")
 
@@ -67,19 +66,3 @@
     "//services/service_manager/runner/common",
   ]
 }
-
-catalog("catalog") {
-  testonly = true
-  catalog_deps = [
-    "//services/service_manager/background/tests:catalog",
-    "//services/service_manager/tests/connect:catalog",
-    "//services/service_manager/tests/service_manager:catalog",
-    "//services/service_manager/tests/shutdown:catalog",
-  ]
-}
-
-catalog_cpp_source("catalog_source") {
-  testonly = true
-  catalog = ":catalog"
-  generated_function_name = "service_manager::test::CreateTestCatalog"
-}
diff --git a/services/service_manager/tests/connect/BUILD.gn b/services/service_manager/tests/connect/BUILD.gn
index 12d36d2..f861a549 100644
--- a/services/service_manager/tests/connect/BUILD.gn
+++ b/services/service_manager/tests/connect/BUILD.gn
@@ -3,9 +3,7 @@
 # found in the LICENSE file.
 
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//services/catalog/public/tools/catalog.gni")
 import("//services/service_manager/public/cpp/service_executable.gni")
-import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 source_set("connect") {
@@ -20,7 +18,6 @@
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp/test:test_support",
     "//services/service_manager/public/mojom",
-    "//services/service_manager/tests:catalog_source",
     "//services/service_manager/tests:util",
     "//testing/gtest",
   ]
@@ -35,8 +32,9 @@
 }
 
 mojom("interfaces") {
+  testonly = true
   sources = [
-    "connect_test.mojom",
+    "connect.test-mojom",
   ]
   deps = [
     "//mojo/public/mojom/base",
@@ -44,26 +42,6 @@
   ]
 }
 
-service_manifest("manifest") {
-  name = "connect_unittests"
-  source = "connect_unittests_manifest.json"
-}
-
-service_manifest("connect_test_a_manifest") {
-  name = "connect_test_a"
-  source = "connect_test_app_a_manifest.json"
-}
-
-service_manifest("connect_test_b_manifest") {
-  name = "connect_test_b"
-  source = "connect_test_app_b_manifest.json"
-}
-
-service_manifest("connect_test_sandboxed_manifest") {
-  name = "connect_test_sandboxed_app"
-  source = "connect_test_sandboxed_app_manifest.json"
-}
-
 service_executable("connect_test_package") {
   testonly = true
   sources = [
@@ -78,16 +56,6 @@
   ]
 }
 
-service_manifest("connect_test_package_manifest") {
-  name = "connect_test_package"
-  source = "connect_test_package_manifest.json"
-  packaged_services = [
-    ":connect_test_a_manifest",
-    ":connect_test_b_manifest",
-    ":connect_test_sandboxed_manifest",
-  ]
-}
-
 service_executable("connect_test_app") {
   testonly = true
   sources = [
@@ -102,11 +70,6 @@
   ]
 }
 
-service_manifest("connect_test_app_manifest") {
-  name = "connect_test_app"
-  source = "connect_test_app_manifest.json"
-}
-
 service_executable("connect_test_class_app") {
   testonly = true
   sources = [
@@ -121,11 +84,6 @@
   ]
 }
 
-service_manifest("connect_test_class_app_manifest") {
-  name = "connect_test_class_app"
-  source = "connect_test_class_app_manifest.json"
-}
-
 service_executable("connect_test_singleton_app") {
   testonly = true
   sources = [
@@ -138,11 +96,6 @@
   ]
 }
 
-service_manifest("connect_test_singleton_app_manifest") {
-  name = "connect_test_singleton_app"
-  source = "connect_test_singleton_app_manifest.json"
-}
-
 executable("connect_test_exe") {
   testonly = true
 
@@ -158,20 +111,3 @@
     "//services/service_manager/public/cpp/service_executable:main",
   ]
 }
-
-service_manifest("connect_test_exe_manifest") {
-  name = "connect_test_exe"
-  source = "connect_test_exe_manifest.json"
-}
-
-catalog("catalog") {
-  embedded_services = [ ":manifest" ]
-
-  standalone_services = [
-    ":connect_test_app_manifest",
-    ":connect_test_class_app_manifest",
-    ":connect_test_exe_manifest",
-    ":connect_test_package_manifest",
-    ":connect_test_singleton_app_manifest",
-  ]
-}
diff --git a/services/service_manager/tests/connect/OWNERS b/services/service_manager/tests/connect/OWNERS
deleted file mode 100644
index 7b1a383..0000000
--- a/services/service_manager/tests/connect/OWNERS
+++ /dev/null
@@ -1,29 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_app_a_manifest.json=set noparent
-per-file connect_test_app_a_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_app_manifest.json=set noparent
-per-file connect_test_app_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_app_b_manifest.json=set noparent
-per-file connect_test_app_b_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_class_app_manifest.json=set noparent
-per-file connect_test_class_app_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_exe_manifest.json=set noparent
-per-file connect_test_exe_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_package_manifest.json=set noparent
-per-file connect_test_package_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_singleton_app_manifest.json=set noparent
-per-file connect_test_singleton_app_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_unittests_manifest.json=set noparent
-per-file connect_unittests_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file connect_test_sandboxed_app_manifest.json=set noparent
-per-file connect_test_sandboxed_app_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/tests/connect/connect_test.mojom b/services/service_manager/tests/connect/connect.test-mojom
similarity index 100%
rename from services/service_manager/tests/connect/connect_test.mojom
rename to services/service_manager/tests/connect/connect.test-mojom
diff --git a/services/service_manager/tests/connect/connect_test_app.cc b/services/service_manager/tests/connect/connect_test_app.cc
index ca9c0df..8cfb4fd7 100644
--- a/services/service_manager/tests/connect/connect_test_app.cc
+++ b/services/service_manager/tests/connect/connect_test_app.cc
@@ -17,7 +17,7 @@
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/mojom/connector.mojom.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/connect/connect_test.mojom.h"
+#include "services/service_manager/tests/connect/connect.test-mojom.h"
 
 namespace service_manager {
 
diff --git a/services/service_manager/tests/connect/connect_test_app_a_manifest.json b/services/service_manager/tests/connect/connect_test_app_a_manifest.json
deleted file mode 100644
index d396f4d8..0000000
--- a/services/service_manager/tests/connect/connect_test_app_a_manifest.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-  "name": "connect_test_a",
-  "display_name": "Connect Test A",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "connect_unittests:connect_test_service": [
-          "service_manager.test.mojom.ConnectTestService"
-        ],
-        "connect_unittests:standalone_app": [
-          "service_manager.test.mojom.StandaloneApp"
-        ],
-        "connect_unittests:identity_test":[
-          "service_manager.test.mojom.IdentityTest"
-        ]
-      },
-      "requires": {
-        "connect_unittests": [ "connect_unittests:exposed_interface" ],
-        "connect_test_class_app": [ "connect_unittests:class" ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/connect/connect_test_app_b_manifest.json b/services/service_manager/tests/connect/connect_test_app_b_manifest.json
deleted file mode 100644
index 1ea8da5..0000000
--- a/services/service_manager/tests/connect/connect_test_app_b_manifest.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "connect_test_b",
-  "display_name": "Connect Test B",
-  "interface_provider_specs": { }
-}
diff --git a/services/service_manager/tests/connect/connect_test_app_manifest.json b/services/service_manager/tests/connect/connect_test_app_manifest.json
deleted file mode 100644
index 4182e52..0000000
--- a/services/service_manager/tests/connect/connect_test_app_manifest.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
-  "name": "connect_test_app",
-  "display_name": "Connect Test App",
-  "options": { "can_connect_to_other_services_as_any_user": true },
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "connect_unittests:connect_test_service": [
-          "service_manager.test.mojom.ConnectTestService"
-        ],
-        "connect_unittests:standalone_app": [
-          "service_manager.test.mojom.StandaloneApp"
-        ],
-        "connect_unittests:identity_test": [
-          "service_manager.test.mojom.IdentityTest"
-        ]
-      },
-      "requires": {
-        "connect_unittests": [ "connect_unittests:exposed_interface" ],
-        "connect_test_a": [ "connect_unittests:connect_test_service" ],
-        "connect_test_class_app": [
-          "connect_unittests:class",
-          "connect_unittests:connect_test_service"
-        ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/connect/connect_test_class_app.cc b/services/service_manager/tests/connect/connect_test_class_app.cc
index 7c4a4fe..d895df0 100644
--- a/services/service_manager/tests/connect/connect_test_class_app.cc
+++ b/services/service_manager/tests/connect/connect_test_class_app.cc
@@ -15,7 +15,7 @@
 #include "services/service_manager/public/cpp/service_keepalive.h"
 #include "services/service_manager/public/mojom/connector.mojom.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/connect/connect_test.mojom.h"
+#include "services/service_manager/tests/connect/connect.test-mojom.h"
 
 namespace service_manager {
 
diff --git a/services/service_manager/tests/connect/connect_test_class_app_manifest.json b/services/service_manager/tests/connect/connect_test_class_app_manifest.json
deleted file mode 100644
index f0be8b4..0000000
--- a/services/service_manager/tests/connect/connect_test_class_app_manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "name": "connect_test_class_app",
-  "display_name": "Connect Test Class App",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "connect_unittests:class": [ "service_manager.test.mojom.ClassInterface" ],
-        "connect_unittests:connect_test_service": [
-          "service_manager.test.mojom.ConnectTestService"
-        ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/connect/connect_test_exe.cc b/services/service_manager/tests/connect/connect_test_exe.cc
index 8d9e567a..836401f2 100644
--- a/services/service_manager/tests/connect/connect_test_exe.cc
+++ b/services/service_manager/tests/connect/connect_test_exe.cc
@@ -12,7 +12,7 @@
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/connect/connect_test.mojom.h"
+#include "services/service_manager/tests/connect/connect.test-mojom.h"
 
 using service_manager::test::mojom::ConnectTestService;
 using service_manager::test::mojom::ConnectTestServiceRequest;
diff --git a/services/service_manager/tests/connect/connect_test_exe_manifest.json b/services/service_manager/tests/connect/connect_test_exe_manifest.json
deleted file mode 100644
index 9498362..0000000
--- a/services/service_manager/tests/connect/connect_test_exe_manifest.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "name": "connect_test_exe",
-  "display_name": "Connect Test Exe",
-  "interface_provider_specs": { }
-}
diff --git a/services/service_manager/tests/connect/connect_test_package.cc b/services/service_manager/tests/connect/connect_test_package.cc
index 2150f2b..998aabac 100644
--- a/services/service_manager/tests/connect/connect_test_package.cc
+++ b/services/service_manager/tests/connect/connect_test_package.cc
@@ -21,7 +21,7 @@
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service_factory.mojom.h"
-#include "services/service_manager/tests/connect/connect_test.mojom.h"
+#include "services/service_manager/tests/connect/connect.test-mojom.h"
 
 // Tests that multiple services can be packaged in a single service by
 // implementing ServiceFactory; that these services can be specified by
diff --git a/services/service_manager/tests/connect/connect_test_package_manifest.json b/services/service_manager/tests/connect/connect_test_package_manifest.json
deleted file mode 100644
index 646ad07..0000000
--- a/services/service_manager/tests/connect/connect_test_package_manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "name": "connect_test_package",
-  "display_name": "Connect Test Package",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "connect_unittests:connect_test_service": [
-          "service_manager.test.mojom.ConnectTestService"
-        ],
-        "service_manager:service_factory": [
-          "service_manager.mojom.ServiceFactory"
-        ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/connect/connect_test_sandboxed_app_manifest.json b/services/service_manager/tests/connect/connect_test_sandboxed_app_manifest.json
deleted file mode 100644
index 8e316c1..0000000
--- a/services/service_manager/tests/connect/connect_test_sandboxed_app_manifest.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-  "name": "connect_test_sandboxed_app",
-  "display_name": "Sandboxed Connect Test App",
-  "sandbox_type": "superduper",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-    }
-  }
-}
diff --git a/services/service_manager/tests/connect/connect_test_singleton_app_manifest.json b/services/service_manager/tests/connect/connect_test_singleton_app_manifest.json
deleted file mode 100644
index e63f5a6..0000000
--- a/services/service_manager/tests/connect/connect_test_singleton_app_manifest.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-  "name": "connect_test_singleton_app",
-  "display_name": "Connect Test Singleton App",
-  "options": {
-    "instance_sharing" : "shared_instance_across_users"
-  },
-  "interface_provider_specs": {
-    "service_manager:connector" : {
-    }
-  }
-}
diff --git a/services/service_manager/tests/connect/connect_unittest.cc b/services/service_manager/tests/connect/connect_unittest.cc
index b72cb060..3df8bffd 100644
--- a/services/service_manager/tests/connect/connect_unittest.cc
+++ b/services/service_manager/tests/connect/connect_unittest.cc
@@ -7,13 +7,16 @@
 
 #include <memory>
 #include <utility>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/guid.h"
 #include "base/macros.h"
+#include "base/no_destructor.h"
 #include "base/optional.h"
 #include "base/process/process.h"
 #include "base/run_loop.h"
+#include "base/strings/strcat.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/gtest_util.h"
 #include "base/test/scoped_task_environment.h"
@@ -22,12 +25,14 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/constants.h"
+#include "services/service_manager/public/cpp/manifest.h"
+#include "services/service_manager/public/cpp/manifest_builder.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/test/test_service_manager.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
 #include "services/service_manager/public/mojom/service_manager.mojom.h"
-#include "services/service_manager/tests/catalog_source.h"
-#include "services/service_manager/tests/connect/connect_test.mojom.h"
+#include "services/service_manager/tests/connect/connect.test-mojom.h"
 #include "services/service_manager/tests/util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -42,6 +47,7 @@
 const char kTestServiceName[] = "connect_unittests";
 const char kTestPackageName[] = "connect_test_package";
 const char kTestAppName[] = "connect_test_app";
+const char kTestExeName[] = "connect_test_exe";
 const char kTestAppAName[] = "connect_test_a";
 const char kTestAppBName[] = "connect_test_b";
 const char kTestNonexistentAppName[] = "connect_test_nonexistent_app";
@@ -49,6 +55,107 @@
 const char kTestClassAppName[] = "connect_test_class_app";
 const char kTestSingletonAppName[] = "connect_test_singleton_app";
 
+const char kIdentityTestCapability[] = "identity_test";
+const char kConnectTestServiceCapability[] = "connect_test_service";
+const char kStandaloneAppControlCapability[] = "standalone_app_control";
+
+const char kConnectClassCapability[] = "connect_class";
+const char kExposedInterfaceCapability[] = "exposed_interface";
+
+const std::vector<Manifest>& GetTestManifests() {
+  static base::NoDestructor<std::vector<Manifest>> manifests{
+      {ManifestBuilder()
+           .WithServiceName(kTestAppName)
+           .WithOptions(ManifestOptionsBuilder()
+                            .CanConnectToInstancesInAnyGroup(true)
+                            .Build())
+           .ExposeCapability(
+               kIdentityTestCapability,
+               Manifest::InterfaceList<test::mojom::IdentityTest>())
+           .ExposeCapability(
+               kConnectTestServiceCapability,
+               Manifest::InterfaceList<test::mojom::ConnectTestService>())
+           .ExposeCapability(
+               kStandaloneAppControlCapability,
+               Manifest::InterfaceList<test::mojom::StandaloneApp>())
+           .RequireCapability(kTestClassAppName, kConnectClassCapability)
+           .RequireCapability(kTestClassAppName, kConnectTestServiceCapability)
+           .RequireCapability(kTestServiceName, kExposedInterfaceCapability)
+           .RequireCapability(kTestAppAName, kConnectTestServiceCapability)
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName(kTestClassAppName)
+           .ExposeCapability(
+               kConnectClassCapability,
+               Manifest::InterfaceList<test::mojom::ClassInterface>())
+           .ExposeCapability(
+               kConnectTestServiceCapability,
+               Manifest::InterfaceList<test::mojom::ConnectTestService>())
+           .Build(),
+       ManifestBuilder().WithServiceName(kTestExeName).Build(),
+       ManifestBuilder()
+           .WithServiceName(kTestPackageName)
+           .ExposeCapability("service_manager:service_factory",
+                             Manifest::InterfaceList<mojom::ServiceFactory>())
+           .ExposeCapability(
+               kConnectTestServiceCapability,
+               Manifest::InterfaceList<test::mojom::ConnectTestService>())
+           .PackageService(
+               ManifestBuilder()
+                   .WithServiceName(kTestAppAName)
+                   .ExposeCapability(
+                       kIdentityTestCapability,
+                       Manifest::InterfaceList<test::mojom::IdentityTest>())
+                   .ExposeCapability(kConnectTestServiceCapability,
+                                     Manifest::InterfaceList<
+                                         test::mojom::ConnectTestService>())
+                   .ExposeCapability(
+                       kStandaloneAppControlCapability,
+                       Manifest::InterfaceList<test::mojom::StandaloneApp>())
+                   .RequireCapability(kTestClassAppName,
+                                      kConnectClassCapability)
+                   .RequireCapability(kTestServiceName,
+                                      kExposedInterfaceCapability)
+                   .Build())
+           .PackageService(
+               ManifestBuilder().WithServiceName(kTestAppBName).Build())
+           .PackageService(ManifestBuilder()
+                               .WithServiceName(kTestSandboxedAppName)
+                               .WithOptions(ManifestOptionsBuilder()
+                                                .WithSandboxType("superduper")
+                                                .Build())
+                               .Build())
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName(kTestSingletonAppName)
+           .WithOptions(ManifestOptionsBuilder()
+                            .WithInstanceSharingPolicy(
+                                service_manager::Manifest::
+                                    InstanceSharingPolicy::kSharedAcrossGroups)
+                            .Build())
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName(kTestServiceName)
+           .WithOptions(ManifestOptionsBuilder()
+                            .CanConnectToInstancesInAnyGroup(true)
+                            .CanConnectToInstancesWithAnyId(true)
+                            .Build())
+           .ExposeCapability(
+               kExposedInterfaceCapability,
+               Manifest::InterfaceList<test::mojom::ExposedInterface>())
+           .RequireCapability(kTestSingletonAppName, "")
+           .RequireCapability(kTestAppName, kConnectTestServiceCapability)
+           .RequireCapability(kTestAppName, kStandaloneAppControlCapability)
+           .RequireCapability(kTestAppName, kIdentityTestCapability)
+           .RequireCapability(kTestAppAName, kConnectTestServiceCapability)
+           .RequireCapability(kTestAppAName, kStandaloneAppControlCapability)
+           .RequireCapability(kTestAppAName, kIdentityTestCapability)
+           .RequireCapability(kTestPackageName, kConnectTestServiceCapability)
+           .Build()}};
+
+  return *manifests;
+}
+
 void ReceiveOneString(std::string* out_string,
                       base::RunLoop* loop,
                       const std::string& in_string) {
@@ -151,7 +258,7 @@
                     public Service,
                     public test::mojom::ExposedInterface {
  public:
-  ConnectTest() : test_service_manager_(test::CreateTestCatalog()) {}
+  ConnectTest() : test_service_manager_(GetTestManifests()) {}
   ~ConnectTest() override = default;
 
   Connector* connector() { return service_binding_.GetConnector(); }
@@ -540,11 +647,11 @@
   mojom::ConnectResult result =
       service_manager::test::LaunchAndConnectToProcess(
 #if defined(OS_WIN)
-          "connect_test_exe.exe",
+          base::StrCat({kTestExeName, ".exe"}),
 #else
-          "connect_test_exe",
+          kTestExeName,
 #endif
-          service_manager::Identity("connect_test_exe", kSystemInstanceGroup,
+          service_manager::Identity(kTestExeName, kSystemInstanceGroup,
                                     base::Token{}, base::Token::CreateRandom()),
           connector(), &process);
   EXPECT_EQ(result, mojom::ConnectResult::ACCESS_DENIED);
diff --git a/services/service_manager/tests/connect/connect_unittests_manifest.json b/services/service_manager/tests/connect/connect_unittests_manifest.json
deleted file mode 100644
index 1cb8b86..0000000
--- a/services/service_manager/tests/connect/connect_unittests_manifest.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-  "name": "connect_unittests",
-  "display_name": "Connect Unittests",
-  "options": {
-    "can_connect_to_other_services_as_any_user": true,
-    "can_connect_to_other_services_with_any_instance_name": true
-  },
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "connect_unittests:exposed_interface": [
-          "service_manager.test.mojom.ExposedInterface"
-        ]
-      },
-      "requires": {
-        "connect_test_package": [
-          "connect_unittests:connect_test_service"
-        ],
-        "connect_test_app": [
-          "connect_unittests:connect_test_service",
-          "connect_unittests:standalone_app",
-          "connect_unittests:identity_test"
-        ],
-        "connect_test_driver": [
-          "connect_unittests:client_process_test"
-        ],
-        "connect_test_a": [
-          "connect_unittests:connect_test_service",
-          "connect_unittests:standalone_app",
-          "connect_unittests:identity_test"
-        ],
-        "connect_test_singleton_app": []
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/lifecycle/BUILD.gn b/services/service_manager/tests/lifecycle/BUILD.gn
index 34aa4429..0aac78ee 100644
--- a/services/service_manager/tests/lifecycle/BUILD.gn
+++ b/services/service_manager/tests/lifecycle/BUILD.gn
@@ -30,12 +30,14 @@
 }
 
 mojom("interfaces") {
+  testonly = true
   sources = [
-    "lifecycle_unittest.mojom",
+    "lifecycle.test-mojom",
   ]
 }
 
 source_set("app_client") {
+  testonly = true
   sources = [
     "app_client.cc",
     "app_client.h",
diff --git a/services/service_manager/tests/lifecycle/OWNERS b/services/service_manager/tests/lifecycle/OWNERS
deleted file mode 100644
index 08850f4..0000000
--- a/services/service_manager/tests/lifecycle/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/tests/lifecycle/app_client.h b/services/service_manager/tests/lifecycle/app_client.h
index 213fe67..629b126 100644
--- a/services/service_manager/tests/lifecycle/app_client.h
+++ b/services/service_manager/tests/lifecycle/app_client.h
@@ -15,7 +15,7 @@
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/lifecycle/lifecycle_unittest.mojom.h"
+#include "services/service_manager/tests/lifecycle/lifecycle.test-mojom.h"
 
 namespace service_manager {
 namespace test {
diff --git a/services/service_manager/tests/lifecycle/lifecycle_unittest.mojom b/services/service_manager/tests/lifecycle/lifecycle.test-mojom
similarity index 100%
rename from services/service_manager/tests/lifecycle/lifecycle_unittest.mojom
rename to services/service_manager/tests/lifecycle/lifecycle.test-mojom
diff --git a/services/service_manager/tests/lifecycle/lifecycle_unittest.cc b/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
index e5e92ce..b78d4a8 100644
--- a/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
+++ b/services/service_manager/tests/lifecycle/lifecycle_unittest.cc
@@ -27,7 +27,7 @@
 #include "services/service_manager/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/mojom/service_factory.mojom.h"
 #include "services/service_manager/public/mojom/service_manager.mojom.h"
-#include "services/service_manager/tests/lifecycle/lifecycle_unittest.mojom.h"
+#include "services/service_manager/tests/lifecycle/lifecycle.test-mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace service_manager {
diff --git a/services/service_manager/tests/lifecycle/package.cc b/services/service_manager/tests/lifecycle/package.cc
index b481f2c..f0777e21 100644
--- a/services/service_manager/tests/lifecycle/package.cc
+++ b/services/service_manager/tests/lifecycle/package.cc
@@ -14,7 +14,7 @@
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service_factory.mojom.h"
 #include "services/service_manager/tests/lifecycle/app_client.h"
-#include "services/service_manager/tests/lifecycle/lifecycle_unittest.mojom.h"
+#include "services/service_manager/tests/lifecycle/lifecycle.test-mojom.h"
 
 namespace {
 
diff --git a/services/service_manager/tests/lifecycle/parent.cc b/services/service_manager/tests/lifecycle/parent.cc
index e7a5722..3246e82 100644
--- a/services/service_manager/tests/lifecycle/parent.cc
+++ b/services/service_manager/tests/lifecycle/parent.cc
@@ -14,7 +14,7 @@
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/lifecycle/lifecycle_unittest.mojom.h"
+#include "services/service_manager/tests/lifecycle/lifecycle.test-mojom.h"
 
 namespace {
 
diff --git a/services/service_manager/tests/service_manager/BUILD.gn b/services/service_manager/tests/service_manager/BUILD.gn
index ba34c4e..29de43a 100644
--- a/services/service_manager/tests/service_manager/BUILD.gn
+++ b/services/service_manager/tests/service_manager/BUILD.gn
@@ -3,9 +3,7 @@
 # found in the LICENSE file.
 
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//services/catalog/public/tools/catalog.gni")
 import("//services/service_manager/public/cpp/service_executable.gni")
-import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 source_set("service_manager") {
@@ -17,6 +15,7 @@
 
   deps = [
     ":interfaces",
+    ":test_manifests",
     "//base",
     "//base/test:test_config",
     "//base/test:test_support",
@@ -27,7 +26,6 @@
     "//services/service_manager/public/cpp/test:test_support",
     "//services/service_manager/public/mojom",
     "//services/service_manager/runner/common",
-    "//services/service_manager/tests:catalog_source",
     "//testing/gtest",
   ]
 
@@ -38,8 +36,9 @@
 }
 
 mojom("interfaces") {
+  testonly = true
   sources = [
-    "service_manager_unittest.mojom",
+    "service_manager.test-mojom",
   ]
 
   deps = [
@@ -47,9 +46,18 @@
   ]
 }
 
-service_manifest("manifest") {
-  name = "service_manager_unittest"
-  source = "service_manager_unittest_manifest.json"
+source_set("test_manifests") {
+  testonly = true
+  sources = [
+    "test_manifests.cc",
+    "test_manifests.h",
+  ]
+  deps = [
+    ":interfaces",
+    "//base",
+    "//services/service_manager/public/cpp",
+    "//services/service_manager/public/mojom",
+  ]
 }
 
 executable("service_manager_unittest_target") {
@@ -61,6 +69,7 @@
 
   deps = [
     ":interfaces",
+    ":test_manifests",
     "//base",
     "//build/win:default_exe_manifest",
     "//services/service_manager/public/cpp",
@@ -68,36 +77,6 @@
   ]
 }
 
-service_manifest("target_manifest") {
-  name = "service_manager_unittest_target"
-  source = "target_manifest.json"
-}
-
-service_manifest("embedder_manifest") {
-  name = "service_manager_unittest_embedder"
-  source = "embedder_manifest.json"
-  packaged_services = [
-    ":shared_instance_across_users_manifest",
-    ":regular_manifest",
-    ":singleton_manifest",
-  ]
-}
-
-service_manifest("shared_instance_across_users_manifest") {
-  name = "service_manager_unittest_shared_instance_across_users"
-  source = "shared_instance_across_users_manifest.json"
-}
-
-service_manifest("singleton_manifest") {
-  name = "service_manager_unittest_singleton"
-  source = "singleton_manifest.json"
-}
-
-service_manifest("regular_manifest") {
-  name = "service_manager_unittest_regular"
-  source = "regular_manifest.json"
-}
-
 service_executable("service_manager_unittest_embedder") {
   testonly = true
   sources = [
@@ -106,6 +85,7 @@
 
   deps = [
     ":interfaces",
+    ":test_manifests",
     "//base",
     "//build/win:default_exe_manifest",
     "//services/service_manager/public/cpp",
@@ -114,12 +94,3 @@
     "//services/service_manager/runner/common",
   ]
 }
-
-catalog("catalog") {
-  embedded_services = [ ":manifest" ]
-
-  standalone_services = [
-    ":embedder_manifest",
-    ":target_manifest",
-  ]
-}
diff --git a/services/service_manager/tests/service_manager/OWNERS b/services/service_manager/tests/service_manager/OWNERS
deleted file mode 100644
index a0396007..0000000
--- a/services/service_manager/tests/service_manager/OWNERS
+++ /dev/null
@@ -1,20 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file embedder_manifest.json=set noparent
-per-file embedder_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file service_manager_unittest_manifest.json=set noparent
-per-file service_manager_unittest_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file regular_manifest.json=set noparent
-per-file regular_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file singleton_manifest.json=set noparent
-per-file singleton_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file target_manifest.json=set noparent
-per-file target_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file shared_instance_across_users_manifest.json=set noparent
-per-file shared_instance_across_users_manifest.json=file://ipc/SECURITY_OWNERS
\ No newline at end of file
diff --git a/services/service_manager/tests/service_manager/embedder.cc b/services/service_manager/tests/service_manager/embedder.cc
index 7fc5a6d..7b8d817 100644
--- a/services/service_manager/tests/service_manager/embedder.cc
+++ b/services/service_manager/tests/service_manager/embedder.cc
@@ -13,6 +13,7 @@
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
 #include "services/service_manager/public/mojom/service_factory.mojom.h"
+#include "services/service_manager/tests/service_manager/test_manifests.h"
 
 namespace {
 
@@ -56,12 +57,12 @@
       service_manager::mojom::ServiceRequest request,
       const std::string& name,
       service_manager::mojom::PIDReceiverPtr pid_receiver) override {
-    if (name == "service_manager_unittest_shared_instance_across_users" ||
-        name == "service_manager_unittest_singleton" ||
-        name == "service_manager_unittest_regular") {
+    if (name == service_manager::kTestRegularServiceName ||
+        name == service_manager::kTestSharedServiceName ||
+        name == service_manager::kTestSingletonServiceName) {
       packaged_service_ = std::make_unique<PackagedService>(std::move(request));
     } else {
-      LOG(ERROR) << "Failed to create unknow service " << name;
+      LOG(ERROR) << "Failed to create unknown service " << name;
     }
   }
 
diff --git a/services/service_manager/tests/service_manager/embedder_manifest.json b/services/service_manager/tests/service_manager/embedder_manifest.json
deleted file mode 100644
index 2b284472..0000000
--- a/services/service_manager/tests/service_manager/embedder_manifest.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-  "name": "service_manager_unittest_embedder",
-  "display_name": "Service Manager Unittest: Embedder",
-  "options": {
-    "instance_sharing" : "singleton"
-  },
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "service_manager_unittest:embedder": [ ],
-        "service_manager:service_factory": [
-          "service_manager.mojom.ServiceFactory"
-        ]
-      },
-      "requires": {
-        "service_manager_unittest_target": [ ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/service_manager/regular_manifest.json b/services/service_manager/tests/service_manager/regular_manifest.json
deleted file mode 100644
index 40f03f107..0000000
--- a/services/service_manager/tests/service_manager/regular_manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "service_manager_unittest_regular",
-  "display_name": "Service Manager Unittest: Regular",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "service_manager_unittest:regular": [ ]
-      },
-      "requires": {
-        "service_manager_unittest_target": [ ],
-        "service_manager": [ ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/service_manager/service_manager_unittest.mojom b/services/service_manager/tests/service_manager/service_manager.test-mojom
similarity index 100%
rename from services/service_manager/tests/service_manager/service_manager_unittest.mojom
rename to services/service_manager/tests/service_manager/service_manager.test-mojom
diff --git a/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc b/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc
index 937563cb..e922c84 100644
--- a/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc
+++ b/services/service_manager/tests/service_manager/service_manager_listener_unittest.cc
@@ -18,17 +18,12 @@
 #include "services/service_manager/public/mojom/service.mojom.h"
 #include "services/service_manager/public/mojom/service_manager.mojom.h"
 #include "services/service_manager/service_manager.h"
-#include "services/service_manager/tests/catalog_source.h"
+#include "services/service_manager/tests/service_manager/test_manifests.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace service_manager {
 namespace {
 
-// These constants reflect service names in test service manifests within the
-// default catalog for service_unittests.
-const char kTestServiceName[] = "service_manager_unittest";
-const char kTestTargetServiceName[] = "service_manager_unittest_target";
-
 constexpr uint32_t kTestSelfPid = 1234;
 constexpr uint32_t kTestTargetPid1 = 4567;
 constexpr uint32_t kTestTargetPid2 = 8910;
@@ -108,7 +103,7 @@
 class ServiceManagerListenerTest : public testing::Test, public Service {
  public:
   ServiceManagerListenerTest()
-      : service_manager_(nullptr, test::CreateTestCatalog(), nullptr) {}
+      : service_manager_(nullptr, GetTestManifests(), nullptr) {}
   ~ServiceManagerListenerTest() override = default;
 
   Connector* connector() { return service_binding_.GetConnector(); }
@@ -155,12 +150,12 @@
 
 TEST_F(ServiceManagerListenerTest, InstancesHaveUniqueIdentity) {
   TestTargetService target1(
-      RegisterServiceInstance(kTestTargetServiceName, kTestTargetPid1));
+      RegisterServiceInstance(kTestTargetName, kTestTargetPid1));
 
   Identity identity1;
   uint32_t pid1;
   WaitForServiceStarted(&identity1, &pid1);
-  EXPECT_EQ(kTestTargetServiceName, identity1.name());
+  EXPECT_EQ(kTestTargetName, identity1.name());
   EXPECT_FALSE(identity1.globally_unique_id().is_zero());
   EXPECT_EQ(kTestTargetPid1, pid1);
 
@@ -173,12 +168,12 @@
   target1.QuitGracefullyAndWait();
 
   TestTargetService target2(
-      RegisterServiceInstance(kTestTargetServiceName, kTestTargetPid2));
+      RegisterServiceInstance(kTestTargetName, kTestTargetPid2));
 
   Identity identity2;
   uint32_t pid2;
   WaitForServiceStarted(&identity2, &pid2);
-  EXPECT_EQ(kTestTargetServiceName, identity2.name());
+  EXPECT_EQ(kTestTargetName, identity2.name());
   EXPECT_FALSE(identity2.globally_unique_id().is_zero());
   EXPECT_EQ(kTestTargetPid2, pid2);
 
diff --git a/services/service_manager/tests/service_manager/service_manager_unittest.cc b/services/service_manager/tests/service_manager/service_manager_unittest.cc
index a7d5cec..78f09fc 100644
--- a/services/service_manager/tests/service_manager/service_manager_unittest.cc
+++ b/services/service_manager/tests/service_manager/service_manager_unittest.cc
@@ -34,8 +34,8 @@
 #include "services/service_manager/public/cpp/test/test_service_manager.h"
 #include "services/service_manager/public/mojom/service_manager.mojom.h"
 #include "services/service_manager/runner/common/client_util.h"
-#include "services/service_manager/tests/catalog_source.h"
-#include "services/service_manager/tests/service_manager/service_manager_unittest.mojom.h"
+#include "services/service_manager/tests/service_manager/service_manager.test-mojom.h"
+#include "services/service_manager/tests/service_manager/test_manifests.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace service_manager {
@@ -151,9 +151,9 @@
                            public mojom::ServiceManagerListener {
  public:
   ServiceManagerTest()
-      : test_service_manager_(test::CreateTestCatalog()),
-        test_service_(test_service_manager_.RegisterTestInstance(
-            "service_manager_unittest")) {}
+      : test_service_manager_(GetTestManifests()),
+        test_service_(
+            test_service_manager_.RegisterTestInstance(kTestServiceName)) {}
   ~ServiceManagerTest() override = default;
 
  protected:
@@ -243,11 +243,10 @@
     CHECK(base::PathService::Get(base::DIR_ASSETS, &target_path));
 
 #if defined(OS_WIN)
-    target_path = target_path.Append(
-        FILE_PATH_LITERAL("service_manager_unittest_target.exe"));
+    target_path =
+        target_path.AppendASCII(kTestTargetName).AddExtensionASCII("exe");
 #else
-    target_path = target_path.Append(
-        FILE_PATH_LITERAL("service_manager_unittest_target"));
+    target_path = target_path.Append(FILE_PATH_LITERAL(kTestTargetName));
 #endif
 
     base::CommandLine child_command_line(target_path);
@@ -270,9 +269,8 @@
                                                          &child_command_line);
     service_manager::mojom::PIDReceiverPtr receiver;
     connector()->RegisterServiceInstance(
-        service_manager::Identity("service_manager_unittest_target",
-                                  kSystemInstanceGroup, base::Token{},
-                                  base::Token::CreateRandom()),
+        service_manager::Identity(kTestTargetName, kSystemInstanceGroup,
+                                  base::Token{}, base::Token::CreateRandom()),
         std::move(client), mojo::MakeRequest(&receiver));
 
     target_ = base::LaunchProcess(child_command_line, options);
@@ -294,12 +292,12 @@
     set_service_failed_to_start_callback(base::BindRepeating(
         &OnServiceFailedToStartCallback, &failed_to_start, loop.QuitClosure()));
 
-    connector()->WarmService(service_manager::ServiceFilter::ByName(
-        "service_manager_unittest_embedder"));
+    connector()->WarmService(
+        service_manager::ServiceFilter::ByName(kTestEmbedderName));
     loop.Run();
     EXPECT_FALSE(failed_to_start);
     EXPECT_EQ(1, start_count);
-    EXPECT_EQ("service_manager_unittest_embedder", service_name);
+    EXPECT_EQ(kTestEmbedderName, service_name);
   }
 
   void StartService(const ServiceFilter& filter, bool expect_service_started) {
@@ -409,7 +407,7 @@
 
   // 3. Validate that this test suite's name was received from the application
   //    manager.
-  EXPECT_TRUE(ContainsInstanceWithName("service_manager_unittest"));
+  EXPECT_TRUE(ContainsInstanceWithName(kTestServiceName));
 
   // 4. Validate that the right applications/processes were created.
   //    Note that the target process will be created even if the tests are
@@ -419,8 +417,7 @@
     auto& instance = instances().back();
     // We learn about the target process id via a ping from it.
     EXPECT_EQ(target_identity(), instance.identity);
-    EXPECT_EQ("service_manager_unittest_target",
-              instance.identity.name());
+    EXPECT_EQ(kTestTargetName, instance.identity.name());
     EXPECT_NE(base::kNullProcessId, instance.pid);
   }
 
@@ -431,14 +428,12 @@
 // the service again, a new service is created unless the same user ID and
 // instance names are used.
 TEST_F(ServiceManagerTest, CreatePackagedRegularInstances) {
-  constexpr char kRegularServiceName[] = "service_manager_unittest_regular";
-
   AddListenerAndWaitForApplications();
 
   // Connect to the embedder service first.
   StartEmbedderService();
 
-  auto filter = ServiceFilter::ByName(kRegularServiceName);
+  auto filter = ServiceFilter::ByName(kTestRegularServiceName);
   StartService(filter, /*expect_service_started=*/true);
 
   // Retstarting with the same identity reuses the existing service.
@@ -446,65 +441,61 @@
 
   // Starting with a different instance group creates a new service.
   auto other_group_filter = ServiceFilter::ByNameInGroup(
-      kRegularServiceName, base::Token::CreateRandom());
+      kTestRegularServiceName, base::Token::CreateRandom());
   StartService(other_group_filter, /*expect_service_started=*/true);
 
   // Starting with a different instance ID creates a new service as well.
   auto other_id_filter =
-      ServiceFilter::ByNameWithId(kRegularServiceName, base::Token{1, 2});
+      ServiceFilter::ByNameWithId(kTestRegularServiceName, base::Token{1, 2});
   StartService(other_id_filter, /*expect_service_started=*/true);
 }
 
 // Tests that starting a shared instance packaged service works, and that when
 // starting that service again, a new service is created only when a different
 // instance name is specified.
-TEST_F(ServiceManagerTest, CreatePackagedAllUsersInstances) {
-  constexpr char kAllUsersServiceName[] =
-      "service_manager_unittest_shared_instance_across_users";
-
+TEST_F(ServiceManagerTest, CreatePackagedSharedAcrossGroupsInstances) {
   AddListenerAndWaitForApplications();
 
   // Connect to the embedder service first.
   StartEmbedderService();
 
-  auto filter = ServiceFilter::ByName(kAllUsersServiceName);
+  auto filter = ServiceFilter::ByName(kTestSharedServiceName);
   StartService(filter, /*expect_service_started=*/true);
 
   // Start again with a different instance group. The existing service should be
   // reused.
   auto other_group_filter = ServiceFilter::ByNameInGroup(
-      kAllUsersServiceName, base::Token::CreateRandom());
+      kTestSharedServiceName, base::Token::CreateRandom());
   StartService(other_group_filter, /*expect_service_started=*/false);
 
   // Start again with a difference instance ID. In that case a new service
   // should get created.
   auto other_id_filter = ServiceFilter::ByNameWithIdInGroup(
-      kAllUsersServiceName, base::Token{1, 2}, base::Token::CreateRandom());
+      kTestSharedServiceName, base::Token{1, 2}, base::Token::CreateRandom());
   StartService(other_id_filter, /*expect_service_started=*/true);
 }
 
 // Tests that creating a singleton packaged service works, and that when
 // starting that service again a new service is never created.
 TEST_F(ServiceManagerTest, CreatePackagedSingletonInstances) {
-  constexpr char kSingletonServiceName[] = "service_manager_unittest_singleton";
   AddListenerAndWaitForApplications();
 
   // Connect to the embedder service first.
   StartEmbedderService();
 
-  auto filter = ServiceFilter::ByName(kSingletonServiceName);
+  auto filter = ServiceFilter::ByName(kTestSingletonServiceName);
   StartService(filter, /*expect_service_started=*/true);
 
   // Start again with a different instance group. The existing service should be
   // reused.
   auto other_group_filter = ServiceFilter::ByNameInGroup(
-      kSingletonServiceName, base::Token::CreateRandom());
+      kTestSingletonServiceName, base::Token::CreateRandom());
   StartService(other_group_filter, /*expect_service_started=*/false);
 
   // Start again with the same instance group but a difference instance ID. The
   // existing service should still be reused.
   auto other_id_filter =
-      ServiceFilter::ByNameWithId(kSingletonServiceName, base::Token{3, 4});
+      ServiceFilter::ByNameWithId(kTestSingletonServiceName, base::Token{3, 4});
   StartService(other_id_filter, /*expect_service_started=*/false);
 }
 
@@ -522,11 +513,10 @@
     set_service_failed_to_start_callback(base::BindRepeating(
         &OnServiceFailedToStartCallback, &failed_to_start, loop.QuitClosure()));
 
-    connector()->WarmService(
-        ServiceFilter::ByName("service_manager_unittest_embedder"));
+    connector()->WarmService(ServiceFilter::ByName(kTestEmbedderName));
     loop.Run();
     EXPECT_FALSE(failed_to_start);
-    EXPECT_EQ("service_manager_unittest_embedder", service_name);
+    EXPECT_EQ(kTestEmbedderName, service_name);
     EXPECT_NE(pid, 0u);
   }
 }
@@ -534,7 +524,7 @@
 TEST_F(ServiceManagerTest, ClientProcessCapabilityEnforced) {
   AddListenerAndWaitForApplications();
 
-  const std::string kTestService = "service_manager_unittest_target";
+  const std::string kTestService = kTestTargetName;
   const Identity kInstance1Id(kTestService, kSystemInstanceGroup,
                               base::Token{1, 2}, base::Token::CreateRandom());
   const Identity kInstance2Id(kTestService, kSystemInstanceGroup,
@@ -552,7 +542,7 @@
   pid_receiver1->SetPID(42);
   WaitForInstanceToStart(kInstance1Id);
   EXPECT_EQ(1u, instances().size());
-  EXPECT_TRUE(ContainsInstanceWithName("service_manager_unittest_target"));
+  EXPECT_TRUE(ContainsInstanceWithName(kTestTargetName));
 
   // Now use the new instance (which does not have client_process capability)
   // to attempt introduction of yet another instance. This should fail.
diff --git a/services/service_manager/tests/service_manager/service_manager_unittest_manifest.json b/services/service_manager/tests/service_manager/service_manager_unittest_manifest.json
deleted file mode 100644
index a7355a4..0000000
--- a/services/service_manager/tests/service_manager/service_manager_unittest_manifest.json
+++ /dev/null
@@ -1,34 +0,0 @@
-{
-  "name": "service_manager_unittest",
-  "display_name": "Service Manager Unittest",
-  "options": {
-    "instance_sharing": "singleton",
-    "can_connect_to_other_services_with_any_instance_name": true,
-    "can_create_other_service_instances": true
-  },
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "service_manager_unittest:create_instance_test": [
-          "service_manager.test.mojom.CreateInstanceTest"
-        ]
-      },
-      "requires": {
-        "service_manager": [
-          "service_manager:service_manager"
-        ],
-        "service_manager_unittest_embedder": [
-          "service_manager_unittest:embedder"
-        ],
-        "service_manager_unittest_singleton": [
-          "service_manager_unittest:singleton"
-        ],
-        "service_manager_unittest_shared_instance_across_users": [ ],
-        "service_manager_unittest_regular": [
-          "service_manager_unittest:regular"
-        ],
-        "service_manager_unittest_target": [ ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/service_manager/shared_instance_across_users_manifest.json b/services/service_manager/tests/service_manager/shared_instance_across_users_manifest.json
deleted file mode 100644
index 2cad14f..0000000
--- a/services/service_manager/tests/service_manager/shared_instance_across_users_manifest.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "name": "service_manager_unittest_shared_instance_across_users",
-  "display_name": "Service Manager Unittest: Shared instance across users",
-  "options" : {
-    "instance_sharing" : "shared_instance_across_users"
-  },
-  "interface_provider_specs": {
-    "service_manager:connector": { }
-  }
-}
diff --git a/services/service_manager/tests/service_manager/singleton_manifest.json b/services/service_manager/tests/service_manager/singleton_manifest.json
deleted file mode 100644
index 6007bec..0000000
--- a/services/service_manager/tests/service_manager/singleton_manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "service_manager_unittest_singleton",
-  "display_name": "Service Manager Unittest: Singleton",
-  "options" : {
-    "instance_sharing" : "singleton"
-  },
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "service_manager_unittest:singleton": [ ]
-      },
-      "requires": {
-        "service_manager_unittest_target": [ ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/service_manager/target.cc b/services/service_manager/tests/service_manager/target.cc
index e1e8eb03..f7638ff 100644
--- a/services/service_manager/tests/service_manager/target.cc
+++ b/services/service_manager/tests/service_manager/target.cc
@@ -9,7 +9,8 @@
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/service_manager/service_manager_unittest.mojom.h"
+#include "services/service_manager/tests/service_manager/service_manager.test-mojom.h"
+#include "services/service_manager/tests/service_manager/test_manifests.h"
 
 namespace {
 
@@ -23,8 +24,8 @@
   // service_manager::Service:
   void OnStart() override {
     service_manager::test::mojom::CreateInstanceTestPtr service;
-    service_binding_.GetConnector()->BindInterface("service_manager_unittest",
-                                                   &service);
+    service_binding_.GetConnector()->BindInterface(
+        service_manager::kTestServiceName, &service);
     service->SetTargetIdentity(service_binding_.identity());
   }
 
diff --git a/services/service_manager/tests/service_manager/target_manifest.json b/services/service_manager/tests/service_manager/target_manifest.json
deleted file mode 100644
index ff8696cd..0000000
--- a/services/service_manager/tests/service_manager/target_manifest.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "name": "service_manager_unittest_target",
-  "display_name": "Service Manager Unittest: Target",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "requires": {
-        "service_manager_unittest": [
-          "service_manager_unittest:create_instance_test"
-        ],
-        "service_manager_unittest_target": []
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/service_manager/test_manifests.cc b/services/service_manager/tests/service_manager/test_manifests.cc
new file mode 100644
index 0000000..585d7bd
--- /dev/null
+++ b/services/service_manager/tests/service_manager/test_manifests.cc
@@ -0,0 +1,88 @@
+// 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 "services/service_manager/tests/service_manager/test_manifests.h"
+
+#include "base/no_destructor.h"
+#include "services/service_manager/public/cpp/manifest_builder.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
+#include "services/service_manager/tests/service_manager/service_manager.test-mojom.h"
+
+namespace service_manager {
+
+const char kTestServiceName[] = "service_manager_unittest";
+const char kTestTargetName[] = "service_manager_unittest_target";
+const char kTestEmbedderName[] = "service_manager_unittest_embedder";
+const char kTestRegularServiceName[] = "service_manager_unittest_regular";
+const char kTestSharedServiceName[] =
+    "service_manager_unittest_shared_across_groups";
+const char kTestSingletonServiceName[] = "service_manager_unittest_singleton";
+
+const char kCreateInstanceTestCapability[] = "create_instance_test";
+
+const std::vector<Manifest>& GetTestManifests() {
+  static base::NoDestructor<std::vector<Manifest>> manifests{
+      {ManifestBuilder()
+           .WithServiceName(kTestEmbedderName)
+           .WithOptions(ManifestOptionsBuilder()
+                            .WithInstanceSharingPolicy(
+                                Manifest::InstanceSharingPolicy::kSingleton)
+                            .Build())
+           .ExposeCapability("service_manager:service_factory",
+                             Manifest::InterfaceList<mojom::ServiceFactory>())
+           .RequireCapability(kTestTargetName, "")
+           .PackageService(ManifestBuilder()
+                               .WithServiceName(kTestRegularServiceName)
+                               .RequireCapability(kTestTargetName, "")
+                               .RequireCapability(mojom::kServiceName, "")
+                               .Build())
+           .PackageService(
+               ManifestBuilder()
+                   .WithServiceName(kTestSharedServiceName)
+                   .WithOptions(ManifestOptionsBuilder()
+                                    .WithInstanceSharingPolicy(
+                                        Manifest::InstanceSharingPolicy::
+                                            kSharedAcrossGroups)
+                                    .Build())
+                   .Build())
+           .PackageService(
+               ManifestBuilder()
+                   .WithServiceName(kTestSingletonServiceName)
+                   .WithOptions(
+                       ManifestOptionsBuilder()
+                           .WithInstanceSharingPolicy(
+                               Manifest::InstanceSharingPolicy::kSingleton)
+                           .Build())
+                   .RequireCapability(kTestTargetName, "")
+                   .Build())
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName("service_manager_unittest")
+           .WithOptions(ManifestOptionsBuilder()
+                            .WithInstanceSharingPolicy(
+                                Manifest::InstanceSharingPolicy::kSingleton)
+                            .CanConnectToInstancesWithAnyId(true)
+                            .CanRegisterOtherServiceInstances(true)
+                            .Build())
+           .ExposeCapability(
+               kCreateInstanceTestCapability,
+               Manifest::InterfaceList<test::mojom::CreateInstanceTest>())
+           .RequireCapability(kTestTargetName, "")
+           .RequireCapability(kTestEmbedderName, "")
+           .RequireCapability(kTestSharedServiceName, "")
+           .RequireCapability(kTestSingletonServiceName, "")
+           .RequireCapability(kTestRegularServiceName, "")
+           .RequireCapability(mojom::kServiceName,
+                              "service_manager:service_manager")
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName(kTestTargetName)
+           .RequireCapability(kTestTargetName, "")
+           .RequireCapability(kTestServiceName, kCreateInstanceTestCapability)
+           .Build()}};
+  return *manifests;
+}
+
+}  // namespace service_manager
diff --git a/services/service_manager/tests/service_manager/test_manifests.h b/services/service_manager/tests/service_manager/test_manifests.h
new file mode 100644
index 0000000..bef8ea1
--- /dev/null
+++ b/services/service_manager/tests/service_manager/test_manifests.h
@@ -0,0 +1,25 @@
+// 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 SERVICES_SERVICE_MANAGER_TESTS_SERVICE_MANAGER_TEST_MANIFESTS_H_
+#define SERVICES_SERVICE_MANAGER_TESTS_SERVICE_MANAGER_TEST_MANIFESTS_H_
+
+#include <vector>
+
+#include "services/service_manager/public/cpp/manifest.h"
+
+namespace service_manager {
+
+extern const char kTestServiceName[];
+extern const char kTestTargetName[];
+extern const char kTestEmbedderName[];
+extern const char kTestRegularServiceName[];
+extern const char kTestSharedServiceName[];
+extern const char kTestSingletonServiceName[];
+
+const std::vector<Manifest>& GetTestManifests();
+
+}  // namespace service_manager
+
+#endif  // SERVICES_SERVICE_MANAGER_TESTS_SERVICE_MANAGER_TEST_MANIFESTS_H_
diff --git a/services/service_manager/tests/shutdown/BUILD.gn b/services/service_manager/tests/shutdown/BUILD.gn
index 007691d..249b590a 100644
--- a/services/service_manager/tests/shutdown/BUILD.gn
+++ b/services/service_manager/tests/shutdown/BUILD.gn
@@ -3,9 +3,7 @@
 # found in the LICENSE file.
 
 import("//mojo/public/tools/bindings/mojom.gni")
-import("//services/catalog/public/tools/catalog.gni")
 import("//services/service_manager/public/cpp/service_executable.gni")
-import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 
 source_set("shutdown") {
@@ -24,7 +22,6 @@
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp/test:test_support",
     "//services/service_manager/public/mojom",
-    "//services/service_manager/tests:catalog_source",
     "//testing/gtest",
   ]
 
@@ -35,21 +32,12 @@
 }
 
 mojom("interfaces") {
+  testonly = true
   sources = [
-    "shutdown_unittest.mojom",
+    "shutdown.test-mojom",
   ]
 }
 
-service_manifest("shutdown_unittest_manifest") {
-  name = "shutdown_unittest"
-  source = "shutdown_unittest_manifest.json"
-}
-
-service_manifest("shutdown_service_manifest") {
-  name = "shutdown_service"
-  source = "shutdown_service_manifest.json"
-}
-
 service_executable("shutdown_service") {
   testonly = true
   sources = [
@@ -63,11 +51,6 @@
   ]
 }
 
-service_manifest("shutdown_client_manifest") {
-  name = "shutdown_client"
-  source = "shutdown_client_manifest.json"
-}
-
 service_executable("shutdown_client") {
   testonly = true
   sources = [
@@ -80,12 +63,3 @@
     "//services/service_manager/public/mojom",
   ]
 }
-
-catalog("catalog") {
-  embedded_services = [ ":shutdown_unittest_manifest" ]
-
-  standalone_services = [
-    ":shutdown_client_manifest",
-    ":shutdown_service_manifest",
-  ]
-}
diff --git a/services/service_manager/tests/shutdown/OWNERS b/services/service_manager/tests/shutdown/OWNERS
deleted file mode 100644
index 340de599..0000000
--- a/services/service_manager/tests/shutdown/OWNERS
+++ /dev/null
@@ -1,11 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-
-per-file shutdown_client_manifest.json=set noparent
-per-file shutdown_client_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file shutdown_service_manifest.json=set noparent
-per-file shutdown_service_manifest.json=file://ipc/SECURITY_OWNERS
-
-per-file shutdown_unittest_manifest.json=set noparent
-per-file shutdown_unittest_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/services/service_manager/tests/shutdown/shutdown_unittest.mojom b/services/service_manager/tests/shutdown/shutdown.test-mojom
similarity index 100%
rename from services/service_manager/tests/shutdown/shutdown_unittest.mojom
rename to services/service_manager/tests/shutdown/shutdown.test-mojom
diff --git a/services/service_manager/tests/shutdown/shutdown_client_app.cc b/services/service_manager/tests/shutdown/shutdown_client_app.cc
index e28c6990..0f23496 100644
--- a/services/service_manager/tests/shutdown/shutdown_client_app.cc
+++ b/services/service_manager/tests/shutdown/shutdown_client_app.cc
@@ -10,7 +10,7 @@
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
-#include "services/service_manager/tests/shutdown/shutdown_unittest.mojom.h"
+#include "services/service_manager/tests/shutdown/shutdown.test-mojom.h"
 
 namespace service_manager {
 
diff --git a/services/service_manager/tests/shutdown/shutdown_client_manifest.json b/services/service_manager/tests/shutdown/shutdown_client_manifest.json
deleted file mode 100644
index 57101e73..0000000
--- a/services/service_manager/tests/shutdown/shutdown_client_manifest.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "name": "shutdown_client",
-  "display_name": "Shutdown Client",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "shutdown_unittest:shutdown_test_client_controller": [
-          "service_manager.mojom.ShutdownTestClientController"
-        ]
-      },
-      "requires": {
-        "service_manager": [ "service_manager:service_manager" ],
-        "shutdown_service": [ "shutdown_unittest:shutdown_test_service" ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/shutdown/shutdown_service_app.cc b/services/service_manager/tests/shutdown/shutdown_service_app.cc
index 84990cc..2bf549b 100644
--- a/services/service_manager/tests/shutdown/shutdown_service_app.cc
+++ b/services/service_manager/tests/shutdown/shutdown_service_app.cc
@@ -10,7 +10,7 @@
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/service_executable/service_main.h"
 #include "services/service_manager/public/mojom/service.mojom.h"
-#include "services/service_manager/tests/shutdown/shutdown_unittest.mojom.h"
+#include "services/service_manager/tests/shutdown/shutdown.test-mojom.h"
 
 namespace service_manager {
 namespace {
diff --git a/services/service_manager/tests/shutdown/shutdown_service_manifest.json b/services/service_manager/tests/shutdown/shutdown_service_manifest.json
deleted file mode 100644
index dcb69bb..0000000
--- a/services/service_manager/tests/shutdown/shutdown_service_manifest.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
-  "name": "shutdown_service",
-  "display_name": "Shutdown Service",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "provides": {
-        "shutdown_unittest:shutdown_test_service": [
-          "service_manager.mojom.ShutdownTestService"
-        ]
-      },
-      "requires": {
-        "service_manager": [ "service_manager:service_manager" ]
-      }
-    }
-  }
-}
diff --git a/services/service_manager/tests/shutdown/shutdown_unittest.cc b/services/service_manager/tests/shutdown/shutdown_unittest.cc
index 66c4696..a00f355 100644
--- a/services/service_manager/tests/shutdown/shutdown_unittest.cc
+++ b/services/service_manager/tests/shutdown/shutdown_unittest.cc
@@ -2,26 +2,67 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <vector>
+
+#include "base/no_destructor.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/manifest.h"
+#include "services/service_manager/public/cpp/manifest_builder.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_binding.h"
 #include "services/service_manager/public/cpp/test/test_service_manager.h"
-#include "services/service_manager/tests/catalog_source.h"
-#include "services/service_manager/tests/shutdown/shutdown_unittest.mojom.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
+#include "services/service_manager/tests/shutdown/shutdown.test-mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace service_manager {
 namespace {
 
+const char kTestServiceName[] = "shutdown_unittest";
+const char kShutdownServiceName[] = "shutdown_service";
+const char kShutdownClientName[] = "shutdown_client";
+
+const char kClientControllerCapability[] = "client_controller";
+const char kShutdownServiceCapability[] = "shutdown_service";
+
+const std::vector<Manifest>& GetTestManifests() {
+  static base::NoDestructor<std::vector<Manifest>> manifests{
+      {ManifestBuilder()
+           .WithServiceName(kShutdownClientName)
+           .ExposeCapability(
+               kClientControllerCapability,
+               Manifest::InterfaceList<mojom::ShutdownTestClientController>())
+           .RequireCapability(kShutdownServiceName, kShutdownServiceCapability)
+           .RequireCapability(mojom::kServiceName,
+                              "service_manager:service_manager")
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName(kShutdownServiceName)
+           .ExposeCapability(
+               kShutdownServiceCapability,
+               Manifest::InterfaceList<mojom::ShutdownTestService>())
+           .RequireCapability(mojom::kServiceName,
+                              "service_manager:service_manager")
+           .Build(),
+       ManifestBuilder()
+           .WithServiceName(kTestServiceName)
+           .RequireCapability(kShutdownServiceName, kShutdownServiceCapability)
+           .RequireCapability(mojom::kServiceName,
+                              "service_manager:service_manager")
+           .RequireCapability(kShutdownClientName, kClientControllerCapability)
+           .Build()}};
+  return *manifests;
+}
+
 class ShutdownTest : public testing::Test {
  public:
   ShutdownTest()
-      : test_service_manager_(test::CreateTestCatalog()),
+      : test_service_manager_(GetTestManifests()),
         test_service_binding_(
             &test_service_,
-            test_service_manager_.RegisterTestInstance("shutdown_unittest")) {}
+            test_service_manager_.RegisterTestInstance(kTestServiceName)) {}
   ~ShutdownTest() override = default;
 
   Connector* connector() { return test_service_binding_.GetConnector(); }
@@ -42,11 +83,11 @@
   // working as intended.
 
   mojom::ShutdownTestClientControllerPtr control;
-  connector()->BindInterface("shutdown_client", &control);
+  connector()->BindInterface(kShutdownClientName, &control);
 
   // Connect to shutdown_service and immediately request that it shut down.
   mojom::ShutdownTestServicePtr service;
-  connector()->BindInterface("shutdown_service", &service);
+  connector()->BindInterface(kShutdownServiceName, &service);
   service->ShutDown();
 
   // Tell shutdown_client to connect to an interface on shutdown_service and
diff --git a/services/service_manager/tests/shutdown/shutdown_unittest_manifest.json b/services/service_manager/tests/shutdown/shutdown_unittest_manifest.json
deleted file mode 100644
index 38ad6bd..0000000
--- a/services/service_manager/tests/shutdown/shutdown_unittest_manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "name": "shutdown_unittest",
-  "display_name": "Shutdown Unittest",
-  "interface_provider_specs": {
-    "service_manager:connector": {
-      "requires": {
-        "service_manager": [ "service_manager:service_manager" ],
-        "shutdown_client": [
-          "shutdown_unittest:shutdown_test_client_controller"
-        ],
-        "shutdown_service": [ "shutdown_unittest:shutdown_test_service" ]
-      }
-    }
-  }
-}
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index e0b6f29..e2707e5 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -633,8 +633,7 @@
       {
         "args": [
           "--enable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter"
+          "--override-use-software-gl-for-tests"
         ],
         "name": "single_process_mash_content_browsertests",
         "swarming": {
@@ -789,8 +788,7 @@
       },
       {
         "args": [
-          "--enable-features=SingleProcessMash",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter"
+          "--enable-features=SingleProcessMash"
         ],
         "name": "single_process_mash_interactive_ui_tests",
         "swarming": {
@@ -1342,8 +1340,7 @@
       {
         "args": [
           "--enable-features=SingleProcessMash",
-          "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter"
+          "--override-use-software-gl-for-tests"
         ],
         "name": "single_process_mash_content_browsertests",
         "swarming": {
@@ -1498,8 +1495,7 @@
       },
       {
         "args": [
-          "--enable-features=SingleProcessMash",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter"
+          "--enable-features=SingleProcessMash"
         ],
         "name": "single_process_mash_interactive_ui_tests",
         "swarming": {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 23d367b..e2b1b8e7 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -4437,24 +4437,6 @@
       }
     ]
   },
-  "linux-autofill-captured-sites-rel": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gtest_filter=\"AutofillCapturedSitesInteractiveTest.Recipe/*\"",
-          "--enable-pixel-output-in-tests",
-          "--ui-test-action-max-timeout=1000000",
-          "--test-launcher-timeout=1000000",
-          "--vmodule=captured_sites_test_utils=1,autofill_captured_sites_interactive_uitest=1"
-        ],
-        "name": "autofill_captured_sites_interactive_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "captured_sites_interactive_tests"
-      }
-    ]
-  },
   "linux-blink-animation-use-time-delta": {
     "additional_compile_targets": [
       "all"
@@ -11356,24 +11338,6 @@
       }
     ]
   },
-  "mac-autofill-captured-sites-rel": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gtest_filter=\"AutofillCapturedSitesInteractiveTest.Recipe/*\"",
-          "--enable-pixel-output-in-tests",
-          "--ui-test-action-max-timeout=1000000",
-          "--test-launcher-timeout=1000000",
-          "--vmodule=captured_sites_test_utils=1,autofill_captured_sites_interactive_uitest=1"
-        ],
-        "name": "autofill_captured_sites_interactive_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "captured_sites_interactive_tests"
-      }
-    ]
-  },
   "mac-hermetic-upgrade-rel": {
     "additional_compile_targets": [
       "all"
@@ -13801,24 +13765,6 @@
       }
     ]
   },
-  "win-autofill-captured-sites-rel": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--gtest_filter=\"AutofillCapturedSitesInteractiveTest.Recipe/*\"",
-          "--enable-pixel-output-in-tests",
-          "--ui-test-action-max-timeout=1000000",
-          "--test-launcher-timeout=1000000",
-          "--vmodule=captured_sites_test_utils=1,autofill_captured_sites_interactive_uitest=1"
-        ],
-        "name": "autofill_captured_sites_interactive_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "captured_sites_interactive_tests"
-      }
-    ]
-  },
   "win10-blink-rel-dummy": {
     "isolated_scripts": [
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 08923d6..f3bfb87 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -4440,7 +4440,6 @@
         "args": [
           "--enable-features=SingleProcessMash",
           "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter",
           "--test-launcher-print-test-stdio=always"
         ],
         "name": "single_process_mash_content_browsertests",
@@ -4643,7 +4642,6 @@
       {
         "args": [
           "--enable-features=SingleProcessMash",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter",
           "--test-launcher-print-test-stdio=always"
         ],
         "name": "single_process_mash_interactive_ui_tests",
@@ -5615,7 +5613,6 @@
         "args": [
           "--enable-features=SingleProcessMash",
           "--override-use-software-gl-for-tests",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter",
           "--test-launcher-print-test-stdio=always"
         ],
         "name": "single_process_mash_content_browsertests",
@@ -5945,7 +5942,6 @@
       {
         "args": [
           "--enable-features=SingleProcessMash",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter",
           "--test-launcher-print-test-stdio=always"
         ],
         "name": "single_process_mash_interactive_ui_tests",
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index 0d754e7..487d5e6 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -57,7 +57,6 @@
 
   data = [
     "//testing/buildbot/filters/cast-linux.content_browsertests.filter",
-    "//testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter",
     "//testing/buildbot/filters/mojo.fyi.network_content_browsertests.filter",
     "//testing/buildbot/filters/site_isolation_android.content_browsertests.filter",
   ]
@@ -78,7 +77,6 @@
 
   data = [
     "//testing/buildbot/filters/chromeos.mash.fyi.interactive_ui_tests.filter",
-    "//testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter",
     "//testing/buildbot/filters/mojo.fyi.chromeos.network_interactive_ui_tests.filter",
     "//testing/buildbot/filters/webui_polymer2_interactive_ui_tests.filter",
   ]
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
deleted file mode 100644
index 8f666190..0000000
--- a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
+++ /dev/null
@@ -1,15 +0,0 @@
-# These tests currently fail with SingleProcessMash enabled.
-# Bug: crbug.com/874089
-
-
-# CopyOutputRequests not allowed. https://crbug.com/877172
--AuraWindowVideoCaptureDeviceBrowserTest.DeliversRefreshFramesUponRequest
--AuraWindowVideoCaptureDeviceBrowserTest.ErrorsOutWhenWindowIsDestroyed
--AuraWindowVideoCaptureDeviceBrowserTestP.CapturesContentChanges/0
--AuraWindowVideoCaptureDeviceBrowserTestP.CapturesContentChanges/1
--AuraWindowVideoCaptureDeviceBrowserTest.SuspendsAndResumes
--CaptureScreenshotTest.CaptureScreenshot
--CaptureScreenshotTest.CaptureScreenshotJpeg
--CaptureScreenshotTest.SetDefaultBackgroundColorOverride
--CaptureScreenshotTest.TransparentScreenshots
--CompositedScrollingBrowserTest.Scroll3DTransformedScroller
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
deleted file mode 100644
index 197df33..0000000
--- a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
+++ /dev/null
@@ -1,12 +0,0 @@
-# These tests currently fail with SingleProcessMash enabled.
-# Bug: crbug.com/883523
-
-# TODO(sky): this now fails because of differences in timing. In particular,
-# in classic mode an accelerator that moves focus is processed *after* text
-# is inserted, where as now the accelerator runs first, resulting in text
-# going to the wrong place. The right fix likely entails updating the test for
-# ChromeOS.
--BrowserKeyEventsTest.AccessKeys
-
-# This test is flaky. https://crbug.com/897879
--ExtensionApiTest.DisplayModeWindowIsInFullscreen
diff --git a/testing/buildbot/generate_buildbot_json.py b/testing/buildbot/generate_buildbot_json.py
index b7cb9bf..e7e8a37 100755
--- a/testing/buildbot/generate_buildbot_json.py
+++ b/testing/buildbot/generate_buildbot_json.py
@@ -848,6 +848,12 @@
 
   def get_valid_bot_names(self):
     # Extract bot names from infra/config/global/luci-milo.cfg.
+    # NOTE: This reference can cause issues; if a file changes there, the
+    # presubmit here won't be run by default. A manually maintained list there
+    # tries to run presubmit here when luci-milo.cfg is changed. If any other
+    # references to configs outside of this directory are added, please change
+    # their presubmit to run `generate_buildbot_json.py -c`, so that the tree
+    # never ends up in an invalid state.
     bot_names = set()
     infra_config_dir = os.path.abspath(
         os.path.join(os.path.dirname(__file__),
diff --git a/testing/buildbot/gn_isolate_map.pyl b/testing/buildbot/gn_isolate_map.pyl
index 82dab9e..35512c40 100644
--- a/testing/buildbot/gn_isolate_map.pyl
+++ b/testing/buildbot/gn_isolate_map.pyl
@@ -411,10 +411,6 @@
     "label": "//media/capture:capture_unittests",
     "type": "windowed_test_launcher",
   },
-  "captured_sites_interactive_tests": {
-    "label": "//chrome/test:captured_sites_interactive_tests",
-    "type": "console_test_launcher",
-  },
   "cast_audio_backend_unittests": {
     "label": "//chromecast/media/cma/backend:cast_audio_backend_unittests",
     "type": "console_test_launcher",
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index 7021de47..967dec9 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -332,19 +332,6 @@
       'wm_unittests': {},
     },
 
-    'autofill_captured_sites_gtests': {
-      'autofill_captured_sites_interactive_tests': {
-        'test': 'captured_sites_interactive_tests',
-        'args': [
-          '--gtest_filter="AutofillCapturedSitesInteractiveTest.Recipe/*"',
-          '--enable-pixel-output-in-tests',
-          '--ui-test-action-max-timeout=1000000',
-          '--test-launcher-timeout=1000000',
-          '--vmodule=captured_sites_test_utils=1,autofill_captured_sites_interactive_uitest=1'
-        ],
-      },
-    },
-
     'cast_audio_specific_chromium_gtests': {
       'cast_audio_backend_unittests': {},
       'cast_base_unittests': {},
@@ -3539,8 +3526,7 @@
         'test': 'content_browsertests',
         'args': [
           '--enable-features=SingleProcessMash',
-          '--override-use-software-gl-for-tests',
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter',
+          '--override-use-software-gl-for-tests'
         ],
         'swarming': {
           'shards': 5,
@@ -3555,8 +3541,7 @@
       'single_process_mash_interactive_ui_tests': {
         'test': 'interactive_ui_tests',
         'args': [
-          '--enable-features=SingleProcessMash',
-          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter',
+          '--enable-features=SingleProcessMash'
         ],
         'swarming': {
           'shards': 3,
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 9446c06..194c7c98 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -1460,11 +1460,6 @@
           'scripts': 'test_traffic_annotation_auditor_script',
         }
       },
-      'linux-autofill-captured-sites-rel': {
-        'test_suites': {
-          'gtest_tests': 'autofill_captured_sites_gtests',
-        },
-      },
       'linux-blink-animation-use-time-delta': {
         'additional_compile_targets': [
           'all',
@@ -1549,11 +1544,6 @@
           'scripts': 'chromium_linux_scripts',
         },
       },
-      'mac-autofill-captured-sites-rel': {
-        'test_suites': {
-          'gtest_tests': 'autofill_captured_sites_gtests',
-        },
-      },
       'mac-hermetic-upgrade-rel': {
         'additional_compile_targets': [
           'all'
@@ -1663,11 +1653,6 @@
           'scripts': 'test_traffic_annotation_auditor_script',
         }
       },
-      'win-autofill-captured-sites-rel': {
-        'test_suites': {
-          'gtest_tests': 'autofill_captured_sites_gtests',
-        },
-      },
       'win10-blink-rel-dummy': {
         'swarming': {
           'dimension_sets': [
diff --git a/third_party/blink/public/platform/web_insecure_request_policy.h b/third_party/blink/public/platform/web_insecure_request_policy.h
index 8e22f6a..f83715d 100644
--- a/third_party/blink/public/platform/web_insecure_request_policy.h
+++ b/third_party/blink/public/platform/web_insecure_request_policy.h
@@ -9,6 +9,9 @@
 
 namespace blink {
 
+// The values of
+// https://w3c.github.io/webappsec-upgrade-insecure-requests/#insecure-requests-policy
+//
 // TODO(mkwst): In an ideal world, the combined state would be the same as
 // "Upgrade". Once we're consistently upgrading all requests, we can replace
 // this bitfield-style representation with an enum. Until then, we need to
diff --git a/third_party/blink/renderer/bindings/core/v8/window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
index 64736b5..d0f5142 100644
--- a/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
+++ b/third_party/blink/renderer/bindings/core/v8/window_proxy.cc
@@ -73,7 +73,7 @@
   DisposeContext(Lifecycle::kGlobalObjectIsDetached, kFrameWillNotBeReused);
 }
 
-void WindowProxy::ClearForMummification() {
+void WindowProxy::ClearForV8MemoryPurge() {
   DisposeContext(Lifecycle::kForciblyPurgeV8Memory, kFrameWillNotBeReused);
 }
 
diff --git a/third_party/blink/renderer/bindings/core/v8/window_proxy.h b/third_party/blink/renderer/bindings/core/v8/window_proxy.h
index 221d01d1f..c6a83aa 100644
--- a/third_party/blink/renderer/bindings/core/v8/window_proxy.h
+++ b/third_party/blink/renderer/bindings/core/v8/window_proxy.h
@@ -152,7 +152,7 @@
   void ClearForClose();
   void ClearForNavigation();
   void ClearForSwap();
-  void ClearForMummification();
+  void ClearForV8MemoryPurge();
 
   CORE_EXPORT v8::Local<v8::Object> GlobalProxyIfNotDetached();
   v8::Local<v8::Object> ReleaseGlobalProxy();
diff --git a/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc b/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
index 4365c73a..122f33e 100644
--- a/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
+++ b/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.cc
@@ -33,10 +33,10 @@
     entry.value->ClearForSwap();
 }
 
-void WindowProxyManager::ClearForMummification() {
-  window_proxy_->ClearForMummification();
+void WindowProxyManager::ClearForV8MemoryPurge() {
+  window_proxy_->ClearForV8MemoryPurge();
   for (auto& entry : isolated_worlds_)
-    entry.value->ClearForMummification();
+    entry.value->ClearForV8MemoryPurge();
 }
 
 void WindowProxyManager::ReleaseGlobalProxies(
diff --git a/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h b/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
index f0515f29..c988154 100644
--- a/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
+++ b/third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h
@@ -29,7 +29,7 @@
   void ClearForClose();
   void CORE_EXPORT ClearForNavigation();
   void ClearForSwap();
-  void ClearForMummification();
+  void ClearForV8MemoryPurge();
 
   // Global proxies are passed in a vector to maintain their order: global proxy
   // object for the main world is always first. This is needed to prevent bugs
diff --git a/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc b/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
index 30e93f2..cb34c4b2c 100644
--- a/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
+++ b/third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map_test.cc
@@ -18,6 +18,20 @@
  public:
   PrepopulatedComputedStylePropertyMapTest() = default;
 
+  void SetElementWithStyle(const String& value) {
+    GetDocument().body()->SetInnerHTMLFromString("<div id='target' style='" +
+                                                 value + "'></div>");
+    UpdateAllLifecyclePhasesForTest();
+  }
+
+  const CSSValue* GetNativeValue(const CSSPropertyID& property_id) {
+    Element* node = GetDocument().getElementById("target");
+    return CSSProperty::Get(property_id)
+        .CSSValueFromComputedStyle(node->ComputedStyleRef(),
+                                   nullptr /* layout_object */, node,
+                                   false /* allow_visited_style */);
+  }
+
   CSSComputedStyleDeclaration* Declaration() const {
     return declaration_.Get();
   }
@@ -111,4 +125,10 @@
   EXPECT_FALSE(exception_state.HadException());
 }
 
+TEST_F(PrepopulatedComputedStylePropertyMapTest, WidthBeingAuto) {
+  SetElementWithStyle("width:auto");
+  const CSSValue* value = GetNativeValue(CSSPropertyWidth);
+  EXPECT_EQ("auto", value->CssText());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index e5b8fd48..20b1baa0 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6552,7 +6552,8 @@
     const ContentSecurityPolicy* last_origin_document_csp) {
   SetContentSecurityPolicy(csp ? csp : ContentSecurityPolicy::Create());
 
-  GetContentSecurityPolicy()->BindToExecutionContext(this);
+  GetContentSecurityPolicy()->BindToDelegate(
+      GetContentSecurityPolicyDelegate());
 
   // We should inherit the navigation initiator CSP if the document is loaded
   // using a local-scheme url.
diff --git a/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc b/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
index ad2fff90..f910b5f 100644
--- a/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
+++ b/third_party/blink/renderer/core/dom/scripted_idle_task_controller_test.cc
@@ -95,7 +95,6 @@
   MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield::DONT_YIELD);
   ScopedSchedulerOverrider scheduler_overrider(&scheduler);
 
-  NullExecutionContext execution_context;
   ScriptedIdleTaskController* controller =
       ScriptedIdleTaskController::Create(execution_context_);
 
@@ -116,7 +115,6 @@
   MockScriptedIdleTaskControllerScheduler scheduler(ShouldYield::YIELD);
   ScopedSchedulerOverrider scheduler_overrider(&scheduler);
 
-  NullExecutionContext execution_context;
   ScriptedIdleTaskController* controller =
       ScriptedIdleTaskController::Create(execution_context_);
 
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.cc b/third_party/blink/renderer/core/execution_context/execution_context.cc
index 7fe16fa..44e16cf1 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.cc
+++ b/third_party/blink/renderer/core/execution_context/execution_context.cc
@@ -34,6 +34,7 @@
 #include "third_party/blink/renderer/core/dom/pausable_object.h"
 #include "third_party/blink/renderer/core/events/error_event.h"
 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
+#include "third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
@@ -52,6 +53,7 @@
       in_dispatch_error_event_(false),
       is_context_paused_(false),
       is_context_destroyed_(false),
+      csp_delegate_(MakeGarbageCollected<ExecutionContextCSPDelegate>(*this)),
       window_interaction_tokens_(0),
       referrer_policy_(network::mojom::ReferrerPolicy::kDefault),
       invalidator_(std::make_unique<InterfaceInvalidator>()) {}
@@ -165,6 +167,11 @@
   return *public_url_manager_;
 }
 
+ContentSecurityPolicyDelegate&
+ExecutionContext::GetContentSecurityPolicyDelegate() {
+  return *csp_delegate_;
+}
+
 const SecurityOrigin* ExecutionContext::GetSecurityOrigin() {
   return GetSecurityContext().GetSecurityOrigin();
 }
@@ -250,6 +257,7 @@
 void ExecutionContext::Trace(blink::Visitor* visitor) {
   visitor->Trace(public_url_manager_);
   visitor->Trace(pending_exceptions_);
+  visitor->Trace(csp_delegate_);
   ContextLifecycleNotifier::Trace(visitor);
   Supplementable<ExecutionContext>::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/core/execution_context/execution_context.h b/third_party/blink/renderer/core/execution_context/execution_context.h
index c0c6bab..68afe9e 100644
--- a/third_party/blink/renderer/core/execution_context/execution_context.h
+++ b/third_party/blink/renderer/core/execution_context/execution_context.h
@@ -55,6 +55,7 @@
 
 class ConsoleMessage;
 class ContentSecurityPolicy;
+class ContentSecurityPolicyDelegate;
 class CoreProbeSink;
 class DOMTimerCoordinator;
 class ErrorEvent;
@@ -175,6 +176,8 @@
 
   PublicURLManager& GetPublicURLManager();
 
+  ContentSecurityPolicyDelegate& GetContentSecurityPolicyDelegate();
+
   virtual void RemoveURLFromMemoryCache(const KURL&);
 
   void PausePausableObjects();
@@ -273,6 +276,8 @@
 
   Member<PublicURLManager> public_url_manager_;
 
+  const Member<ContentSecurityPolicyDelegate> csp_delegate_;
+
   // Counter that keeps track of how many window interaction calls are allowed
   // for this ExecutionContext. Callers are expected to call
   // |allowWindowInteraction()| and |consumeWindowInteraction()| in order to
diff --git a/third_party/blink/renderer/core/execution_context/security_context.h b/third_party/blink/renderer/core/execution_context/security_context.h
index fc777a33..c6cf76f 100644
--- a/third_party/blink/renderer/core/execution_context/security_context.h
+++ b/third_party/blink/renderer/core/execution_context/security_context.h
@@ -106,6 +106,7 @@
   void SetRequireTrustedTypes() { require_safe_types_ = true; }
   bool RequireTrustedTypes() const { return require_safe_types_; }
 
+  // https://w3c.github.io/webappsec-upgrade-insecure-requests/#upgrade-insecure-navigations-set
   void SetInsecureNavigationsSet(const std::vector<unsigned>& set) {
     insecure_navigations_to_upgrade_.clear();
     for (unsigned hash : set)
@@ -118,6 +119,7 @@
     return &insecure_navigations_to_upgrade_;
   }
 
+  // https://w3c.github.io/webappsec-upgrade-insecure-requests/#insecure-requests-policy
   virtual void SetInsecureRequestPolicy(WebInsecureRequestPolicy policy) {
     insecure_request_policy_ = policy;
   }
diff --git a/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc
index 4ae5f2dc..832bc0d1 100644
--- a/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc
+++ b/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.cc
@@ -262,4 +262,8 @@
   data_pipe_.reset();
 }
 
+void DataPipeBytesConsumer::Dispose() {
+  watcher_.Cancel();
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.h b/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.h
index e696345..eb986df4 100644
--- a/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.h
+++ b/third_party/blink/renderer/core/fetch/data_pipe_bytes_consumer.h
@@ -22,6 +22,8 @@
 // error signals, we define another interface, CompletionNotifier, for the
 // signals.
 class CORE_EXPORT DataPipeBytesConsumer final : public BytesConsumer {
+  USING_PRE_FINALIZER(DataPipeBytesConsumer, Dispose);
+
  public:
   class CORE_EXPORT CompletionNotifier final
       : public GarbageCollected<CompletionNotifier> {
@@ -70,6 +72,7 @@
   void ClearDataPipe();
   void SignalComplete();
   void SignalError(const Error& error);
+  void Dispose();
 
   Member<ExecutionContext> execution_context_;
   mojo::ScopedDataPipeConsumerHandle data_pipe_;
diff --git a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
index f36cf01..877c0ad 100644
--- a/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_data_loader.cc
@@ -485,6 +485,7 @@
 class FetchDataLoaderAsDataPipe final : public FetchDataLoader,
                                         public BytesConsumer::Client {
   USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsDataPipe);
+  USING_PRE_FINALIZER(FetchDataLoaderAsDataPipe, Dispose);
 
  public:
   explicit FetchDataLoaderAsDataPipe(
@@ -616,6 +617,8 @@
     out_data_pipe_.reset();
   }
 
+  void Dispose() { data_pipe_watcher_.Cancel(); }
+
   TraceWrapperMember<BytesConsumer> consumer_;
   Member<FetchDataLoader::Client> client_;
 
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index e0ce605c..098496b1 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -19,6 +19,8 @@
     "csp/csp_directive_list.h",
     "csp/csp_source.cc",
     "csp/csp_source.h",
+    "csp/execution_context_csp_delegate.cc",
+    "csp/execution_context_csp_delegate.h",
     "csp/media_list_directive.cc",
     "csp/media_list_directive.h",
     "csp/source_list_directive.cc",
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
index e28b9a4..64e77f00 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.cc
@@ -26,6 +26,7 @@
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 
 #include <memory>
+#include <utility>
 #include <vector>
 
 #include "third_party/blink/public/mojom/net/ip_address_space.mojom-blink.h"
@@ -39,7 +40,7 @@
 #include "third_party/blink/renderer/core/dom/dom_string_list.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
-#include "third_party/blink/renderer/core/events/security_policy_violation_event.h"
+#include "third_party/blink/renderer/core/events/security_policy_violation_event_init.h"
 #include "third_party/blink/renderer/core/frame/csp/csp_directive_list.h"
 #include "third_party/blink/renderer/core/frame/csp/csp_source.h"
 #include "third_party/blink/renderer/core/frame/csp/media_list_directive.h"
@@ -53,11 +54,6 @@
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/html/html_script_element.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/ping_loader.h"
-#include "third_party/blink/renderer/core/probe/core_probes.h"
-#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
-#include "third_party/blink/renderer/core/workers/worklet_global_scope.h"
 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
 #include "third_party/blink/renderer/platform/json/json_values.h"
 #include "third_party/blink/renderer/platform/loader/fetch/integrity_metadata.h"
@@ -65,11 +61,9 @@
 #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
 #include "third_party/blink/renderer/platform/network/content_security_policy_response_headers.h"
-#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/weborigin/known_ports.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
-#include "third_party/blink/renderer/platform/weborigin/reporting_service_proxy_ptr_holder.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 #include "third_party/blink/renderer/platform/wtf/not_found.h"
 #include "third_party/blink/renderer/platform/wtf/string_hasher.h"
@@ -154,7 +148,7 @@
 }
 
 ContentSecurityPolicy::ContentSecurityPolicy()
-    : execution_context_(nullptr),
+    : delegate_(nullptr),
       override_inline_style_allowed_(false),
       script_hash_algorithms_used_(kContentSecurityPolicyHashAlgorithmNone),
       style_hash_algorithms_used_(kContentSecurityPolicyHashAlgorithmNone),
@@ -163,10 +157,12 @@
       require_safe_types_(false),
       insecure_request_policy_(kLeaveInsecureRequestsAlone) {}
 
-void ContentSecurityPolicy::BindToExecutionContext(
-    ExecutionContext* execution_context) {
-  execution_context_ = execution_context;
-  ApplyPolicySideEffectsToExecutionContext();
+void ContentSecurityPolicy::BindToDelegate(
+    ContentSecurityPolicyDelegate& delegate) {
+  // TODO(crbug.com/915954): Add DCHECK(!delegate_). It seems some call sites
+  // call this function multiple times.
+  delegate_ = &delegate;
+  ApplyPolicySideEffectsToDelegate();
 }
 
 void ContentSecurityPolicy::SetupSelf(const SecurityOrigin& security_origin) {
@@ -185,66 +181,45 @@
   }
 }
 
-void ContentSecurityPolicy::ApplyPolicySideEffectsToExecutionContext() {
-  DCHECK(execution_context_ &&
-         execution_context_->GetSecurityContext().GetSecurityOrigin());
-  SecurityContext& security_context = execution_context_->GetSecurityContext();
+void ContentSecurityPolicy::ApplyPolicySideEffectsToDelegate() {
+  DCHECK(delegate_);
 
-  SetupSelf(*security_context.GetSecurityOrigin());
+  const SecurityOrigin* security_origin = delegate_->GetSecurityOrigin();
+  DCHECK(security_origin);
+
+  SetupSelf(*security_origin);
 
   // Set mixed content checking and sandbox flags, then dump all the parsing
   // error messages, then poke at histograms.
-  Document* document = this->GetDocument();
   if (sandbox_mask_ != kSandboxNone) {
-    UseCounter::Count(execution_context_, WebFeature::kSandboxViaCSP);
-    if (document)
-      document->EnforceSandboxFlags(sandbox_mask_);
-    else
-      security_context.ApplySandboxFlags(sandbox_mask_);
+    Count(WebFeature::kSandboxViaCSP);
+    delegate_->SetSandboxFlags(sandbox_mask_);
   }
-  if (treat_as_public_address_) {
-    security_context.SetAddressSpace(mojom::IPAddressSpace::kPublic);
-  }
-  if (require_safe_types_) {
-    security_context.SetRequireTrustedTypes();
-  }
+  if (treat_as_public_address_)
+    delegate_->SetAddressSpace(mojom::IPAddressSpace::kPublic);
 
-  // Upgrade Insecure Requests: Update the policy.
-  security_context.SetInsecureRequestPolicy(
-      security_context.GetInsecureRequestPolicy() | insecure_request_policy_);
-  if (document)
-    document->DidEnforceInsecureRequestPolicy();
+  if (require_safe_types_)
+    delegate_->SetRequireTrustedTypes();
 
-  // Upgrade Insecure Requests: Update the set of insecure URLs to upgrade.
-  if (insecure_request_policy_ & kUpgradeInsecureRequests) {
-    UseCounter::Count(execution_context_,
-                      WebFeature::kUpgradeInsecureRequestsEnabled);
-    if (!execution_context_->Url().Host().IsEmpty()) {
-      uint32_t hash = execution_context_->Url().Host().Impl()->GetHash();
-      security_context.AddInsecureNavigationUpgrade(hash);
-      if (document)
-        document->DidEnforceInsecureNavigationsSet();
-    }
-  }
+  delegate_->AddInsecureRequestPolicy(insecure_request_policy_);
 
   for (const auto& console_message : console_messages_)
-    execution_context_->AddConsoleMessage(console_message);
+    delegate_->AddConsoleMessage(console_message);
   console_messages_.clear();
 
   for (const auto& policy : policies_) {
-    UseCounter::Count(execution_context_,
-                      GetUseCounterType(policy->HeaderType()));
+    Count(GetUseCounterType(policy->HeaderType()));
     if (policy->AllowDynamic(
             ContentSecurityPolicy::DirectiveType::kScriptSrcAttr) ||
         policy->AllowDynamic(
             ContentSecurityPolicy::DirectiveType::kScriptSrcElem)) {
-      UseCounter::Count(execution_context_, WebFeature::kCSPWithStrictDynamic);
+      Count(WebFeature::kCSPWithStrictDynamic);
     }
 
     if (policy->AllowEval(nullptr,
                           SecurityViolationReportingPolicy::kSuppressReporting,
                           kWillNotThrowException, g_empty_string)) {
-      UseCounter::Count(execution_context_, WebFeature::kCSPWithUnsafeEval);
+      Count(WebFeature::kCSPWithUnsafeEval);
     }
   }
 
@@ -252,22 +227,18 @@
   // the check in the V8Initializer::codeGenerationCheckCallbackInMainThread
   // callback to determine whether the call should execute or not.
   if (!disable_eval_error_message_.IsNull())
-    execution_context_->DisableEval(disable_eval_error_message_);
+    delegate_->DisableEval(disable_eval_error_message_);
 }
 
 ContentSecurityPolicy::~ContentSecurityPolicy() = default;
 
 void ContentSecurityPolicy::Trace(blink::Visitor* visitor) {
-  visitor->Trace(execution_context_);
+  visitor->Trace(delegate_);
   visitor->Trace(policies_);
   visitor->Trace(console_messages_);
   visitor->Trace(self_source_);
 }
 
-Document* ContentSecurityPolicy::GetDocument() const {
-  return DynamicTo<Document>(execution_context_.Get());
-}
-
 void ContentSecurityPolicy::CopyStateFrom(const ContentSecurityPolicy* other) {
   DCHECK(policies_.IsEmpty());
   for (const auto& policy : other->policies_)
@@ -308,10 +279,10 @@
     ContentSecurityPolicyHeaderSource source) {
   AddAndReportPolicyFromHeaderValue(header, type, source);
 
-  // This might be called after we've been bound to an execution context. For
-  // example, a <meta> element might be injected after page load.
-  if (execution_context_)
-    ApplyPolicySideEffectsToExecutionContext();
+  // This might be called after we've been bound to a delegate. For example, a
+  // <meta> element might be injected after page load.
+  if (delegate_)
+    ApplyPolicySideEffectsToDelegate();
 }
 
 bool ContentSecurityPolicy::ShouldEnforceEmbeddersPolicy(
@@ -422,10 +393,9 @@
     policies[i - previous_policy_count] =
         policies_[i]->ExposeForNavigationalChecks();
   }
-  if (GetDocument() && GetDocument()->GetFrame()) {
-    GetDocument()->GetFrame()->Client()->DidAddContentSecurityPolicies(
-        policies);
-  }
+
+  if (delegate_)
+    delegate_->DidAddContentSecurityPolicies(policies);
 }
 
 void ContentSecurityPolicy::SetOverrideAllowInlineStyle(bool value) {
@@ -688,12 +658,10 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_)) {
-    UseCounter::Count(
-        GetDocument(),
-        parser_disposition == kParserInserted
-            ? WebFeature::kScriptWithCSPBypassingSchemeParserInserted
-            : WebFeature::kScriptWithCSPBypassingSchemeNotParserInserted);
+  if (ShouldBypassContentSecurityPolicy(url)) {
+    Count(parser_disposition == kParserInserted
+              ? WebFeature::kScriptWithCSPBypassingSchemeParserInserted
+              : WebFeature::kScriptWithCSPBypassingSchemeNotParserInserted);
 
     // If we're running experimental features, bypass CSP only for
     // non-parser-inserted resources whose scheme otherwise bypasses CSP. If
@@ -706,7 +674,7 @@
         // The schemes where javascript:-URLs are blocked are usually privileged
         // pages, so do not allow the CSP to be bypassed either.
         !SchemeRegistry::ShouldTreatURLSchemeAsNotAllowingJavascriptURLs(
-            execution_context_->GetSecurityOrigin()->Protocol())) {
+            delegate_->GetSecurityOrigin()->Protocol())) {
       return true;
     }
   }
@@ -831,7 +799,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -850,7 +818,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -869,7 +837,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -888,8 +856,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_,
-                                        SchemeRegistry::kPolicyAreaImage))
+  if (ShouldBypassContentSecurityPolicy(url, SchemeRegistry::kPolicyAreaImage))
     return true;
 
   bool is_allowed = true;
@@ -909,8 +876,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_,
-                                        SchemeRegistry::kPolicyAreaStyle))
+  if (ShouldBypassContentSecurityPolicy(url, SchemeRegistry::kPolicyAreaStyle))
     return true;
 
   bool is_allowed = true;
@@ -928,7 +894,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -947,7 +913,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -966,7 +932,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -985,7 +951,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -1005,7 +971,7 @@
     SecurityViolationReportingPolicy reporting_policy) const {
   // `base-uri` isn't affected by 'upgrade-insecure-requests', so we'll check
   // both report-only and enforce headers here.
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -1038,7 +1004,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -1057,7 +1023,7 @@
     RedirectStatus redirect_status,
     SecurityViolationReportingPolicy reporting_policy,
     CheckHeaderType check_header_type) const {
-  if (ShouldBypassContentSecurityPolicy(url, execution_context_))
+  if (ShouldBypassContentSecurityPolicy(url))
     return true;
 
   bool is_allowed = true;
@@ -1101,8 +1067,8 @@
   return false;
 }
 
-const KURL ContentSecurityPolicy::Url() const {
-  return execution_context_->Url();
+const KURL ContentSecurityPolicy::FallbackUrlForPlugin() const {
+  return delegate_ ? delegate_->Url() : KURL();
 }
 
 void ContentSecurityPolicy::EnforceSandboxFlags(SandboxFlags mask) {
@@ -1130,7 +1096,7 @@
 }
 
 static String StripURLForUseInReport(
-    ExecutionContext* context,
+    const SecurityOrigin* security_origin,
     const KURL& url,
     RedirectStatus redirect_status,
     const ContentSecurityPolicy::DirectiveType& effective_type) {
@@ -1143,7 +1109,7 @@
   // (and, by extension, in plugin documents), strip cross-origin 'frame-src'
   // and 'object-src' violations down to an origin. https://crbug.com/633306
   bool can_safely_expose_url =
-      context->GetSecurityOrigin()->CanRequest(url) ||
+      security_origin->CanRequest(url) ||
       (redirect_status == RedirectStatus::kNoRedirect &&
        effective_type != ContentSecurityPolicy::DirectiveType::kFrameSrc &&
        effective_type != ContentSecurityPolicy::DirectiveType::kObjectSrc);
@@ -1160,7 +1126,7 @@
 
 static void GatherSecurityPolicyViolationEventData(
     SecurityPolicyViolationEventInit* init,
-    ExecutionContext* context,
+    ContentSecurityPolicyDelegate* delegate,
     const String& directive_text,
     const ContentSecurityPolicy::DirectiveType& effective_type,
     const KURL& blocked_url,
@@ -1175,13 +1141,14 @@
     // |document| has not yet been initialized. In this case, we'll set both
     // 'documentURI' and 'blockedURI' to the blocked document's URL.
     String stripped_url = StripURLForUseInReport(
-        context, blocked_url, RedirectStatus::kNoRedirect,
+        delegate->GetSecurityOrigin(), blocked_url, RedirectStatus::kNoRedirect,
         ContentSecurityPolicy::DirectiveType::kDefaultSrc);
     init->setDocumentURI(stripped_url);
     init->setBlockedURI(stripped_url);
   } else {
     String stripped_url = StripURLForUseInReport(
-        context, context->Url(), RedirectStatus::kNoRedirect,
+        delegate->GetSecurityOrigin(), delegate->Url(),
+        RedirectStatus::kNoRedirect,
         ContentSecurityPolicy::DirectiveType::kDefaultSrc);
     init->setDocumentURI(stripped_url);
     switch (violation_type) {
@@ -1192,8 +1159,9 @@
         init->setBlockedURI("eval");
         break;
       case ContentSecurityPolicy::kURLViolation:
-        init->setBlockedURI(StripURLForUseInReport(
-            context, blocked_url, redirect_status, effective_type));
+        init->setBlockedURI(
+            StripURLForUseInReport(delegate->GetSecurityOrigin(), blocked_url,
+                                   redirect_status, effective_type));
         break;
     }
   }
@@ -1208,20 +1176,31 @@
                            : "report");
   init->setStatusCode(0);
 
-  // TODO(mkwst): We only have referrer and status code information for
-  // Documents. It would be nice to get them for Workers as well.
-  if (auto* document = DynamicTo<Document>(*context)) {
-    init->setReferrer(document->referrer());
-    if (!SecurityOrigin::IsSecure(context->Url()) && document->Loader())
-      init->setStatusCode(document->Loader()->GetResponse().HttpStatusCode());
-  }
+  // See https://w3c.github.io/webappsec-csp/#create-violation-for-global.
+  // Step 3. If global is a Window object, set violation’s referrer to global’s
+  // document's referrer. [spec text]
+  String referrer = delegate->GetDocumentReferrer();
+  if (referrer)
+    init->setReferrer(referrer);
 
-  // If no source location is provided, use the source location of the context.
+  // Step 4. Set violation’s status to the HTTP status code for the resource
+  // associated with violation’s global object. [spec text]
+  base::Optional<uint16_t> status_code = delegate->GetStatusCode();
+  if (status_code)
+    init->setStatusCode(*status_code);
+
+  // If no source location is provided, use the source location from the
+  // |delegate|.
+  // Step 2. If the user agent is currently executing script, and can extract a
+  // source file’s URL, line number, and column number from the global, set
+  // violation’s source file, line number, and column number accordingly.
+  // [spec text]
   if (!source_location)
-    source_location = SourceLocation::Capture(context);
-  if (source_location->LineNumber()) {
+    source_location = delegate->GetSourceLocation();
+  if (source_location && source_location->LineNumber()) {
     KURL source = KURL(source_location->Url());
-    init->setSourceFile(StripURLForUseInReport(context, source, redirect_status,
+    init->setSourceFile(StripURLForUseInReport(delegate->GetSecurityOrigin(),
+                                               source, redirect_status,
                                                effective_type));
     init->setLineNumber(source_location->LineNumber());
     init->setColumnNumber(source_location->ColumnNumber());
@@ -1257,26 +1236,29 @@
   // TODO(lukasza): Support sending reports from OOPIFs -
   // https://crbug.com/611232 (or move CSP child-src and frame-src checks to the
   // browser process - see https://crbug.com/376522).
-  if (!execution_context_ && !context_frame) {
+  if (!delegate_ && !context_frame) {
     DCHECK(effective_type == DirectiveType::kChildSrc ||
            effective_type == DirectiveType::kFrameSrc ||
            effective_type == DirectiveType::kPluginTypes);
     return;
   }
 
-  DCHECK((execution_context_ && !context_frame) ||
+  DCHECK((delegate_ && !context_frame) ||
          ((effective_type == DirectiveType::kFrameAncestors) && context_frame));
 
   SecurityPolicyViolationEventInit* violation_data =
       SecurityPolicyViolationEventInit::Create();
 
-  // If we're processing 'frame-ancestors', use |contextFrame|'s execution
-  // context to gather data. Otherwise, use the policy's execution context.
-  ExecutionContext* relevant_context =
-      context_frame ? context_frame->GetDocument() : execution_context_;
-  DCHECK(relevant_context);
+  // If we're processing 'frame-ancestors', use the delegate for the
+  // |context_frame|'s document to gather data. Otherwise, use the policy's
+  // |delegate_|.
+  ContentSecurityPolicyDelegate* relevant_delegate =
+      context_frame
+          ? &context_frame->GetDocument()->GetContentSecurityPolicyDelegate()
+          : delegate_.Get();
+  DCHECK(relevant_delegate);
   GatherSecurityPolicyViolationEventData(
-      violation_data, relevant_context, directive_text, effective_type,
+      violation_data, relevant_delegate, directive_text, effective_type,
       blocked_url, header, redirect_status, header_type, violation_type,
       std::move(source_location), source);
 
@@ -1285,24 +1267,17 @@
   // we should at least stop spamming reporting endpoints. See
   // https://crbug.com/524356 for detail.
   if (!violation_data->sourceFile().IsEmpty() &&
-      ShouldBypassContentSecurityPolicy(KURL(violation_data->sourceFile()),
-                                        execution_context_)) {
+      ShouldBypassContentSecurityPolicy(KURL(violation_data->sourceFile()))) {
     return;
   }
 
   PostViolationReport(violation_data, context_frame, report_endpoints,
                       use_reporting_api);
 
-  // Fire a violation event if we're working within an execution context (e.g.
-  // we're not processing 'frame-ancestors').
-  if (execution_context_) {
-    execution_context_->GetTaskRunner(TaskType::kNetworking)
-        ->PostTask(
-            FROM_HERE,
-            WTF::Bind(&ContentSecurityPolicy::DispatchViolationEvents,
-                      WrapPersistent(this), WrapPersistent(violation_data),
-                      WrapPersistent(element)));
-  }
+  // Fire a violation event if we're working with a delegate (e.g. we're not
+  // processing 'frame-ancestors').
+  if (delegate_)
+    delegate_->DispatchViolationEvent(*violation_data, element);
 }
 
 void ContentSecurityPolicy::PostViolationReport(
@@ -1354,70 +1329,19 @@
   if (ShouldSendViolationReport(stringified_report)) {
     DidSendViolationReport(stringified_report);
 
-    // TODO(mkwst): Support POSTing violation reports from a Worker.
-    Document* document =
-        context_frame ? context_frame->GetDocument() : this->GetDocument();
-    if (!document)
-      return;
+    // If we're processing 'frame-ancestors', use the delegate for the
+    // |context_frame|'s document to post violation report. Otherwise, use the
+    // policy's |delegate_|.
+    bool is_frame_ancestors_violation = !!context_frame;
+    ContentSecurityPolicyDelegate* relevant_delegate =
+        is_frame_ancestors_violation
+            ? &context_frame->GetDocument()->GetContentSecurityPolicyDelegate()
+            : delegate_.Get();
+    DCHECK(relevant_delegate);
 
-    LocalFrame* frame = document->GetFrame();
-    if (!frame)
-      return;
-
-    scoped_refptr<EncodedFormData> report =
-        EncodedFormData::Create(stringified_report.Utf8());
-
-    DEFINE_STATIC_LOCAL(ReportingServiceProxyPtrHolder,
-                        reporting_service_proxy_holder, ());
-
-    for (const auto& report_endpoint : report_endpoints) {
-      if (use_reporting_api) {
-        reporting_service_proxy_holder.QueueCspViolationReport(
-            document->Url(), report_endpoint, violation_data);
-      } else {
-        // If we have a context frame we're dealing with 'frame-ancestors' and
-        // we don't have our own execution context. Use the frame's document to
-        // complete the endpoint URL, overriding its URL with the blocked
-        // document's URL.
-        DCHECK(!context_frame || !execution_context_);
-        DCHECK(!context_frame ||
-               GetDirectiveType(violation_data->effectiveDirective()) ==
-                   DirectiveType::kFrameAncestors);
-        KURL url =
-            context_frame
-                ? frame->GetDocument()->CompleteURLWithOverride(
-                      report_endpoint, KURL(violation_data->blockedURI()))
-                // We use the FallbackBaseURL to ensure that we don't
-                // respect base elements when determining the report
-                // endpoint URL.
-                : frame->GetDocument()->CompleteURLWithOverride(
-                      report_endpoint, frame->GetDocument()->FallbackBaseURL());
-        PingLoader::SendViolationReport(
-            frame, url, report,
-            PingLoader::kContentSecurityPolicyViolationReport);
-      }
-    }
-  }
-}
-
-void ContentSecurityPolicy::DispatchViolationEvents(
-    const SecurityPolicyViolationEventInit* violation_data,
-    Element* element) {
-  // Worklets don't support Events in general.
-  if (execution_context_->IsWorkletGlobalScope())
-    return;
-
-  SecurityPolicyViolationEvent& event = *SecurityPolicyViolationEvent::Create(
-      event_type_names::kSecuritypolicyviolation, violation_data);
-  DCHECK(event.bubbles());
-
-  if (auto* document = DynamicTo<Document>(*execution_context_)) {
-    if (element && element->isConnected() && element->GetDocument() == document)
-      element->EnqueueEvent(event, TaskType::kInternalDefault);
-    else
-      document->EnqueueEvent(event, TaskType::kInternalDefault);
-  } else if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_)) {
-    scope->EnqueueEvent(event, TaskType::kInternalDefault);
+    relevant_delegate->PostViolationReport(*violation_data, stringified_report,
+                                           is_frame_ancestors_violation,
+                                           report_endpoints, use_reporting_api);
   }
 }
 
@@ -1607,15 +1531,16 @@
                                          LocalFrame* frame) {
   if (frame)
     frame->GetDocument()->AddConsoleMessage(console_message);
-  else if (execution_context_)
-    execution_context_->AddConsoleMessage(console_message);
+  else if (delegate_)
+    delegate_->AddConsoleMessage(console_message);
   else
     console_messages_.push_back(console_message);
 }
 
 void ContentSecurityPolicy::ReportBlockedScriptExecutionToInspector(
     const String& directive_text) const {
-  probe::scriptExecutionBlockedByCSP(execution_context_, directive_text);
+  if (delegate_)
+    delegate_->ReportBlockedScriptExecutionToInspector(directive_text);
 }
 
 bool ContentSecurityPolicy::ExperimentalFeaturesEnabled() const {
@@ -1826,24 +1751,22 @@
   return policies_[0]->Subsumes(other_vector);
 }
 
-// static
 bool ContentSecurityPolicy::ShouldBypassContentSecurityPolicy(
     const KURL& url,
-    ExecutionContext* execution_context,
-    SchemeRegistry::PolicyAreas area) {
+    SchemeRegistry::PolicyAreas area) const {
   bool should_bypass_csp;
   if (SecurityOrigin::ShouldUseInnerURL(url)) {
     should_bypass_csp = SchemeRegistry::SchemeShouldBypassContentSecurityPolicy(
         SecurityOrigin::ExtractInnerURL(url).Protocol(), area);
     if (should_bypass_csp) {
-      UseCounter::Count(execution_context, WebFeature::kInnerSchemeBypassesCSP);
+      Count(WebFeature::kInnerSchemeBypassesCSP);
     }
   } else {
     should_bypass_csp = SchemeRegistry::SchemeShouldBypassContentSecurityPolicy(
         url.Protocol(), area);
   }
   if (should_bypass_csp) {
-    UseCounter::Count(execution_context, WebFeature::kSchemeBypassesCSP);
+    Count(WebFeature::kSchemeBypassesCSP);
   }
 
   return should_bypass_csp;
@@ -1911,4 +1834,9 @@
   return false;
 }
 
+void ContentSecurityPolicy::Count(WebFeature feature) const {
+  if (delegate_)
+    delegate_->Count(feature);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy.h b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
index 4e805d1..74418da0 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy.h
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy.h
@@ -32,8 +32,8 @@
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
 #include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/web_feature.h"
 #include "third_party/blink/renderer/core/inspector/console_types.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
@@ -62,7 +62,9 @@
 class CSPSource;
 class Document;
 class Element;
+class ExecutionContext;
 class LocalFrameClient;
+class LocalFrame;
 class KURL;
 class ResourceRequest;
 class SecurityOrigin;
@@ -76,6 +78,56 @@
 typedef std::pair<String, ContentSecurityPolicyHeaderType> CSPHeaderAndType;
 using RedirectStatus = ResourceRequest::RedirectStatus;
 
+//  A delegate interface to implement violation reporting, support for some
+//  directives and other miscellaneous functionality.
+class CORE_EXPORT ContentSecurityPolicyDelegate : public GarbageCollectedMixin {
+ public:
+  // Returns the SecurityOrigin this content security policy is bound to. Used
+  // for matching the 'self' keyword. Must return a non-null value.
+  // See https://w3c.github.io/webappsec-csp/#policy-self-origin.
+  virtual const SecurityOrigin* GetSecurityOrigin() = 0;
+
+  // Returns the URL this content security policy is bound to.
+  // Used for https://w3c.github.io/webappsec-csp/#violation-url and so.
+  // Note: Url() is used for several purposes that are specced slightly
+  // differently.
+  // See comments at the callers.
+  virtual const KURL& Url() const = 0;
+
+  // Directives support.
+  virtual void SetSandboxFlags(SandboxFlags) = 0;
+  virtual void SetAddressSpace(mojom::IPAddressSpace) = 0;
+  virtual void SetRequireTrustedTypes() = 0;
+  virtual void AddInsecureRequestPolicy(WebInsecureRequestPolicy) = 0;
+
+  // Violation reporting.
+
+  // See https://w3c.github.io/webappsec-csp/#create-violation-for-global.
+  // These functions are used to create the violation object.
+  virtual std::unique_ptr<SourceLocation> GetSourceLocation() = 0;
+  virtual base::Optional<uint16_t> GetStatusCode() = 0;
+  // If the Delegate is not bound to a document, a null string should be
+  // returned as the referrer.
+  virtual String GetDocumentReferrer() = 0;
+
+  virtual void DispatchViolationEvent(const SecurityPolicyViolationEventInit&,
+                                      Element*) = 0;
+  virtual void PostViolationReport(const SecurityPolicyViolationEventInit&,
+                                   const String& stringified_report,
+                                   bool is_frame_ancestors_violaton,
+                                   const Vector<String>& report_endpoints,
+                                   bool use_reporting_api) = 0;
+
+  virtual void Count(WebFeature) = 0;
+
+  virtual void AddConsoleMessage(ConsoleMessage*) = 0;
+  virtual void DisableEval(const String& error_message) = 0;
+  virtual void ReportBlockedScriptExecutionToInspector(
+      const String& directive_text) = 0;
+  virtual void DidAddContentSecurityPolicies(
+      const blink::WebVector<WebContentSecurityPolicy>&) = 0;
+};
+
 class CORE_EXPORT ContentSecurityPolicy
     : public GarbageCollectedFinalized<ContentSecurityPolicy> {
  public:
@@ -147,7 +199,7 @@
   ~ContentSecurityPolicy();
   void Trace(blink::Visitor*);
 
-  void BindToExecutionContext(ExecutionContext*);
+  void BindToDelegate(ContentSecurityPolicyDelegate&);
   void SetupSelf(const SecurityOrigin&);
   void SetupSelf(const ContentSecurityPolicy&);
   void CopyStateFrom(const ContentSecurityPolicy*);
@@ -404,7 +456,9 @@
   void ReportBlockedScriptExecutionToInspector(
       const String& directive_text) const;
 
-  const KURL Url() const;
+  // Used as <object>'s URL when there is no `src` attribute.
+  const KURL FallbackUrlForPlugin() const;
+
   void EnforceSandboxFlags(SandboxFlags);
   void TreatAsPublicAddress();
   void RequireTrustedTypes();
@@ -429,10 +483,6 @@
   CSPSource* GetSelfSource() const { return self_source_; }
 
   static bool ShouldBypassMainWorld(const ExecutionContext*);
-  static bool ShouldBypassContentSecurityPolicy(
-      const KURL&,
-      ExecutionContext*,
-      SchemeRegistry::PolicyAreas = SchemeRegistry::kPolicyAreaAll);
 
   static bool IsNonceableElement(const Element*);
 
@@ -451,8 +501,6 @@
   // https://w3c.github.io/webappsec-csp/embedded/#subsume-policy
   bool Subsumes(const ContentSecurityPolicy&) const;
 
-  Document* GetDocument() const;
-
   bool HasHeaderDeliveredPolicy() const { return header_delivered_; }
 
   static bool IsValidCSPAttr(const String& attr,
@@ -492,6 +540,8 @@
         directive_type == ContentSecurityPolicy::DirectiveType::kStyleSrcElem);
   }
 
+  void Count(WebFeature feature) const;
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ContentSecurityPolicyTest, NonceInline);
   FRIEND_TEST_ALL_PREFIXES(ContentSecurityPolicyTest, NonceSinglePolicy);
@@ -503,7 +553,7 @@
   FRIEND_TEST_ALL_PREFIXES(FrameFetchContextTest,
                            PopulateResourceRequestChecksReportOnlyCSP);
 
-  void ApplyPolicySideEffectsToExecutionContext();
+  void ApplyPolicySideEffectsToDelegate();
 
   void LogToConsole(const String& message, MessageLevel = kErrorMessageLevel);
 
@@ -513,8 +563,6 @@
 
   bool ShouldSendViolationReport(const String&) const;
   void DidSendViolationReport(const String&);
-  void DispatchViolationEvents(const SecurityPolicyViolationEventInit*,
-                               Element*);
   void PostViolationReport(const SecurityPolicyViolationEventInit*,
                            LocalFrame*,
                            const Vector<String>& report_endpoints,
@@ -533,7 +581,11 @@
                                           const Member<CSPDirectiveList>&,
                                           InlineType);
 
-  Member<ExecutionContext> execution_context_;
+  bool ShouldBypassContentSecurityPolicy(
+      const KURL&,
+      SchemeRegistry::PolicyAreas = SchemeRegistry::kPolicyAreaAll) const;
+
+  Member<ContentSecurityPolicyDelegate> delegate_;
   bool override_inline_style_allowed_;
   CSPDirectiveListVector policies_;
   ConsoleMessageVector console_messages_;
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
index 0ff44e26..35c9991 100644
--- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -71,7 +71,7 @@
     execution_context = CreateExecutionContext();
     execution_context->SetSecurityOrigin(secure_origin);
     execution_context->SetURL(secure_url);
-    csp->BindToExecutionContext(execution_context.Get());
+    csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
     EXPECT_EQ(test.expected_policy,
               execution_context->GetInsecureRequestPolicy());
     bool expect_upgrade = test.expected_policy & kUpgradeInsecureRequests;
@@ -91,7 +91,7 @@
 
     execution_context = CreateExecutionContext();
     execution_context->SetSecurityOrigin(secure_origin);
-    csp->BindToExecutionContext(execution_context.Get());
+    csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
     EXPECT_EQ(kLeaveInsecureRequestsAlone,
               execution_context->GetInsecureRequestPolicy());
     EXPECT_FALSE(execution_context->InsecureNavigationsToUpgrade()->Contains(
@@ -107,7 +107,7 @@
   csp->DidReceiveHeader("treat-as-public-address",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   EXPECT_EQ(mojom::IPAddressSpace::kPrivate, execution_context->AddressSpace());
 }
 
@@ -119,7 +119,7 @@
   csp->DidReceiveHeader("treat-as-public-address",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   EXPECT_EQ(mojom::IPAddressSpace::kPublic, execution_context->AddressSpace());
 }
 
@@ -224,7 +224,7 @@
 // Tests that frame-ancestors directives are discarded from policies
 // delivered in <meta> elements.
 TEST_F(ContentSecurityPolicyTest, FrameAncestorsInMeta) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("frame-ancestors 'none';",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceMeta);
@@ -238,7 +238,7 @@
 // Tests that sandbox directives are discarded from policies
 // delivered in <meta> elements.
 TEST_F(ContentSecurityPolicyTest, SandboxInMeta) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("sandbox;", kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceMeta);
   EXPECT_FALSE(execution_context->GetSecurityOrigin()->IsOpaque());
@@ -270,7 +270,7 @@
 // makes. https://crbug.com/603952
 TEST_F(ContentSecurityPolicyTest, ObjectSrc) {
   const KURL url("https://example.test");
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("object-src 'none';",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceMeta);
@@ -290,7 +290,7 @@
 
 TEST_F(ContentSecurityPolicyTest, ConnectSrc) {
   const KURL url("https://example.test");
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("connect-src 'none';",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceMeta);
@@ -323,7 +323,7 @@
   const KURL url("https://example.test");
   // Enforce
   Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
                            kContentSecurityPolicyHeaderSourceHTTP);
@@ -359,7 +359,7 @@
       SecurityViolationReportingPolicy::kSuppressReporting));
   // Report
   policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
                            kContentSecurityPolicyHeaderSourceHTTP);
@@ -402,10 +402,10 @@
   IntegrityMetadataSet integrity_metadata;
   integrity_metadata.insert(
       IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   // Enforce
   Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
                            kContentSecurityPolicyHeaderSourceHTTP);
@@ -442,7 +442,7 @@
   // Content-Security-Policy-Report-Only is not supported in meta element,
   // so nothing should be blocked
   policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
                            kContentSecurityPolicyHeaderSourceHTTP);
@@ -484,7 +484,7 @@
   const KURL url("https://example.test");
   // Enforce
   Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
                            kContentSecurityPolicyHeaderSourceMeta);
@@ -521,7 +521,7 @@
   // Content-Security-Policy-Report-Only is not supported in meta element,
   // so nothing should be blocked
   policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
                            kContentSecurityPolicyHeaderSourceMeta);
@@ -564,10 +564,10 @@
   IntegrityMetadataSet integrity_metadata;
   integrity_metadata.insert(
       IntegrityMetadata("1234", IntegrityAlgorithm::kSha384).ToPair());
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   // Enforce
   Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeEnforce,
                            kContentSecurityPolicyHeaderSourceMeta);
@@ -604,7 +604,7 @@
   // Content-Security-Policy-Report-Only is not supported in meta element,
   // so nothing should be blocked
   policy = ContentSecurityPolicy::Create();
-  policy->BindToExecutionContext(execution_context.Get());
+  policy->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   policy->DidReceiveHeader("require-sri-for script style",
                            kContentSecurityPolicyHeaderTypeReport,
                            kContentSecurityPolicyHeaderSourceMeta);
@@ -667,7 +667,8 @@
 
     // Single enforce-mode policy should match `test.expected`:
     Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(execution_context.Get());
+    policy->BindToDelegate(
+        execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy,
                              kContentSecurityPolicyHeaderTypeEnforce,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -680,7 +681,8 @@
 
     // Single report-mode policy should always be `true`:
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(execution_context.Get());
+    policy->BindToDelegate(
+        execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy,
                              kContentSecurityPolicyHeaderTypeReport,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -727,7 +729,7 @@
 
     // Enforce 'script-src'
     Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(document);
+    policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("script-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeEnforce,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -739,7 +741,7 @@
 
     // Enforce 'style-src'
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(document);
+    policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("style-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeEnforce,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -751,7 +753,7 @@
 
     // Report 'script-src'
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(document);
+    policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("script-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeReport,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -762,7 +764,7 @@
 
     // Report 'style-src'
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(document);
+    policy->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(String("style-src ") + test.policy,
                              kContentSecurityPolicyHeaderTypeReport,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -832,7 +834,8 @@
 
     // Enforce / Report
     Persistent<ContentSecurityPolicy> policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(execution_context.Get());
+    policy->BindToDelegate(
+        execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
                              kContentSecurityPolicyHeaderTypeEnforce,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -854,7 +857,8 @@
 
     // Report / Enforce
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(execution_context.Get());
+    policy->BindToDelegate(
+        execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
                              kContentSecurityPolicyHeaderTypeReport,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -876,7 +880,8 @@
 
     // Enforce / Enforce
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(execution_context.Get());
+    policy->BindToDelegate(
+        execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
                              kContentSecurityPolicyHeaderTypeEnforce,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -893,7 +898,8 @@
 
     // Report / Report
     policy = ContentSecurityPolicy::Create();
-    policy->BindToExecutionContext(execution_context.Get());
+    policy->BindToDelegate(
+        execution_context->GetContentSecurityPolicyDelegate());
     policy->DidReceiveHeader(test.policy1,
                              kContentSecurityPolicyHeaderTypeReport,
                              kContentSecurityPolicyHeaderSourceHTTP);
@@ -1051,7 +1057,7 @@
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);  // https://example.com
   execution_context->SetURL(secure_url);                // https://example.com
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("default-src https://example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1091,7 +1097,7 @@
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);  // https://example.com
   execution_context->SetURL(secure_url);                // https://example.com
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("default-src https://example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1136,7 +1142,7 @@
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);  // https://example.com
   execution_context->SetURL(secure_url);                // https://example.com
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("default-src https://example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1179,7 +1185,7 @@
   execution_context = CreateExecutionContext();
   execution_context->SetSecurityOrigin(secure_origin);
   execution_context->SetURL(BlankURL());
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("script-src http://example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1359,14 +1365,14 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, TrustedTypesNoDirective) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("", kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
   EXPECT_TRUE(csp->AllowTrustedTypePolicy("somepolicy"));
 }
 
 TEST_F(ContentSecurityPolicyTest, TrustedTypesSimpleDirective) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("trusted-types one two three",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1377,7 +1383,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, TrustedTypesWhitespace) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("trusted-types one\ntwo\rthree",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1387,7 +1393,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, TrustedTypesEmpty) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("trusted-types",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1395,7 +1401,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, TrustedTypesStar) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("trusted-types *",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1403,7 +1409,7 @@
 }
 
 TEST_F(ContentSecurityPolicyTest, TrustedTypesReserved) {
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
   csp->DidReceiveHeader("trusted-types one \"two\" 'three'",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
@@ -1425,7 +1431,7 @@
   csp->DidReceiveHeader("sCrIpt-sRc http://example.com",
                         kContentSecurityPolicyHeaderTypeEnforce,
                         kContentSecurityPolicyHeaderSourceHTTP);
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
 
   EXPECT_TRUE(csp->AllowScriptFromSource(
       example_url, String(), IntegrityMetadataSet(), kParserInserted));
@@ -1439,7 +1445,7 @@
       "SCRipt-SRC http://example.com; script-src http://not-example.com;",
       kContentSecurityPolicyHeaderTypeEnforce,
       kContentSecurityPolicyHeaderSourceHTTP);
-  csp->BindToExecutionContext(execution_context.Get());
+  csp->BindToDelegate(execution_context->GetContentSecurityPolicyDelegate());
 
   EXPECT_TRUE(csp->AllowScriptFromSource(
       example_url, String(), IntegrityMetadataSet(), kParserInserted));
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
index c188a9d..9a9abf9 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.cc
@@ -276,8 +276,10 @@
   // If |url| is empty, fall back to the policy URL to ensure that <object>'s
   // without a `src` can be blocked/allowed, as they can still load plugins
   // even though they don't actually have a URL.
-  return !directive || directive->Allows(url.IsEmpty() ? policy_->Url() : url,
-                                         redirect_status);
+  return !directive ||
+         directive->Allows(
+             url.IsEmpty() ? policy_->FallbackUrlForPlugin() : url,
+             redirect_status);
 }
 
 bool CSPDirectiveList::CheckAncestors(SourceListDirective* directive,
@@ -958,8 +960,7 @@
       !CheckSource(
           OperativeDirective(ContentSecurityPolicy::DirectiveType::kBaseURI),
           url, redirect_status)) {
-    UseCounter::Count(policy_->GetDocument(),
-                      WebFeature::kBaseWouldBeBlockedByDefaultSrc);
+    policy_->Count(WebFeature::kBaseWouldBeBlockedByDefaultSrc);
   }
 
   return result;
@@ -1122,7 +1123,7 @@
   // The directive-name must be non-empty.
   if (name_begin == position) {
     // Malformed CSP: directive starts with invalid characters
-    UseCounter::Count(policy_->GetDocument(), WebFeature::kMalformedCSP);
+    policy_->Count(WebFeature::kMalformedCSP);
 
     SkipWhile<UChar, IsNotASCIISpace>(position, end);
     policy_->ReportUnsupportedDirective(
@@ -1138,7 +1139,7 @@
 
   if (!SkipExactly<UChar, IsASCIISpace>(position, end)) {
     // Malformed CSP: after the directive name we don't have a space
-    UseCounter::Count(policy_->GetDocument(), WebFeature::kMalformedCSP);
+    policy_->Count(WebFeature::kMalformedCSP);
 
     SkipWhile<UChar, IsNotASCIISpace>(position, end);
     policy_->ReportUnsupportedDirective(
@@ -1153,7 +1154,7 @@
 
   if (position != end) {
     // Malformed CSP: directive value has invalid characters
-    UseCounter::Count(policy_->GetDocument(), WebFeature::kMalformedCSP);
+    policy_->Count(WebFeature::kMalformedCSP);
 
     policy_->ReportInvalidDirectiveValueCharacter(
         *name, String(value_begin, static_cast<wtf_size_t>(end - value_begin)));
@@ -1257,33 +1258,56 @@
   ParseAndAppendReportEndpoints(value);
 }
 
+// For "report-uri" directive, this method corresponds to:
+// https://w3c.github.io/webappsec-csp/#report-violation
+// Step 3.4.2. For each token returned by splitting a string on ASCII whitespace
+// with directive's value as the input. [spec text]
+
+// For "report-to" directive, the spec says |value| is a single token
+// but we use the same logic as "report-uri" and thus we split |value| by
+// ASCII whitespaces.
+// https://w3c.github.io/webappsec-csp/#directive-report-to
+//
+// TODO(https://crbug.com/916265): Fix this inconsistency.
 void CSPDirectiveList::ParseAndAppendReportEndpoints(const String& value) {
   Vector<UChar> characters;
   value.AppendTo(characters);
 
+  // https://infra.spec.whatwg.org/#split-on-ascii-whitespace
+
+  // Step 2. Let tokens be a list of strings, initially empty. [spec text]
+  DCHECK(report_endpoints_.IsEmpty());
+
   const UChar* position = characters.data();
   const UChar* end = position + characters.size();
 
+  // Step 4. While position is not past the end of input: [spec text]
   while (position < end) {
+    // Step 3. Skip ASCII whitespace within input given position. [spec text]
+    // Step 4.3. Skip ASCII whitespace within input given position. [spec text]
+    //
+    // Note: IsASCIISpace returns true for U+000B which is not included in
+    // https://infra.spec.whatwg.org/#ascii-whitespace.
+    // TODO(mkwst): Investigate why the restrictions in the infra spec are
+    // different than those in Blink here.
     SkipWhile<UChar, IsASCIISpace>(position, end);
 
+    // Step 4.1. Let token be the result of collecting a sequence of code points
+    // that are not ASCII whitespace from input, given position. [spec text]
     const UChar* endpoint_begin = position;
     SkipWhile<UChar, IsNotASCIISpace>(position, end);
 
     if (endpoint_begin < position) {
+      // Step 4.2. Append token to tokens. [spec text]
       String endpoint = String(
           endpoint_begin, static_cast<wtf_size_t>(position - endpoint_begin));
       report_endpoints_.push_back(endpoint);
     }
   }
 
-  if (report_endpoints_.size() > 1) {
-    UseCounter::Count(policy_->GetDocument(),
-                      WebFeature::kReportUriMultipleEndpoints);
-  } else {
-    UseCounter::Count(policy_->GetDocument(),
-                      WebFeature::kReportUriSingleEndpoint);
-  }
+  policy_->Count(report_endpoints_.size() > 1
+                     ? WebFeature::kReportUriMultipleEndpoints
+                     : WebFeature::kReportUriSingleEndpoint);
 }
 
 template <class CSPDirectiveType>
diff --git a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
index dc32911..c56732b 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
+++ b/third_party/blink/renderer/core/frame/csp/csp_directive_list.h
@@ -380,6 +380,14 @@
 
   uint8_t require_sri_for_;
 
+  // If a "report-to" directive is used:
+  // - |report_endpoints_| is a list of token parsed from the "report-to"
+  //   directive's value, and
+  // - |use_reporting_api_| is true.
+  // Otherwise,
+  // - |report_endpoints_| is a list of uri-reference parsed from a
+  //   "report-uri" directive's value if any, and
+  // - |use_reporting_api_| is false.
   Vector<String> report_endpoints_;
   bool use_reporting_api_;
 
diff --git a/third_party/blink/renderer/core/frame/csp/csp_source.cc b/third_party/blink/renderer/core/frame/csp/csp_source.cc
index 5d41751d..85264b2 100644
--- a/third_party/blink/renderer/core/frame/csp/csp_source.cc
+++ b/third_party/blink/renderer/core/frame/csp/csp_source.cc
@@ -113,7 +113,6 @@
 }
 
 bool CSPSource::HostMatches(const String& host) const {
-  Document* document = policy_->GetDocument();
   bool match;
 
   bool equal_hosts = host_ == host;
@@ -130,10 +129,8 @@
     // the following count measures when a match fails that would have
     // passed the old, incorrect style, in case a lot of sites were
     // relying on that behavior.
-    if (document && equal_hosts) {
-      UseCounter::Count(*document,
-                        WebFeature::kCSPSourceWildcardWouldMatchExactHost);
-    }
+    if (equal_hosts)
+      policy_->Count(WebFeature::kCSPSourceWildcardWouldMatchExactHost);
   } else {
     // host-part = 1*host-char *( "." 1*host-char )
     match = equal_hosts;
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
new file mode 100644
index 0000000..50081f7
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.cc
@@ -0,0 +1,252 @@
+// 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/frame/csp/execution_context_csp_delegate.h"
+
+#include "third_party/blink/renderer/bindings/core/v8/source_location.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/events/security_policy_violation_event.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_client.h"
+#include "third_party/blink/renderer/core/frame/use_counter.h"
+#include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/ping_loader.h"
+#include "third_party/blink/renderer/core/probe/core_probes.h"
+#include "third_party/blink/renderer/core/workers/worker_global_scope.h"
+#include "third_party/blink/renderer/platform/network/encoded_form_data.h"
+#include "third_party/blink/renderer/platform/weborigin/reporting_service_proxy_ptr_holder.h"
+#include "third_party/blink/renderer/platform/weborigin/security_origin.h"
+
+namespace blink {
+
+ExecutionContextCSPDelegate::ExecutionContextCSPDelegate(
+    ExecutionContext& execution_context)
+    : execution_context_(&execution_context) {}
+
+void ExecutionContextCSPDelegate::Trace(blink::Visitor* visitor) {
+  visitor->Trace(execution_context_);
+  ContentSecurityPolicyDelegate::Trace(visitor);
+}
+
+const SecurityOrigin* ExecutionContextCSPDelegate::GetSecurityOrigin() {
+  return execution_context_->GetSecurityOrigin();
+}
+
+const KURL& ExecutionContextCSPDelegate::Url() const {
+  return execution_context_->Url();
+}
+
+void ExecutionContextCSPDelegate::SetSandboxFlags(SandboxFlags mask) {
+  GetSecurityContext().EnforceSandboxFlags(mask);
+}
+
+void ExecutionContextCSPDelegate::SetAddressSpace(mojom::IPAddressSpace space) {
+  GetSecurityContext().SetAddressSpace(space);
+}
+
+void ExecutionContextCSPDelegate::SetRequireTrustedTypes() {
+  GetSecurityContext().SetRequireTrustedTypes();
+}
+
+void ExecutionContextCSPDelegate::AddInsecureRequestPolicy(
+    WebInsecureRequestPolicy policy) {
+  SecurityContext& security_context = GetSecurityContext();
+
+  Document* document = GetDocument();
+
+  // Step 2. Set settings’s insecure requests policy to Upgrade. [spec text]
+  // Upgrade Insecure Requests: Update the policy.
+  security_context.SetInsecureRequestPolicy(
+      security_context.GetInsecureRequestPolicy() | policy);
+  if (document)
+    document->DidEnforceInsecureRequestPolicy();
+
+  // Upgrade Insecure Requests: Update the set of insecure URLs to upgrade.
+  if (policy & kUpgradeInsecureRequests) {
+    // Spec: Enforcing part of:
+    // https://w3c.github.io/webappsec-upgrade-insecure-requests/#delivery
+    // Step 3. Let tuple be a tuple of the protected resource’s URL's host and
+    // port. [spec text]
+    // Step 4. Insert tuple into settings’s upgrade insecure navigations set.
+    // [spec text]
+    Count(WebFeature::kUpgradeInsecureRequestsEnabled);
+    if (!Url().Host().IsEmpty()) {
+      uint32_t hash = Url().Host().Impl()->GetHash();
+      security_context.AddInsecureNavigationUpgrade(hash);
+      if (document)
+        document->DidEnforceInsecureNavigationsSet();
+    }
+  }
+}
+
+std::unique_ptr<SourceLocation>
+ExecutionContextCSPDelegate::GetSourceLocation() {
+  return SourceLocation::Capture(execution_context_);
+}
+
+base::Optional<uint16_t> ExecutionContextCSPDelegate::GetStatusCode() {
+  base::Optional<uint16_t> status_code;
+
+  // TODO(mkwst): We only have status code information for Documents. It would
+  // be nice to get them for Workers as well.
+  Document* document = GetDocument();
+  if (document && !SecurityOrigin::IsSecure(document->Url()) &&
+      document->Loader()) {
+    status_code = document->Loader()->GetResponse().HttpStatusCode();
+  }
+
+  return status_code;
+}
+
+String ExecutionContextCSPDelegate::GetDocumentReferrer() {
+  String referrer;
+
+  // TODO(mkwst): We only have referrer information for Documents. It would be
+  // nice to get them for Workers as well.
+  if (Document* document = GetDocument())
+    referrer = document->referrer();
+  return referrer;
+}
+
+void ExecutionContextCSPDelegate::DispatchViolationEvent(
+    const SecurityPolicyViolationEventInit& violation_data,
+    Element* element) {
+  execution_context_->GetTaskRunner(TaskType::kNetworking)
+      ->PostTask(
+          FROM_HERE,
+          WTF::Bind(
+              &ExecutionContextCSPDelegate::DispatchViolationEventInternal,
+              WrapPersistent(this), WrapPersistent(&violation_data),
+              WrapPersistent(element)));
+}
+
+void ExecutionContextCSPDelegate::PostViolationReport(
+    const SecurityPolicyViolationEventInit& violation_data,
+    const String& stringified_report,
+    bool is_frame_ancestors_violation,
+    const Vector<String>& report_endpoints,
+    bool use_reporting_api) {
+  DCHECK_EQ(is_frame_ancestors_violation,
+            ContentSecurityPolicy::DirectiveType::kFrameAncestors ==
+                ContentSecurityPolicy::GetDirectiveType(
+                    violation_data.effectiveDirective()));
+
+  // TODO(mkwst): Support POSTing violation reports from a Worker.
+  Document* document = GetDocument();
+  if (!document)
+    return;
+
+  LocalFrame* frame = document->GetFrame();
+  if (!frame)
+    return;
+
+  scoped_refptr<EncodedFormData> report =
+      EncodedFormData::Create(stringified_report.Utf8());
+
+  DEFINE_STATIC_LOCAL(ReportingServiceProxyPtrHolder,
+                      reporting_service_proxy_holder, ());
+
+  for (const auto& report_endpoint : report_endpoints) {
+    if (use_reporting_api) {
+      // https://w3c.github.io/webappsec-csp/#report-violation
+      // Step 3.5. If violation’s policy’s directive set contains a directive
+      // named "report-to" (directive): [spec text]
+      //
+      // https://w3c.github.io/reporting/#queue-report
+      // Step 2. If url was not provided by the caller, let url be settings’s
+      // creation URL. [spec text]
+      reporting_service_proxy_holder.QueueCspViolationReport(
+          Url(), report_endpoint, &violation_data);
+      continue;
+    }
+
+    // Use the frame's document to complete the endpoint URL, overriding its URL
+    // with the blocked document's URL.
+    // https://w3c.github.io/webappsec-csp/#report-violation
+    // Step 3.4.2.1. Let endpoint be the result of executing the URL parser with
+    // token as the input, and violation’s url as the base URL. [spec text]
+    KURL url = is_frame_ancestors_violation
+                   ? document->CompleteURLWithOverride(
+                         report_endpoint, KURL(violation_data.blockedURI()))
+                   // We use the FallbackBaseURL to ensure that we don't
+                   // respect base elements when determining the report
+                   // endpoint URL.
+                   // Note: According to Step 3.4.2.1 mentioned above, the base
+                   // URL is "violation’s url" which should be violation's
+                   // global object's URL. So using FallbackBaseURL() might be
+                   // inconsistent.
+                   : document->CompleteURLWithOverride(
+                         report_endpoint, document->FallbackBaseURL());
+    PingLoader::SendViolationReport(
+        frame, url, report, PingLoader::kContentSecurityPolicyViolationReport);
+  }
+}
+
+void ExecutionContextCSPDelegate::Count(WebFeature feature) {
+  UseCounter::Count(execution_context_, feature);
+}
+
+void ExecutionContextCSPDelegate::AddConsoleMessage(
+    ConsoleMessage* console_message) {
+  execution_context_->AddConsoleMessage(console_message);
+}
+
+void ExecutionContextCSPDelegate::DisableEval(const String& error_message) {
+  execution_context_->DisableEval(error_message);
+}
+
+void ExecutionContextCSPDelegate::ReportBlockedScriptExecutionToInspector(
+    const String& directive_text) {
+  probe::scriptExecutionBlockedByCSP(execution_context_, directive_text);
+}
+
+void ExecutionContextCSPDelegate::DidAddContentSecurityPolicies(
+    const blink::WebVector<WebContentSecurityPolicy>& policies) {
+  Document* document = GetDocument();
+  if (document && document->GetFrame())
+    document->GetFrame()->Client()->DidAddContentSecurityPolicies(policies);
+}
+
+SecurityContext& ExecutionContextCSPDelegate::GetSecurityContext() {
+  return execution_context_->GetSecurityContext();
+}
+
+Document* ExecutionContextCSPDelegate::GetDocument() {
+  return DynamicTo<Document>(execution_context_.Get());
+}
+
+void ExecutionContextCSPDelegate::DispatchViolationEventInternal(
+    const SecurityPolicyViolationEventInit* violation_data,
+    Element* element) {
+  // Worklets don't support Events in general.
+  if (execution_context_->IsWorkletGlobalScope())
+    return;
+
+  // https://w3c.github.io/webappsec-csp/#report-violation.
+  // Step 3.1. If target is not null, and global is a Window, and target’s
+  // shadow-including root is not global’s associated Document, set target to
+  // null. [spec text]
+  // Step 3.2. If target is null:
+  //    Step 3.2.1. Set target be violation’s global object.
+  //    Step 3.2.2. If target is a Window, set target to target’s associated
+  //    Document. [spec text]
+  // Step 3.3. Fire an event named securitypolicyviolation that uses the
+  // SecurityPolicyViolationEvent interface at target.. [spec text]
+  SecurityPolicyViolationEvent& event = *SecurityPolicyViolationEvent::Create(
+      event_type_names::kSecuritypolicyviolation, violation_data);
+  DCHECK(event.bubbles());
+
+  if (auto* document = GetDocument()) {
+    if (element && element->isConnected() && element->GetDocument() == document)
+      element->EnqueueEvent(event, TaskType::kInternalDefault);
+    else
+      document->EnqueueEvent(event, TaskType::kInternalDefault);
+  } else if (auto* scope = DynamicTo<WorkerGlobalScope>(*execution_context_)) {
+    scope->EnqueueEvent(event, TaskType::kInternalDefault);
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
new file mode 100644
index 0000000..7ab27c24
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/csp/execution_context_csp_delegate.h
@@ -0,0 +1,62 @@
+// 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_FRAME_CSP_EXECUTION_CONTEXT_CSP_DELEGATE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_EXECUTION_CONTEXT_CSP_DELEGATE_H_
+
+#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
+
+namespace blink {
+
+class Document;
+class ExecutionContext;
+class SecurityContext;
+
+class ExecutionContextCSPDelegate final
+    : public GarbageCollected<ExecutionContextCSPDelegate>,
+      public ContentSecurityPolicyDelegate {
+  USING_GARBAGE_COLLECTED_MIXIN(ExecutionContextCSPDelegate);
+
+ public:
+  explicit ExecutionContextCSPDelegate(ExecutionContext&);
+
+  void Trace(blink::Visitor*) override;
+
+  // ContentSecurityPolicyDelegate overrides:
+  const SecurityOrigin* GetSecurityOrigin() override;
+  const KURL& Url() const override;
+  void SetSandboxFlags(SandboxFlags) override;
+  void SetAddressSpace(mojom::IPAddressSpace) override;
+  void SetRequireTrustedTypes() override;
+  void AddInsecureRequestPolicy(WebInsecureRequestPolicy) override;
+  std::unique_ptr<SourceLocation> GetSourceLocation() override;
+  base::Optional<uint16_t> GetStatusCode() override;
+  String GetDocumentReferrer() override;
+  void DispatchViolationEvent(const SecurityPolicyViolationEventInit&,
+                              Element*) override;
+  void PostViolationReport(const SecurityPolicyViolationEventInit&,
+                           const String& stringified_report,
+                           bool is_frame_ancestors_violation,
+                           const Vector<String>& report_endpoints,
+                           bool use_reporting_api) override;
+  void Count(WebFeature) override;
+  void AddConsoleMessage(ConsoleMessage*) override;
+  void DisableEval(const String& error_message) override;
+  void ReportBlockedScriptExecutionToInspector(
+      const String& directive_text) override;
+  void DidAddContentSecurityPolicies(
+      const blink::WebVector<WebContentSecurityPolicy>&) override;
+
+ private:
+  SecurityContext& GetSecurityContext();
+  Document* GetDocument();
+  void DispatchViolationEventInternal(const SecurityPolicyViolationEventInit*,
+                                      Element*);
+
+  const Member<ExecutionContext> execution_context_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_CSP_EXECUTION_CONTEXT_CSP_DELEGATE_H_
diff --git a/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc b/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
index ff0b713..236e891 100644
--- a/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
+++ b/third_party/blink/renderer/core/frame/csp/source_list_directive_test.cc
@@ -36,7 +36,7 @@
         SecurityOrigin::Create(secure_url));
     document = Document::CreateForTest();
     document->SetSecurityOrigin(secure_origin);
-    csp->BindToExecutionContext(document.Get());
+    csp->BindToDelegate(document->GetContentSecurityPolicyDelegate());
   }
 
   ContentSecurityPolicy* SetUpWithOrigin(const String& origin) {
@@ -46,7 +46,7 @@
     Document* document = Document::CreateForTest();
     document->SetSecurityOrigin(secure_origin);
     ContentSecurityPolicy* csp = ContentSecurityPolicy::Create();
-    csp->BindToExecutionContext(document);
+    csp->BindToDelegate(document->GetContentSecurityPolicyDelegate());
     return csp;
   }
 
diff --git a/third_party/blink/renderer/core/html/parser/preload_request.cc b/third_party/blink/renderer/core/html/parser/preload_request.cc
index 892cf94..6182fd8 100644
--- a/third_party/blink/renderer/core/html/parser/preload_request.cc
+++ b/third_party/blink/renderer/core/html/parser/preload_request.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
+#include "third_party/blink/renderer/core/loader/link_loader.h"
 #include "third_party/blink/renderer/core/script/document_write_intervention.h"
 #include "third_party/blink/renderer/core/script/script_loader.h"
 #include "third_party/blink/renderer/platform/cross_origin_attribute_value.h"
@@ -113,7 +114,7 @@
     }
   }
 
-  return document->Loader()->StartPreload(resource_type_, params);
+  return LinkLoader::StartPreload(resource_type_, params, document->Fetcher());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index a0bbaf0..4b4261e1 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -55,7 +55,6 @@
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
-#include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
 #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
@@ -67,10 +66,6 @@
 #include "third_party/blink/renderer/core/loader/link_loader.h"
 #include "third_party/blink/renderer/core/loader/network_hints_interface.h"
 #include "third_party/blink/renderer/core/loader/progress_tracker.h"
-#include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/image_resource.h"
-#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
 #include "third_party/blink/renderer/core/loader/subresource_filter.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
 #include "third_party/blink/renderer/core/origin_trials/origin_trials.h"
@@ -266,44 +261,6 @@
   return request_.Url();
 }
 
-Resource* DocumentLoader::StartPreload(ResourceType type,
-                                       FetchParameters& params) {
-  Resource* resource = nullptr;
-  switch (type) {
-    case ResourceType::kImage:
-      resource = ImageResource::Fetch(params, Fetcher());
-      break;
-    case ResourceType::kScript:
-      params.SetRequestContext(mojom::RequestContextType::SCRIPT);
-      resource = ScriptResource::Fetch(params, Fetcher(), nullptr,
-                                       ScriptResource::kAllowStreaming);
-      break;
-    case ResourceType::kCSSStyleSheet:
-      resource = CSSStyleSheetResource::Fetch(params, Fetcher(), nullptr);
-      break;
-    case ResourceType::kFont:
-      resource = FontResource::Fetch(params, Fetcher(), nullptr);
-      break;
-    case ResourceType::kAudio:
-    case ResourceType::kVideo:
-      resource = RawResource::FetchMedia(params, Fetcher(), nullptr);
-      break;
-    case ResourceType::kTextTrack:
-      resource = RawResource::FetchTextTrack(params, Fetcher(), nullptr);
-      break;
-    case ResourceType::kImportResource:
-      resource = RawResource::FetchImport(params, Fetcher(), nullptr);
-      break;
-    case ResourceType::kRaw:
-      resource = RawResource::Fetch(params, Fetcher(), nullptr);
-      break;
-    default:
-      NOTREACHED();
-  }
-
-  return resource;
-}
-
 void DocumentLoader::SetServiceWorkerNetworkProvider(
     std::unique_ptr<WebServiceWorkerNetworkProvider> provider) {
   service_worker_network_provider_ = std::move(provider);
diff --git a/third_party/blink/renderer/core/loader/document_loader.h b/third_party/blink/renderer/core/loader/document_loader.h
index 8530825..02b4d7f 100644
--- a/third_party/blink/renderer/core/loader/document_loader.h
+++ b/third_party/blink/renderer/core/loader/document_loader.h
@@ -209,8 +209,6 @@
   void DispatchLinkHeaderPreloads(ViewportDescriptionWrapper*,
                                   LinkLoader::MediaPreloadPolicy);
 
-  Resource* StartPreload(ResourceType, FetchParameters&);
-
   void SetServiceWorkerNetworkProvider(
       std::unique_ptr<WebServiceWorkerNetworkProvider>);
 
diff --git a/third_party/blink/renderer/core/loader/link_loader.cc b/third_party/blink/renderer/core/loader/link_loader.cc
index 89e90d4..3b99308 100644
--- a/third_party/blink/renderer/core/loader/link_loader.cc
+++ b/third_party/blink/renderer/core/loader/link_loader.cc
@@ -53,7 +53,10 @@
 #include "third_party/blink/renderer/core/loader/network_hints_interface.h"
 #include "third_party/blink/renderer/core/loader/private/prerender_handle.h"
 #include "third_party/blink/renderer/core/loader/resource/css_style_sheet_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/font_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/image_resource.h"
 #include "third_party/blink/renderer/core/loader/resource/link_fetch_resource.h"
+#include "third_party/blink/renderer/core/loader/resource/script_resource.h"
 #include "third_party/blink/renderer/core/loader/subresource_integrity_helper.h"
 #include "third_party/blink/renderer/core/script/module_script.h"
 #include "third_party/blink/renderer/core/script/script_loader.h"
@@ -438,8 +441,8 @@
         String("Preload triggered for " + url.Host() + url.GetPath())));
   }
   link_fetch_params.SetLinkPreload(true);
-  return document.Loader()->StartPreload(resource_type.value(),
-                                         link_fetch_params);
+  return LinkLoader::StartPreload(resource_type.value(), link_fetch_params,
+                                  document.Fetcher());
 }
 
 // https://html.spec.whatwg.org/multipage/links.html#link-type-modulepreload
@@ -642,6 +645,46 @@
   }
 }
 
+Resource* LinkLoader::StartPreload(ResourceType type,
+                                   FetchParameters& params,
+                                   ResourceFetcher* resource_fetcher) {
+  Resource* resource = nullptr;
+  switch (type) {
+    case ResourceType::kImage:
+      resource = ImageResource::Fetch(params, resource_fetcher);
+      break;
+    case ResourceType::kScript:
+      params.SetRequestContext(mojom::RequestContextType::SCRIPT);
+      resource = ScriptResource::Fetch(params, resource_fetcher, nullptr,
+                                       ScriptResource::kAllowStreaming);
+      break;
+    case ResourceType::kCSSStyleSheet:
+      resource =
+          CSSStyleSheetResource::Fetch(params, resource_fetcher, nullptr);
+      break;
+    case ResourceType::kFont:
+      resource = FontResource::Fetch(params, resource_fetcher, nullptr);
+      break;
+    case ResourceType::kAudio:
+    case ResourceType::kVideo:
+      resource = RawResource::FetchMedia(params, resource_fetcher, nullptr);
+      break;
+    case ResourceType::kTextTrack:
+      resource = RawResource::FetchTextTrack(params, resource_fetcher, nullptr);
+      break;
+    case ResourceType::kImportResource:
+      resource = RawResource::FetchImport(params, resource_fetcher, nullptr);
+      break;
+    case ResourceType::kRaw:
+      resource = RawResource::Fetch(params, resource_fetcher, nullptr);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  return resource;
+}
+
 bool LinkLoader::LoadLink(
     const LinkLoadParameters& params,
     Document& document,
diff --git a/third_party/blink/renderer/core/loader/link_loader.h b/third_party/blink/renderer/core/loader/link_loader.h
index 75674849..6eca21d1 100644
--- a/third_party/blink/renderer/core/loader/link_loader.h
+++ b/third_party/blink/renderer/core/loader/link_loader.h
@@ -144,6 +144,9 @@
                                   CanLoadResources,
                                   MediaPreloadPolicy,
                                   ViewportDescriptionWrapper*);
+  static Resource* StartPreload(ResourceType,
+                                FetchParameters&,
+                                ResourceFetcher*);
   static base::Optional<ResourceType> GetResourceTypeFromAsAttribute(
       const String& as);
 
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.cc b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
index 680bc1d..64250bc5 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.cc
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.cc
@@ -35,26 +35,13 @@
 
 WorkerFetchContext::~WorkerFetchContext() = default;
 
-WorkerFetchContext* WorkerFetchContext::Create(
-    WorkerOrWorkletGlobalScope& global_scope,
-    scoped_refptr<WebWorkerFetchContext> web_context,
-    SubresourceFilter* subresource_filter,
-    FetchClientSettingsObject* fetch_client_settings_object) {
-  if (!web_context)
-    return nullptr;
-  DCHECK(fetch_client_settings_object);
-  return MakeGarbageCollected<WorkerFetchContext>(
-      global_scope, std::move(web_context), subresource_filter,
-      fetch_client_settings_object);
-}
-
 WorkerFetchContext::WorkerFetchContext(
     WorkerOrWorkletGlobalScope& global_scope,
     scoped_refptr<WebWorkerFetchContext> web_context,
     SubresourceFilter* subresource_filter,
-    FetchClientSettingsObject* fetch_client_settings_object)
+    FetchClientSettingsObject& fetch_client_settings_object)
     : BaseFetchContext(global_scope.GetTaskRunner(TaskType::kInternalLoading),
-                       *fetch_client_settings_object),
+                       fetch_client_settings_object),
       global_scope_(global_scope),
       web_context_(std::move(web_context)),
       subresource_filter_(subresource_filter),
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.h b/third_party/blink/renderer/core/loader/worker_fetch_context.h
index 5e68855..3a793d27 100644
--- a/third_party/blink/renderer/core/loader/worker_fetch_context.h
+++ b/third_party/blink/renderer/core/loader/worker_fetch_context.h
@@ -28,15 +28,10 @@
 // service workers) and threaded worklets (animation and audio worklets).
 class WorkerFetchContext final : public BaseFetchContext {
  public:
-  static WorkerFetchContext* Create(WorkerOrWorkletGlobalScope&,
-                                    scoped_refptr<WebWorkerFetchContext>,
-                                    SubresourceFilter*,
-                                    FetchClientSettingsObject*);
-
   WorkerFetchContext(WorkerOrWorkletGlobalScope&,
                      scoped_refptr<WebWorkerFetchContext>,
                      SubresourceFilter*,
-                     FetchClientSettingsObject*);
+                     FetchClientSettingsObject&);
   ~WorkerFetchContext() override;
 
   // BaseFetchContext implementation:
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 5a901cc..d8deec2d 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -841,6 +841,8 @@
 
   // Some descendants under a pagination container (e.g. composited objects
   // in SPv1 and column spanners) may escape fragment clips.
+  // TODO(crbug.com/803649): Remove this when we fix fragment clip hierarchy
+  // issues.
   if (layer->EnclosingPaginationLayer())
     return false;
 
@@ -2352,17 +2354,29 @@
   // should also skip any fragment clip created by the skipped pagination
   // container. We also need to skip fragment clip if the object is a paint
   // invalidation container which doesn't allow fragmentation.
+  // TODO(crbug.com/803649): This may also skip necessary clips under the
+  // skipped fragment clip.
   if (object_.IsColumnSpanAll() ||
       (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
        object_.IsPaintInvalidationContainer() &&
        ToLayoutBoxModelObject(object_).Layer()->EnclosingPaginationLayer())) {
     if (const auto* pagination_layer_in_tree_hierarchy =
             object_.Parent()->EnclosingLayer()->EnclosingPaginationLayer()) {
-      const auto* properties =
-          pagination_layer_in_tree_hierarchy->GetLayoutObject()
-              .FirstFragment()
-              .PaintProperties();
+      const auto& clip_container =
+          pagination_layer_in_tree_hierarchy->GetLayoutObject();
+      const auto* properties = clip_container.FirstFragment().PaintProperties();
       if (properties && properties->FragmentClip()) {
+        // However, because we don't allow an object's clip to escape the
+        // output clip of the object's effect, we can't skip fragment clip if
+        // between this object and the container there is any effect that has
+        // an output clip. TODO(crbug.com/803649): Fix this workaround.
+        const auto* clip_container_effect =
+            clip_container.FirstFragment().PostIsolationEffect();
+        for (const auto* effect = context_.fragments[0].current_effect;
+             effect != clip_container_effect; effect = effect->Parent()) {
+          if (effect->OutputClip())
+            return;
+        }
         context_.fragments[0].current.clip =
             properties->FragmentClip()->Parent();
       }
diff --git a/third_party/blink/renderer/core/script/script_loader.h b/third_party/blink/renderer/core/script/script_loader.h
index 0d243ad..689d62b1 100644
--- a/third_party/blink/renderer/core/script/script_loader.h
+++ b/third_party/blink/renderer/core/script/script_loader.h
@@ -42,6 +42,7 @@
 namespace blink {
 
 class Resource;
+class ResourceFetcher;
 class ScriptElementBase;
 class Script;
 class ScriptResource;
diff --git a/third_party/blink/renderer/core/testing/null_execution_context.cc b/third_party/blink/renderer/core/testing/null_execution_context.cc
index 1fdf44f8..6bcc92f 100644
--- a/third_party/blink/renderer/core/testing/null_execution_context.cc
+++ b/third_party/blink/renderer/core/testing/null_execution_context.cc
@@ -30,7 +30,7 @@
 void NullExecutionContext::SetUpSecurityContext() {
   ContentSecurityPolicy* policy = ContentSecurityPolicy::Create();
   SecurityContext::SetSecurityOrigin(SecurityOrigin::Create(url_));
-  policy->BindToExecutionContext(this);
+  policy->BindToDelegate(GetContentSecurityPolicyDelegate());
   SecurityContext::SetContentSecurityPolicy(policy);
 }
 
diff --git a/third_party/blink/renderer/core/workers/worker_global_scope.cc b/third_party/blink/renderer/core/workers/worker_global_scope.cc
index baa2c49..6d7e1b9 100644
--- a/third_party/blink/renderer/core/workers/worker_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_global_scope.cc
@@ -610,7 +610,8 @@
     SetContentSecurityPolicy(csp);
   }
   GetContentSecurityPolicy()->DidReceiveHeaders(headers);
-  GetContentSecurityPolicy()->BindToExecutionContext(GetExecutionContext());
+  GetContentSecurityPolicy()->BindToDelegate(
+      GetContentSecurityPolicyDelegate());
 }
 
 void WorkerGlobalScope::ExceptionThrown(ErrorEvent* event) {
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index f28c26d..740540f5 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -131,10 +131,14 @@
 ResourceFetcher* WorkerOrWorkletGlobalScope::CreateFetcherInternal(
     FetchClientSettingsObject* fetch_client_settings_object) {
   DCHECK(IsContextThread());
+  DCHECK(fetch_client_settings_object);
   InitializeWebFetchContextIfNeeded();
-  WorkerFetchContext* fetch_context = WorkerFetchContext::Create(
-      *this, web_worker_fetch_context_, subresource_filter_,
-      fetch_client_settings_object);
+  WorkerFetchContext* fetch_context =
+      web_worker_fetch_context_
+          ? MakeGarbageCollected<WorkerFetchContext>(
+                *this, web_worker_fetch_context_, subresource_filter_,
+                *fetch_client_settings_object)
+          : nullptr;
   ResourceFetcher* resource_fetcher =
       MakeGarbageCollected<ResourceFetcher>(fetch_context);
   if (IsContextPaused())
@@ -212,7 +216,8 @@
 
 void WorkerOrWorkletGlobalScope::BindContentSecurityPolicyToExecutionContext() {
   DCHECK(IsContextThread());
-  GetContentSecurityPolicy()->BindToExecutionContext(GetExecutionContext());
+  GetContentSecurityPolicy()->BindToDelegate(
+      GetContentSecurityPolicyDelegate());
 }
 
 // Implementation of the "fetch a module worker script graph" algorithm in the
diff --git a/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js b/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
index 7488c35..5ac6b17 100644
--- a/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
+++ b/third_party/blink/renderer/devtools/front_end/data_grid/DataGrid.js
@@ -810,7 +810,7 @@
    * @param {!Event} event
    */
   _keyDown(event) {
-    if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing)
+    if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing || UI.isEditing())
       return;
 
     let handled = false;
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js b/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js
index 1ed148b..fba72354 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js
+++ b/third_party/blink/renderer/devtools/front_end/timeline/TimelineDetailsView.js
@@ -126,8 +126,10 @@
   }
 
   _updateContentsFromWindow() {
-    if (!this._model)
+    if (!this._model) {
+      this._setContent(UI.html`<div/>`);
       return;
+    }
     const window = this._model.window();
     this._updateSelectedRangeStats(window.left, window.right);
     this._updateContents();
diff --git a/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css b/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
index 24a3e64..7ee4ac9 100644
--- a/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
+++ b/third_party/blink/renderer/devtools/front_end/timeline/timelinePanel.css
@@ -99,7 +99,7 @@
 }
 
 .timeline.panel .status-pane-container.tinted {
-    background-color: hsla(0, 0%, 90%, 0.8);
+    background-color: lightgray;
     pointer-events: auto;
 }
 
diff --git a/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc b/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
index d9d33691..441b1ae 100644
--- a/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
+++ b/third_party/blink/renderer/modules/media_controls/elements/media_control_input_element.cc
@@ -208,6 +208,11 @@
     MaybeRecordInteracted();
   }
 
+  // Unhover the element if the hover is triggered by a tap on
+  // a touch screen device to avoid showing hover circle indefinitely.
+  if (event.IsGestureEvent() && IsHovered())
+    SetHovered(false);
+
   HTMLInputElement::DefaultEventHandler(event);
 }
 
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
index a018200..163241d 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -58,6 +58,7 @@
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_animated_arrow_container_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_button_panel_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_cast_button_element.h"
+#include "third_party/blink/renderer/modules/media_controls/elements/media_control_consts.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_current_time_display_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_display_cutout_fullscreen_button_element.h"
 #include "third_party/blink/renderer/modules/media_controls/elements/media_control_download_button_element.h"
@@ -694,8 +695,14 @@
 
   // On modern controls, the volume slider is to the left of the mute button.
   if (IsModern()) {
-    MaybeParserAppendChild(button_panel, volume_slider_);
-    button_panel->ParserAppendChild(mute_button_);
+    volume_control_container_ = MediaControlElementsHelper::CreateDiv(
+        "-webkit-media-controls-volume-control-container", button_panel);
+    MediaControlElementsHelper::CreateDiv(
+        "-webkit-media-controls-volume-control-hover-background",
+        volume_control_container_);
+    MaybeParserAppendChild(volume_control_container_, volume_slider_);
+    volume_control_container_->ParserAppendChild(mute_button_);
+    HideVolumeControlHoverBackground();
   } else {
     button_panel->ParserAppendChild(mute_button_);
     MaybeParserAppendChild(button_panel, volume_slider_);
@@ -714,6 +721,19 @@
   }
 
   button_panel->ParserAppendChild(overflow_menu_);
+
+  // Attach hover background div to modern controls
+  if (IsModern()) {
+    AttachHoverBackground(play_button_);
+    AttachHoverBackground(fullscreen_button_);
+    AttachHoverBackground(overflow_menu_);
+  }
+}
+
+void MediaControlsImpl::AttachHoverBackground(Element* element) {
+  MediaControlElementsHelper::CreateDiv(
+      "-internal-media-controls-button-hover-background",
+      element->GetShadowRoot());
 }
 
 Node::InsertionNotificationRequest MediaControlsImpl::InsertedInto(
@@ -1380,6 +1400,9 @@
                     ((controls_size.width - element_size.width) >= 0);
     element->SetDoesFit(does_fit);
 
+    if (element == mute_button_.Get() && IsModern())
+      SetVolumeControlContainerIsWanted(does_fit);
+
     // The element does fit and is sticky so we should allocate space for it. If
     // we cannot fit this element we should stop allocating space for other
     // elements.
@@ -1408,6 +1431,9 @@
       controls_size.width < overflow_icon_width) {
     last_element->SetDoesFit(false);
     last_element->SetOverflowElementIsWanted(true);
+
+    if (last_element == mute_button_.Get() && IsModern())
+      SetVolumeControlContainerIsWanted(false);
   }
 
   MaybeRecordElementsDisplayed();
@@ -2273,6 +2299,7 @@
 
 void MediaControlsImpl::VolumeSliderWantedTimerFired(TimerBase*) {
   volume_slider_->OpenSlider();
+  ShowVolumeControlHoverBackground();
 }
 
 void MediaControlsImpl::OpenVolumeSliderIfNecessary() {
@@ -2292,12 +2319,31 @@
 void MediaControlsImpl::CloseVolumeSliderIfNecessary() {
   if (ShouldCloseVolumeSlider()) {
     volume_slider_->CloseSlider();
+    HideVolumeControlHoverBackground();
 
     if (volume_slider_wanted_timer_.IsActive())
       volume_slider_wanted_timer_.Stop();
   }
 }
 
+void MediaControlsImpl::ShowVolumeControlHoverBackground() {
+  volume_control_container_->classList().Remove(kClosedCSSClass);
+}
+
+void MediaControlsImpl::HideVolumeControlHoverBackground() {
+  volume_control_container_->classList().Add(kClosedCSSClass);
+}
+
+void MediaControlsImpl::SetVolumeControlContainerIsWanted(
+    bool is_wanted) const {
+  if (is_wanted) {
+    volume_control_container_->RemoveInlineStyleProperty(CSSPropertyDisplay);
+  } else {
+    volume_control_container_->SetInlineStyleProperty(CSSPropertyDisplay,
+                                                      CSSValueNone);
+  }
+}
+
 bool MediaControlsImpl::ShouldOpenVolumeSlider() const {
   if (!volume_slider_ || !IsModern())
     return false;
@@ -2380,6 +2426,7 @@
   visitor->Trace(media_button_panel_);
   visitor->Trace(loading_panel_);
   visitor->Trace(display_cutout_fullscreen_button_);
+  visitor->Trace(volume_control_container_);
   MediaControls::Trace(visitor);
   HTMLDivElement::Trace(visitor);
 }
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
index 869dab8..060127f9b 100644
--- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
+++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.h
@@ -248,6 +248,9 @@
   void InitializeControls();
   void PopulatePanel();
 
+  // Attach hover background div to buttons
+  void AttachHoverBackground(Element*);
+
   void MakeOpaque();
   void MakeOpaqueFromPointerEvent();
   void MakeTransparent();
@@ -278,6 +281,9 @@
 
   bool ShouldOpenVolumeSlider() const;
   bool ShouldCloseVolumeSlider() const;
+  void ShowVolumeControlHoverBackground();
+  void HideVolumeControlHoverBackground();
+  void SetVolumeControlContainerIsWanted(bool) const;
 
   void ElementSizeChangedTimerFired(TimerBase*);
 
@@ -392,6 +398,8 @@
   bool is_paused_for_scrubbing_ : 1;
   bool is_scrubbing_ = false;
 
+  Member<HTMLDivElement> volume_control_container_;
+
   // Watches the video element for resize and updates media controls as
   // necessary.
   Member<ResizeObserver> resize_observer_;
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 0715555..8b06a21c 100644
--- a/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
+++ b/third_party/blink/renderer/modules/media_controls/resources/modernMediaControls.css
@@ -170,7 +170,6 @@
 /**
  * Media Buttons
  */
-
 audio::-webkit-media-controls-play-button,
 video::-webkit-media-controls-play-button,
 audio::-webkit-media-controls-mute-button,
@@ -191,8 +190,14 @@
   background-size: 24px;
   background-repeat: no-repeat;
   background-position: center center;
+
+  /*
+   * Width should change to 48px when we have new audio
+   * control specs. Button tap target in audio and video
+   * controls should be same.
+   */
   width: 32px;
-  height: 32px;
+  height: 48px;
   min-width: 32px;
   padding: 0;
   border-width: 0;
@@ -201,6 +206,93 @@
   cursor: pointer;
 }
 
+/*
+ * Each hover background div's positioning rules
+ * are relative to their parent.
+ */
+video::-webkit-media-controls-play-button,
+audio::-webkit-media-controls-play-button,
+video::-webkit-media-controls-fullscreen-button,
+audio::-webkit-media-controls-fullscreen-button,
+video::-internal-media-controls-overflow-button,
+audio::-internal-media-controls-overflow-button {
+  position: relative;
+}
+
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background {
+  background-color: rgba(32, 33, 36, 0);
+  background-size: 24px;
+  background-repeat: no-repeat;
+  background-position: center center;
+  position: absolute;
+  width: 36px;
+  height: 36px;
+  border-radius: 18px;
+  left: 6px;
+  top: 6px;
+  transition: background-color .25s;
+  pointer-events: none;
+  z-index: -1;
+}
+
+/*
+ * Audio control hover circle size should be same as video controls'. Due to increase of audio control tap target
+ * will break the layout when width is 300. We'll shrink the hover circle here. Should remove this rule once the new
+ * audio control layout specs are out
+ */
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background {
+  width: 32px;
+  height: 32px;
+  left: 0;
+  top: 8px;
+  border-radius: 16px;
+}
+
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:focus::-internal-media-controls-button-hover-background {
+  background-color: rgba(32, 33, 36, 0.71);
+}
+
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-play-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-play-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-internal-media-controls-overflow-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.audio-only input[pseudo="-internal-media-controls-overflow-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-play-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-webkit-media-controls-fullscreen-button" i]:enabled:focus::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:hover::-internal-media-controls-button-hover-background,
+audio::-webkit-media-controls input[pseudo="-internal-media-controls-overflow-button" i]:enabled:focus::-internal-media-controls-button-hover-background {
+  background-color: rgba(32, 33, 36, 0.06);
+}
+
+video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-play-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.sizing-medium input[pseudo="-webkit-media-controls-fullscreen-button" i]::-internal-media-controls-button-hover-background,
+video::-webkit-media-controls.sizing-medium input[pseudo="-internal-media-controls-overflow-button" i]::-internal-media-controls-button-hover-background {
+  background-size: 32px;
+  width: 44px;
+  height: 44px;
+  border-radius: 22px;
+  left: 10px;
+  top: 10px;
+}
+
 video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-play-button" i],
 video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-mute-button" i],
 video::-webkit-media-controls.sizing-small input[pseudo="-webkit-media-controls-fullscreen-button" i],
@@ -355,6 +447,97 @@
   border: 0;
 }
 
+/*
+ * Volume control container
+ */
+audio::-webkit-media-controls-volume-control-container,
+video::-webkit-media-controls-volume-control-container {
+  display: flex;
+  justify-content: flex-end;
+  position: relative;
+  height: 48px;
+
+  /* 48(Mute button) + 52(Slider) + 16(Left padding) */
+  min-width: 116px;
+  transition: min-width .3s;
+}
+
+audio::-webkit-media-controls-volume-control-container.closed,
+video::-webkit-media-controls-volume-control-container.closed {
+  min-width: 48px;
+}
+
+/*
+ * Audio control hover container size should be same as video controls'. Due to increase of audio control tap target
+ * will break the layout when width is 300. We'll shrink the hover container here. Should remove the min-width rule
+ * once the new audio control layout specs are out.
+ */
+video::-webkit-media-controls.audio-only div[pseudo="-webkit-media-controls-volume-control-container" i],
+audio::-webkit-media-controls-volume-control-container {
+  min-width: 100px;
+}
+
+video::-webkit-media-controls.audio-only div[pseudo="-webkit-media-controls-volume-control-container" i].closed,
+audio::-webkit-media-controls-volume-control-container.closed {
+  min-width: 32px;
+}
+
+audio::-webkit-media-controls-volume-control-hover-background,
+video::-webkit-media-controls-volume-control-hover-background {
+  position: absolute;
+  z-index: -1;
+  background-color: #202124;
+  opacity: .71;
+  height: 36px;
+  width: 112px;
+  border-radius: 18px;
+  top: 6px;
+  right: 4px;
+  transition: width .3s ease, opacity .25s ease;
+}
+
+/*
+ * Audio control hover size should be same as video controls'. Due to increase of audio control tap target
+ * will break the layout when width is 300. We'll shrink the hover size here. Should remove this rule once the new
+ * audio control layout specs are out. (Don't remove the opacity rule)
+ */
+video::-webkit-media-controls.audio-only div[pseudo="-webkit-media-controls-volume-control-hover-background" i],
+audio::-webkit-media-controls-volume-control-hover-background {
+  height: 32px;
+  width: 100px;
+  border-radius: 16px;
+  top: 8px;
+  right: 0;
+  opacity: .06;
+}
+
+audio::-webkit-media-controls [pseudo="-webkit-media-controls-volume-control-container"].closed [pseudo="-webkit-media-controls-volume-control-hover-background"],
+video::-webkit-media-controls [pseudo="-webkit-media-controls-volume-control-container"].closed [pseudo="-webkit-media-controls-volume-control-hover-background"] {
+  width: 36px;
+  opacity: 0;
+}
+
+video::-webkit-media-controls.sizing-medium div[pseudo="-webkit-media-controls-volume-control-container" i] {
+  height: 64px;
+  min-width: 132px;
+}
+
+video::-webkit-media-controls.sizing-medium div[pseudo="-webkit-media-controls-volume-control-container" i].closed {
+  min-width: 64px;
+}
+
+video::-webkit-media-controls.sizing-medium div[pseudo="-webkit-media-controls-volume-control-hover-background" i] {
+  height: 44px;
+  width: 124px;
+  border-radius: 22px;
+  top: 10px;
+  right: 8px;
+}
+
+video::-webkit-media-controls.sizing-medum [pseudo="-webkit-media-controls-volume-control-container"].closed [pseudo="-webkit-media-controls-volume-control-hover-background"] {
+  width: 44px;
+}
+
 /**
  * The overlay-play-button is disabled if the video element is loaded via
  * MHTML, and a ruleset for input[type=button]:disabled in win.css has
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc
index 3ff688d..3a883114 100644
--- a/third_party/blink/renderer/modules/webaudio/audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -363,14 +363,18 @@
 }
 
 void AudioContext::NotifySourceNodeStart() {
+  DCHECK(IsMainThread());
+
   source_node_started_ = true;
   if (!user_gesture_required_)
     return;
 
   MaybeAllowAutoplayWithUnlockType(AutoplayUnlockType::kSourceNodeStart);
 
-  if (IsAllowedToStart())
+  if (IsAllowedToStart()) {
     StartRendering();
+    SetContextState(kRunning);
+  }
 }
 
 AutoplayPolicy::Type AudioContext::GetAutoplayPolicy() const {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index 1120a8b..b584dc34 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -2072,6 +2072,15 @@
     return;
   }
 
+  if (!mask) {
+    // Use OnErrorMessage because it's both rate-limited and obeys the
+    // webGLErrorsToConsole setting.
+    OnErrorMessage(
+        "Performance warning: clear() called with no buffers in bitmask", 0);
+    // Don't skip the call to ClearIfComposited below; it has side
+    // effects even without the user requesting to clear any buffers.
+  }
+
   ScopedRGBEmulationColorMask emulation_color_mask(this, color_mask_,
                                                    drawing_buffer_.get());
 
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.cc b/third_party/blink/renderer/platform/bindings/callback_function_base.cc
index 12ba1af..73d47e3 100644
--- a/third_party/blink/renderer/platform/bindings/callback_function_base.cc
+++ b/third_party/blink/renderer/platform/bindings/callback_function_base.cc
@@ -73,6 +73,7 @@
 V8PersistentCallbackFunctionBase::V8PersistentCallbackFunctionBase(
     CallbackFunctionBase* callback_function)
     : callback_function_(callback_function) {
+  v8::HandleScope scope(callback_function_->GetIsolate());
   v8_function_.Reset(callback_function_->GetIsolate(),
                      callback_function_->callback_function_.Get());
 }
diff --git a/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-under-clip-path-crash.html b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-under-clip-path-crash.html
new file mode 100644
index 0000000..d37a120
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-multicol/multicol-span-all-under-clip-path-crash.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Should not crash on composited column-span:all under a clip-path</title>
+<link rel="help" href="https://drafts.csswg.org/css-multicol">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>test(()=>{})</script>
+<div style="columns: 2; width: 200px">
+  <div style="clip-path: circle(70%); background: blue">
+    <div style="column-span: all; will-change: transform">column-span: all</div>
+  </div>
+</div>
diff --git a/third_party/blink/web_tests/external/wpt/portals/portals-no-referrer.html b/third_party/blink/web_tests/external/wpt/portals/portals-no-referrer.html
new file mode 100644
index 0000000..0386272
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/portals-no-referrer.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+// TODO(jbroman): Remove use of BroadcastChannel for messaging once it is
+// possible to postMessage to a portal the normal way.
+promise_test(async () => {
+  assert_true('HTMLPortalElement' in self, 'HTMLPortalElement is required for this test');
+  let portal = document.createElement('portal');
+  let channelName = 'portals-no-referrer';
+  let broadcastChannel = new BroadcastChannel(channelName);
+  try {
+    let referrerPromise = new Promise((resolve, reject) => {
+      broadcastChannel.addEventListener('message', e => {
+        resolve(e.data);
+      }, {once: true});
+    });
+    portal.src = `resources/postmessage-referrer.sub.html?broadcastchannel=${channelName}`;
+    document.body.appendChild(portal);
+    try {
+      let {httpReferrer, documentReferrer} = await referrerPromise;
+      assert_equals(httpReferrer, 'no-http-referrer', 'No HTTP Referer header should be sent');
+      assert_equals(documentReferrer, 'no-document-referrer', 'No document.referrer should be present');
+    } finally {
+      document.body.removeChild(portal);
+    }
+  } finally {
+    broadcastChannel.close();
+  }
+}, "portal contents should be loaded with no referrer");
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/portals/resources/postmessage-referrer.sub.html b/third_party/blink/web_tests/external/wpt/portals/resources/postmessage-referrer.sub.html
new file mode 100644
index 0000000..6897ab0
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/portals/resources/postmessage-referrer.sub.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<script>
+let message = {
+  httpReferrer: '{{header_or_default(Referer, no-http-referrer)}}',
+  documentReferrer: document.referrer || 'no-document-referrer',
+};
+
+let broadcastChannel = new BroadcastChannel(new URL(location).searchParams.get('broadcastchannel'));
+try {
+  broadcastChannel.postMessage(message);
+} finally {
+  broadcastChannel.close();
+}
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/fallback-to-another-sxg.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/fallback-to-another-sxg.sxg.headers
index ab188e54..ca411784 100644
--- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/fallback-to-another-sxg.sxg.headers
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/fallback-to-another-sxg.sxg.headers
@@ -1 +1,2 @@
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/generate-test-sxgs.sh b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/generate-test-sxgs.sh
index 6336ba3..a31ce681 100755
--- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/generate-test-sxgs.sh
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/generate-test-sxgs.sh
@@ -100,4 +100,52 @@
   -o nested-sxg.sxg \
   -miRecordSize 100
 
+# Fallback URL has non-ASCII UTF-8 characters.
+gen-signedexchange \
+  -version 1b2 \
+  -ignoreErrors \
+  -uri "$inner_url_origin/signed-exchange/resources/🌐📦.html" \
+  -status 200 \
+  -content sxg-location.html \
+  -certificate $certfile \
+  -certUrl $cert_url_origin/signed-exchange/resources/$certfile.cbor \
+  -validityUrl $inner_url_origin/signed-exchange/resources/resource.validity.msg \
+  -privateKey $keyfile \
+  -date 2018-04-01T00:00:00Z \
+  -expire 168h \
+  -o sxg-utf8-inner-url.sxg \
+  -miRecordSize 100
+
+# Fallback URL has invalid UTF-8 sequence.
+gen-signedexchange \
+  -version 1b2 \
+  -ignoreErrors \
+  -uri "$inner_url_origin/signed-exchange/resources/$(echo -e '\xce\xce\xa9').html" \
+  -status 200 \
+  -content sxg-location.html \
+  -certificate $certfile \
+  -certUrl $cert_url_origin/signed-exchange/resources/$certfile.cbor \
+  -validityUrl $inner_url_origin/signed-exchange/resources/resource.validity.msg \
+  -privateKey $keyfile \
+  -date 2018-04-01T00:00:00Z \
+  -expire 168h \
+  -o sxg-invalid-utf8-inner-url.sxg \
+  -miRecordSize 100
+
+# Fallback URL has UTF-8 BOM.
+gen-signedexchange \
+  -version 1b2 \
+  -ignoreErrors \
+  -uri "$(echo -e '\xef\xbb\xbf')$inner_url_origin/signed-exchange/resources/inner-url.html" \
+  -status 200 \
+  -content sxg-location.html \
+  -certificate $certfile \
+  -certUrl $cert_url_origin/signed-exchange/resources/$certfile.cbor \
+  -validityUrl $inner_url_origin/signed-exchange/resources/resource.validity.msg \
+  -privateKey $keyfile \
+  -date 2018-04-01T00:00:00Z \
+  -expire 168h \
+  -o sxg-inner-url-bom.sxg \
+  -miRecordSize 100
+
 rm -fr $tmpdir
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/nested-sxg.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/nested-sxg.sxg.headers
index ab188e54..ca411784 100644
--- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/nested-sxg.sxg.headers
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/nested-sxg.sxg.headers
@@ -1 +1,2 @@
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-head-request.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-head-request.sxg.headers
index ab188e54..ca411784 100644
--- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-head-request.sxg.headers
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-head-request.sxg.headers
@@ -1 +1,2 @@
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-inner-url-bom.sxg b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-inner-url-bom.sxg
new file mode 100644
index 0000000..ace5abd
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-inner-url-bom.sxg
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-inner-url-bom.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-inner-url-bom.sxg.headers
new file mode 100644
index 0000000..ca411784
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-inner-url-bom.sxg.headers
@@ -0,0 +1,2 @@
+Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg
new file mode 100644
index 0000000..1f697b74
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg.headers
new file mode 100644
index 0000000..ca411784
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg.headers
@@ -0,0 +1,2 @@
+Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-validity-url.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-validity-url.sxg.headers
index ab188e54..ca411784 100644
--- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-validity-url.sxg.headers
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-invalid-validity-url.sxg.headers
@@ -1 +1,2 @@
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-location.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-location.sxg.headers
index ab188e54..ca411784 100644
--- a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-location.sxg.headers
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-location.sxg.headers
@@ -1 +1,2 @@
 Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-utf8-inner-url.sxg b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-utf8-inner-url.sxg
new file mode 100644
index 0000000..c8f8a94e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-utf8-inner-url.sxg
Binary files differ
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-utf8-inner-url.sxg.headers b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-utf8-inner-url.sxg.headers
new file mode 100644
index 0000000..ca411784
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/resources/sxg-utf8-inner-url.sxg.headers
@@ -0,0 +1,2 @@
+Content-Type: application/signed-exchange;v=b2
+X-Content-Type-Options: nosniff
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-inner-url-bom.tentative.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-inner-url-bom.tentative.html
new file mode 100644
index 0000000..c694a223
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-inner-url-bom.tentative.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>SignedHTTPExchange's fallback url must not have UTF-8 BOM</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="./resources/sxg-util.js"></script>
+<body>
+<script>
+promise_test(async (t) => {
+  try {
+    const sxgUrl = get_host_info().HTTP_ORIGIN + '/signed-exchange/resources/sxg-inner-url-bom.sxg';
+    const message = await openSXGInIframeAndWaitForMessage(t, sxgUrl);
+    if (message.is_fallback) {
+        assert_unreached('Fallback redirect should not have happened');
+    } else {
+        assert_unreached('SXG should not have loaded');
+    }
+  } catch (e) {
+    assert_equals(e, 'timeout');
+  }
+}, "SignedHTTPExchange's fallback url must not have UTF-8 BOM");
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-invalid-utf8-inner-url.tentative.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-invalid-utf8-inner-url.tentative.html
new file mode 100644
index 0000000..bc28d81
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-invalid-utf8-inner-url.tentative.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>SignedHTTPExchange's fallback url must not have invalid UTF-8 sequence</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="./resources/sxg-util.js"></script>
+<body>
+<script>
+promise_test(async (t) => {
+  try {
+    const sxgUrl = get_host_info().HTTPS_ORIGIN + '/signed-exchange/resources/sxg-invalid-utf8-inner-url.sxg';
+    const message = await openSXGInIframeAndWaitForMessage(t, sxgUrl);
+    if (message.is_fallback) {
+        assert_unreached('Fallback redirect should not have happened');
+    } else {
+        assert_unreached('SXG should not have loaded');
+    }
+  } catch (e) {
+    assert_equals(e, 'timeout');
+  }
+}, "SignedHTTPExchange's fallback url must not have invalid UTF-8 sequence");
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-utf8-inner-url.tentative.html b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-utf8-inner-url.tentative.html
new file mode 100644
index 0000000..fc33560d2
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/signed-exchange/sxg-utf8-inner-url.tentative.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>SignedHTTPExchange with UTF-8 inner URL</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="./resources/sxg-util.js"></script>
+<body>
+<script>
+promise_test(async (t) => {
+  const sxgUrl = get_host_info().HTTPS_ORIGIN + '/signed-exchange/resources/sxg-utf8-inner-url.sxg';
+  const message = await openSXGInIframeAndWaitForMessage(t, sxgUrl);
+  assert_equals(message.location, new URL(innerURLOrigin() + '/signed-exchange/resources/\uD83C\uDF10\uD83D\uDCE6.html').href);
+  assert_false(message.is_fallback);
+}, 'SignedHTTPExchange with UTF-8 inner URL');
+
+</script>
+</body>
diff --git a/third_party/blink/web_tests/http/tests/loading/sxg/resources/.htaccess b/third_party/blink/web_tests/http/tests/loading/sxg/resources/.htaccess
index 995b6e0..22d9949f 100644
--- a/third_party/blink/web_tests/http/tests/loading/sxg/resources/.htaccess
+++ b/third_party/blink/web_tests/http/tests/loading/sxg/resources/.htaccess
@@ -1 +1,2 @@
 AddType application/cert-chain+cbor .cbor
+Header set X-Content-Type-Options "nosniff"
diff --git a/third_party/blink/web_tests/media/controls/modern/video-tag-with-only-audio-looks-like-audio-tag.html b/third_party/blink/web_tests/media/controls/modern/video-tag-with-only-audio-looks-like-audio-tag.html
index 794a1c5..4e65e0c 100644
--- a/third_party/blink/web_tests/media/controls/modern/video-tag-with-only-audio-looks-like-audio-tag.html
+++ b/third_party/blink/web_tests/media/controls/modern/video-tag-with-only-audio-looks-like-audio-tag.html
@@ -61,7 +61,7 @@
     assert_false(mediaControls(video).classList.contains('audio-only'));
 
     // The buttons should be children of the media button panel.
-    assert_equals(muteButton(video).parentElement.getAttribute('pseudo'), '-internal-media-controls-button-panel');
+    assert_equals(muteButton(video).parentElement.parentElement.getAttribute('pseudo'), '-internal-media-controls-button-panel');
   }
 
   function expectLooksLikeAudio(video) {
@@ -69,7 +69,7 @@
     assert_true(mediaControls(video).classList.contains('audio-only'));
 
     // The buttons should be children of the main panel.
-    assert_equals(muteButton(video).parentElement.getAttribute('pseudo'), '-webkit-media-controls-panel');
+    assert_equals(muteButton(video).parentElement.parentElement.getAttribute('pseudo'), '-webkit-media-controls-panel');
   }
 });
 </script>
diff --git a/third_party/blink/web_tests/webaudio/AudioContext/autoplay-state-change.html b/third_party/blink/web_tests/webaudio/AudioContext/autoplay-state-change.html
new file mode 100644
index 0000000..37e3620
--- /dev/null
+++ b/third_party/blink/web_tests/webaudio/AudioContext/autoplay-state-change.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>
+      Test if AudioContext state changes correctly after a source starts.
+    </title>
+    <script src="../../resources/testharness.js"></script>
+    <script src="../../resources/testharnessreport.js"></script>
+    <script src="../resources/audit.js"></script>
+  </head>
+  <body>
+    <script id="layout-test-code">
+      const audit = new Audit.createTaskRunner();
+
+      let autoplayIgnoresWebAudioEnabled;
+
+      audit.define('autoplay-policy-setup', function(task) {
+        autoplayIgnoresWebAudioEnabled =
+            internals.runtimeFlags.autoplayIgnoresWebAudioEnabled;
+        internals.runtimeFlags.autoplayIgnoresWebAudioEnabled = false;
+        internals.settings.setAutoplayPolicy(
+            'document-user-activation-required');
+        task.done();
+      });
+
+      audit.define('test-context-state', function(task, should) {
+        const context = new AudioContext();
+        const osc = new OscillatorNode(context);
+        osc.connect(context.destination);
+
+        activateDocument().then(() => {
+          should(context.state, 'Context state').beEqualTo('suspended');
+          osc.start();
+          should(context.state, 'Context state').beEqualTo('running');
+          task.done();
+        });
+      });
+
+      audit.define('post-test-cleanup', function(task) {
+        internals.runtimeFlags.autoplayIgnoresWebAudioEnabled =
+            autoplayIgnoresWebAudioEnabled;
+        internals.settings.setAutoplayPolicy('no-user-gesture-required');
+        task.done();
+      });
+
+      function activateDocument() {
+        return new Promise((resolve, reject) => {
+          chrome.gpuBenchmarking.pointerActionSequence([
+            {
+              source: 'mouse',
+              actions: [
+                { name: 'pointerDown', x: 1, y: 1 },
+                { name: 'pointerUp' },
+              ],
+            }
+          ], resolve);
+        });
+      }
+
+      audit.run();
+    </script>
+  </body>
+</html>
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 5a4c5d0..b27c32a 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 2afe6dc210e3f52da56bc28d234f65d62b490ace
+Revision: 83867d52343b9657ad1263c2a6d5571dbc350b0c
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
index 77faa0aa..ed1d7df 100644
--- a/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
+++ b/third_party/crashpad/crashpad/client/crashpad_client_linux.cc
@@ -28,6 +28,7 @@
 #include "util/file/file_io.h"
 #include "util/linux/exception_handler_client.h"
 #include "util/linux/exception_information.h"
+#include "util/linux/scoped_pr_set_dumpable.h"
 #include "util/linux/scoped_pr_set_ptracer.h"
 #include "util/misc/from_pointer_cast.h"
 #include "util/posix/double_fork_and_exec.h"
@@ -119,6 +120,7 @@
     exception_information_.thread_id = syscall(SYS_gettid);
 
     ScopedPrSetPtracer set_ptracer(getpid(), /* may_log= */ false);
+    ScopedPrSetDumpable set_dumpable(/* may_log= */ false);
 
     pid_t pid = fork();
     if (pid < 0) {
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn
index 9f47a41..c02ecd4e 100644
--- a/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -296,6 +296,8 @@
       "linux/ptrace_connection.h",
       "linux/ptracer.cc",
       "linux/ptracer.h",
+      "linux/scoped_pr_set_dumpable.cc",
+      "linux/scoped_pr_set_dumpable.h",
       "linux/scoped_pr_set_ptracer.cc",
       "linux/scoped_pr_set_ptracer.h",
       "linux/scoped_ptrace_attach.cc",
diff --git a/third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.cc b/third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.cc
new file mode 100644
index 0000000..cbec009b
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.cc
@@ -0,0 +1,41 @@
+// Copyright 2018 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/linux/scoped_pr_set_dumpable.h"
+
+#include <sys/prctl.h>
+
+#include "base/logging.h"
+
+namespace crashpad {
+
+ScopedPrSetDumpable::ScopedPrSetDumpable(bool may_log) : may_log_(may_log) {
+  int result = prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
+  PLOG_IF(ERROR, result < 0 && may_log_) << "prctl";
+  was_dumpable_ = result > 0;
+
+  if (!was_dumpable_) {
+    result = prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+    PLOG_IF(ERROR, result != 0 && may_log_) << "prctl";
+  }
+}
+
+ScopedPrSetDumpable::~ScopedPrSetDumpable() {
+  if (!was_dumpable_) {
+    int result = prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+    PLOG_IF(ERROR, result != 0 && may_log_) << "prctl";
+  }
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h b/third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h
new file mode 100644
index 0000000..1681930
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h
@@ -0,0 +1,44 @@
+// Copyright 2018 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_LINUX_SCOPED_PR_SET_DUMPABLE_H_
+#define CRASHPAD_UTIL_LINUX_SCOPED_PR_SET_DUMPABLE_H_
+
+#include "base/macros.h"
+
+namespace crashpad {
+
+class ScopedPrSetDumpable {
+ public:
+  //! \brief Uses `PR_SET_DUMPABLE` to make the current process dumpable.
+  //!
+  //! Restores the dumpable flag to its original value on destruction. If the
+  //! original value couldn't be determined, the destructor attempts to restore
+  //! the flag to 0 (non-dumpable).
+  //!
+  //! \param[in] may_log `true` if this object may log error messages.
+  explicit ScopedPrSetDumpable(bool may_log);
+
+  ~ScopedPrSetDumpable();
+
+ private:
+  bool was_dumpable_;
+  bool may_log_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPrSetDumpable);
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_UTIL_LINUX_SCOPED_PR_SET_DUMPABLE_H_
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp
index a8ed59e6..60e91304 100644
--- a/third_party/crashpad/crashpad/util/util.gyp
+++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -74,6 +74,8 @@
         'linux/ptrace_connection.h',
         'linux/ptracer.cc',
         'linux/ptracer.h',
+        'linux/scoped_pr_set_dumpable.cc',
+        'linux/scoped_pr_set_dumpable.h',
         'linux/scoped_pr_set_ptracer.cc',
         'linux/scoped_pr_set_ptracer.h',
         'linux/scoped_ptrace_attach.cc',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 55df1b5..f729c9b8 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -508,6 +508,7 @@
     'chromium.webrtc': {
       'WebRTC Chromium Android Builder': 'android_debug_static_bot_arm64',
       'WebRTC Chromium Linux Builder': 'gpu_tests_release_bot',
+      'WebRTC Chromium Linux Builder (RBE)': 'gpu_tests_release_bot',
       'WebRTC Chromium Mac Builder': 'gpu_tests_release_bot',
       'WebRTC Chromium Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks_with_codecs',
     },
@@ -517,7 +518,9 @@
       'WebRTC Chromium FYI Android Builder (dbg)': 'android_debug_static_bot',
       'WebRTC Chromium FYI Android Builder ARM64 (dbg)': 'android_debug_static_bot_arm64',
       'WebRTC Chromium FYI Linux Builder': 'gpu_tests_release_bot',
+      'WebRTC Chromium FYI Linux Builder (RBE)': 'gpu_tests_release_bot',
       'WebRTC Chromium FYI Linux Builder (dbg)': 'debug_bot',
+      'WebRTC Chromium FYI Linux Builder (dbg) (RBE)': 'debug_bot',
       'WebRTC Chromium FYI Mac Builder': 'gpu_tests_release_bot',
       'WebRTC Chromium FYI Mac Builder (dbg)': 'debug_bot',
       'WebRTC Chromium FYI Win Builder': 'release_bot_x86_minimal_symbols_no_com_init_hooks_with_codecs',
@@ -649,7 +652,9 @@
       'closure_compilation': 'closure_compilation',
       'fuchsia_arm64': 'release_trybot_fuchsia_arm64',
       'fuchsia-arm64-cast': 'release_trybot_fuchsia_arm64_cast',
+      'fuchsia-fyi-arm64-rel': 'release_trybot_fuchsia_arm64',
       'fuchsia-fyi-x64-dbg': 'debug_trybot_fuchsia',
+      'fuchsia-fyi-x64-rel': 'release_trybot_fuchsia',
       'fuchsia_x64': 'release_trybot_fuchsia',
       'fuchsia-x64-cast': 'release_trybot_fuchsia_cast',
       'layout_test_leak_detection': 'release_trybot',
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 77b9681..86a50e0 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -12136,6 +12136,15 @@
   <description>User shared to the device's bookmarks.</description>
 </action>
 
+<action name="MobileShareMenuCancel">
+  <owner>gambard@chromium.org</owner>
+  <owner>pkl@chromium.org</owner>
+  <description>
+    The user cancelled the share action menu (i.e. closed it without taking any
+    action).
+  </description>
+</action>
+
 <action name="MobileShareMenuFindInPage">
   <owner>gambard@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a1c73cb..26aa087 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26914,6 +26914,7 @@
   <int value="4" label="Korean"/>
   <int value="5" label="M17n">Multilingualization</int>
   <int value="6" label="T13n">Transliteration</int>
+  <int value="7" label="ARC"/>
 </enum>
 
 <enum name="InputMethodID">
@@ -35516,6 +35517,7 @@
   <int value="3" label="A navigation suggestion is found using top sites list"/>
   <int value="4"
       label="A navigation suggestion is found using site engagement"/>
+  <int value="5" label="A navigation suggestion is found using edit distance"/>
 </enum>
 
 <enum name="NavigationWasServedFromCache">
@@ -41985,6 +41987,16 @@
   <int value="3" label="Popup clicked through (abusive)"/>
 </enum>
 
+<enum name="PortalDetectionMultiProbeResult">
+  <int value="0" label="Undefined result"/>
+  <int value="1" label="HTTPS traffic blocked, no HTTP redirect"/>
+  <int value="2" label="HTTPS traffic blocked, HTTP redirect received"/>
+  <int value="3" label="HTTPS traffic blocked, HTTP 204 received"/>
+  <int value="4" label="HTTPS traffic not blocked, no HTTP redirect"/>
+  <int value="5" label="HTTPS traffic not blocked, HTTP redirect received"/>
+  <int value="6" label="HTTPS traffic not blocked, HTTP 204 received"/>
+</enum>
+
 <enum name="Ports">
   <int value="80" label="Port 80"/>
   <int value="443" label="Port 443"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index eefe7f2..8c3dad5 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -65946,6 +65946,16 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Shill.PortalDetectionMultiProbeResult"
+    enum="PortalDetectionMultiProbeResult" expires_after="2019-12-31">
+  <owner>matthewmwang@chromium.org</owner>
+  <summary>
+    Chrome OS network metric recording portal detection results of both the HTTP
+    and HTTPS probes. This is recorded every time a portal detection trial
+    finishes.
+  </summary>
+</histogram>
+
 <histogram name="Network.Shill.PPPMTUValue" units="bytes">
   <owner>gdk@chromium.org</owner>
   <summary>
@@ -117789,11 +117799,24 @@
   </summary>
 </histogram>
 
+<histogram name="UMA.LowEntropySource3Value" expires_after="2019-08-30">
+  <owner>asvitkine@chromium.org</owner>
+  <owner>mpearson@chromium.org</owner>
+  <summary>
+    Distribution of the new low entropy source value. Corresponds to
+    metrics::prefs::kMetricsLowEntropySource. Used for field trial
+    randomization. Recorded on startup.
+  </summary>
+</histogram>
+
 <histogram name="UMA.LowEntropySourceValue" expires_after="2019-08-30">
   <owner>asvitkine@chromium.org</owner>
+  <owner>mpearson@chromium.org</owner>
   <summary>
-    Distribution of the low entropy source value used for field trial
-    randomization, recorded on startup.
+    Distribution of the old low entropy source value. Corresponds to
+    metrics::prefs::kMetricsOldLowEntropySource. Used for field trial
+    randomization on clients that already have it, but not created on new
+    installs. Recorded on startup.
   </summary>
 </histogram>
 
diff --git a/ui/file_manager/file_manager/foreground/js/directory_contents.js b/ui/file_manager/file_manager/foreground/js/directory_contents.js
index e331189..2e0988c 100644
--- a/ui/file_manager/file_manager/foreground/js/directory_contents.js
+++ b/ui/file_manager/file_manager/foreground/js/directory_contents.js
@@ -439,16 +439,13 @@
 };
 
 /**
- * Show/Hide hidden files (i.e. files starting with '.' or ending with
- * '.crdownload').
+ * Show/Hide hidden files (i.e. files starting with '.').
  * @param {boolean} visible True if hidden files should be visible to the user.
  */
 FileFilter.prototype.setHiddenFilesVisible = function(visible) {
-  var regexpCrdownloadExtension = /\.crdownload$/i;
   if (!visible) {
     this.addFilter('hidden', entry => {
-      return entry.name.substr(0, 1) !== '.' &&
-          !regexpCrdownloadExtension.test(entry.name);
+      return entry.name.substr(0, 1) !== '.';
     });
   } else {
     this.removeFilter('hidden');
diff --git a/ui/file_manager/file_manager/foreground/js/selection_menu_controller.js b/ui/file_manager/file_manager/foreground/js/selection_menu_controller.js
index 579b29d..1993848 100644
--- a/ui/file_manager/file_manager/foreground/js/selection_menu_controller.js
+++ b/ui/file_manager/file_manager/foreground/js/selection_menu_controller.js
@@ -42,7 +42,11 @@
  * @private
  */
 SelectionMenuController.prototype.onHideMenu_ = function() {
-  // Do not remove 'toolbar-menu' yet, it will be removed at the end of
-  // FilesMenuItem.setMenuAsAnimating_ to avoid flicker.  See crbug.com/862926.
+  // If menu is animating to close, then do not remove 'toolbar-menu' yet, it
+  // will be removed at the end of FilesMenuItem.setMenuAsAnimating_ to avoid
+  // flicker.  See crbug.com/862926.
+  if (!this.menu_.classList.contains('animating')) {
+    this.menu_.classList.toggle('toolbar-menu', false);
+  }
   this.toggleRipple_.activated = false;
 };
diff --git a/ui/file_manager/file_manager/test/BUILD.gn b/ui/file_manager/file_manager/test/BUILD.gn
index 6f5cffa3..965a684 100644
--- a/ui/file_manager/file_manager/test/BUILD.gn
+++ b/ui/file_manager/file_manager/test/BUILD.gn
@@ -25,6 +25,7 @@
     "crostini_share.js",
     "crostini_tasks.js",
     "js/strings.js",
+    "menu.js",
     "progress_center.js",
     "uma.js",
   ]
@@ -41,6 +42,7 @@
     ":crostini_mount",
     ":crostini_share",
     ":crostini_tasks",
+    ":menu",
     ":progress_center",
     ":uma",
   ]
@@ -94,6 +96,13 @@
   ]
 }
 
+js_library("menu") {
+  deps = [
+    "js:test_util",
+    "//ui/webui/resources/js:webui_resource_test",
+  ]
+}
+
 js_library("progress_center") {
   deps = [
     "js:test_util",
diff --git a/ui/file_manager/file_manager/test/menu.js b/ui/file_manager/file_manager/test/menu.js
new file mode 100644
index 0000000..6b9a941
--- /dev/null
+++ b/ui/file_manager/file_manager/test/menu.js
@@ -0,0 +1,33 @@
+// 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.
+
+const menu = {};
+
+menu.testToggleToolbarMenu = async function(done) {
+  const hello = '#file-list [file-name="hello.txt"]';
+  const helloCheckmark = hello + ' .detail-checkmark';
+  const selectionMenuButton = 'body.check-select #selection-menu-button';
+  const menuToolbar = '#file-context-menu:not([hidden]).toolbar-menu';
+  const menuNotToolbar = '#file-context-menu:not([hidden]):not(.toolbar-menu)';
+
+  await test.setupAndWaitUntilReady();
+
+  // Right-click hello.txt, menu is shown, not toolbar-menu.
+  assertTrue(test.fakeMouseRightClick(hello));
+  await test.waitForElement(menuNotToolbar);
+
+  // Click on hello.txt checkmark, selection-menu-button replaces gear-button.
+  assertTrue(test.fakeMouseClick(helloCheckmark));
+  await test.waitForElement(selectionMenuButton);
+
+  // Click selection-menu-button, verify toolbar-menu.
+  assertTrue(test.fakeMouseClick(selectionMenuButton));
+  await test.waitForElement(menuToolbar);
+
+  // Right-click hello.txt, verify not toolbar-menu.
+  assertTrue(test.fakeMouseRightClick(hello));
+  await test.waitForElement(menuNotToolbar);
+
+  done();
+};
diff --git a/ui/file_manager/integration_tests/file_manager/gear_menu.js b/ui/file_manager/integration_tests/file_manager/gear_menu.js
index dff9da62..e38cc21 100644
--- a/ui/file_manager/integration_tests/file_manager/gear_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/gear_menu.js
@@ -5,6 +5,20 @@
 'use strict';
 
 /**
+ * Expected files shown in Downloads with hidden disabled
+ *
+ * @type {!Array<!TestEntryInfo>}
+ */
+const BASIC_LOCAL_ENTRY_SET_WITHOUT_HIDDEN = [
+  ENTRIES.hello,
+  ENTRIES.world,
+  ENTRIES.desktop,
+  ENTRIES.beautiful,
+  ENTRIES.photos,
+  ENTRIES.crdownload,
+];
+
+/**
  * Expected files shown in Downloads with hidden enabled
  *
  * @type {!Array<!TestEntryInfo>}
@@ -15,6 +29,7 @@
   ENTRIES.desktop,
   ENTRIES.beautiful,
   ENTRIES.photos,
+  ENTRIES.crdownload,
   ENTRIES.hiddenFile,
 ];
 
@@ -155,7 +170,8 @@
       RootPath.DOWNLOADS, BASIC_LOCAL_ENTRY_SET_WITH_HIDDEN, []);
 
   await runHiddenFilesTest(
-      appId, BASIC_LOCAL_ENTRY_SET, BASIC_LOCAL_ENTRY_SET_WITH_HIDDEN);
+      appId, BASIC_LOCAL_ENTRY_SET_WITHOUT_HIDDEN,
+      BASIC_LOCAL_ENTRY_SET_WITH_HIDDEN);
 };
 
 /**
diff --git a/ui/file_manager/integration_tests/test_util.js b/ui/file_manager/integration_tests/test_util.js
index dfd714c..f20425f8 100644
--- a/ui/file_manager/integration_tests/test_util.js
+++ b/ui/file_manager/integration_tests/test_util.js
@@ -1094,4 +1094,15 @@
     sizeText: '51 bytes',
     typeText: 'Plain text'
   }),
+
+  crdownload: new TestEntryInfo({
+    type: EntryType.FILE,
+    sourceFileName: 'text.txt',
+    targetPath: 'hello.crdownload',
+    mimeType: 'application/octet-stream',
+    lastModifiedTime: 'Sep 4, 1998, 12:34 PM',
+    nameText: 'hello.crdownload',
+    sizeText: '51 bytes',
+    typeText: 'CRDOWNLOAD file'
+  }),
 };
diff --git a/ui/views/controls/button/image_button_factory.cc b/ui/views/controls/button/image_button_factory.cc
index 3ddc201..30c082c 100644
--- a/ui/views/controls/button/image_button_factory.cc
+++ b/ui/views/controls/button/image_button_factory.cc
@@ -52,6 +52,20 @@
                             SkColor related_text_color) {
   const SkColor icon_color =
       color_utils::DeriveDefaultIconColor(related_text_color);
+  SetImageFromVectorIconWithColor(button, icon, dip_size, icon_color);
+}
+
+void SetImageFromVectorIconWithColor(ImageButton* button,
+                                     const gfx::VectorIcon& icon,
+                                     SkColor icon_color) {
+  SetImageFromVectorIconWithColor(button, icon,
+                                  GetDefaultSizeOfVectorIcon(icon), icon_color);
+}
+
+void SetImageFromVectorIconWithColor(ImageButton* button,
+                                     const gfx::VectorIcon& icon,
+                                     int dip_size,
+                                     SkColor icon_color) {
   const SkColor disabled_color =
       SkColorSetA(icon_color, gfx::kDisabledControlAlpha);
   const gfx::ImageSkia& normal_image =
diff --git a/ui/views/controls/button/image_button_factory.h b/ui/views/controls/button/image_button_factory.h
index 0ce421e..0f407183 100644
--- a/ui/views/controls/button/image_button_factory.h
+++ b/ui/views/controls/button/image_button_factory.h
@@ -45,6 +45,18 @@
     int dip_size,
     SkColor related_text_color = gfx::kGoogleGrey900);
 
+// Sets images on |button| for STATE_NORMAL and STATE_DISABLED from the given
+// vector icon and color.
+VIEWS_EXPORT void SetImageFromVectorIconWithColor(ImageButton* button,
+                                                  const gfx::VectorIcon& icon,
+                                                  SkColor icon_color);
+
+// As above, but creates the images at the given size.
+VIEWS_EXPORT void SetImageFromVectorIconWithColor(ImageButton* button,
+                                                  const gfx::VectorIcon& icon,
+                                                  int dip_size,
+                                                  SkColor icon_color);
+
 // As above, but sets the toggled images for a toggled image button.
 VIEWS_EXPORT void SetToggledImageFromVectorIcon(
     ToggleImageButton* button,
diff --git a/ui/views/controls/combobox/combobox.cc b/ui/views/controls/combobox/combobox.cc
index 41a5ac2b..62a28d66 100644
--- a/ui/views/controls/combobox/combobox.cc
+++ b/ui/views/controls/combobox/combobox.cc
@@ -521,7 +521,7 @@
 
   // TODO(hajimehoshi): Fix the problem that the arrow button blinks when
   // cliking this while the dropdown menu is opened.
-  const base::TimeDelta delta = base::Time::Now() - closed_time_;
+  const base::TimeDelta delta = base::TimeTicks::Now() - closed_time_;
   if (delta.InMilliseconds() <= kMinimumMsBetweenButtonClicks)
     return;
 
@@ -644,7 +644,7 @@
 void Combobox::OnMenuClosed(Button::ButtonState original_button_state) {
   menu_runner_.reset();
   arrow_button_->SetState(original_button_state);
-  closed_time_ = base::Time::Now();
+  closed_time_ = base::TimeTicks::Now();
 }
 
 void Combobox::OnPerformAction() {
diff --git a/ui/views/controls/combobox/combobox.h b/ui/views/controls/combobox/combobox.h
index 9f86b461..3bcff7e 100644
--- a/ui/views/controls/combobox/combobox.h
+++ b/ui/views/controls/combobox/combobox.h
@@ -173,7 +173,7 @@
   // menu. There is no clean way to get the second click event because the
   // menu is displayed using a modal loop and, unlike regular menus in Windows,
   // the button is not part of the displayed menu.
-  base::Time closed_time_;
+  base::TimeTicks closed_time_;
 
   // The maximum dimensions of the content in the dropdown.
   gfx::Size content_size_;
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index 90968d5c..0fa90ff 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1187,15 +1187,6 @@
 void Textfield::ShowContextMenuForView(View* source,
                                        const gfx::Point& point,
                                        ui::MenuSourceType source_type) {
-#if defined(OS_MACOSX)
-  // On Mac, the context menu contains a look up item which displays the
-  // selected text. As such, the menu needs to be updated if the selection has
-  // changed. Be careful to reset the MenuRunner first so it doesn't reference
-  // the old model.
-  context_menu_runner_.reset();
-  context_menu_contents_.reset();
-#endif
-
   UpdateContextMenu();
   context_menu_runner_->RunMenuAt(GetWidget(), NULL,
                                   gfx::Rect(point, gfx::Size()),
@@ -2265,30 +2256,33 @@
 }
 
 void Textfield::UpdateContextMenu() {
-  if (!context_menu_contents_.get()) {
-    context_menu_contents_.reset(new ui::SimpleMenuModel(this));
-    context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
-    context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
-    context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
-    context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
-    context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
-    context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
-    context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
-    context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
-                                                IDS_APP_SELECT_ALL);
+  // TextfieldController may modify Textfield's menu, so the menu should be
+  // recreated each time it's shown. Reset the MenuRunner first so it doesn't
+  // reference the old menu model.
+  context_menu_runner_.reset();
 
-    // If the controller adds menu commands, also override ExecuteCommand() and
-    // IsCommandIdEnabled() as appropriate, for the commands added.
-    if (controller_)
-      controller_->UpdateContextMenu(context_menu_contents_.get());
+  context_menu_contents_.reset(new ui::SimpleMenuModel(this));
+  context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO);
+  context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+  context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
+  context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
+  context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
+  context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE);
+  context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR);
+  context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL,
+                                              IDS_APP_SELECT_ALL);
 
-    text_services_context_menu_ = ViewsTextServicesContextMenu::Create(
-        context_menu_contents_.get(), this);
-  }
+  // If the controller adds menu commands, also override ExecuteCommand() and
+  // IsCommandIdEnabled() as appropriate, for the commands added.
+  if (controller_)
+    controller_->UpdateContextMenu(context_menu_contents_.get());
 
-  context_menu_runner_.reset(
-      new MenuRunner(context_menu_contents_.get(),
-                     MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU));
+  text_services_context_menu_ =
+      ViewsTextServicesContextMenu::Create(context_menu_contents_.get(), this);
+
+  context_menu_runner_ = std::make_unique<MenuRunner>(
+      context_menu_contents_.get(),
+      MenuRunner::HAS_MNEMONICS | MenuRunner::CONTEXT_MENU);
 }
 
 bool Textfield::ImeEditingAllowed() const {
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index 7b3f7fd..fd456eff 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -720,6 +720,14 @@
         textfield_->GetSelectedRange().length() == text.length();
 
     int menu_index = 0;
+
+#if defined(OS_MACOSX)
+    if (textfield_has_selection) {
+      EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Look Up "Selection" */));
+      EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
+    }
+#endif
+
     if (ui::IsEmojiPanelSupported()) {
       EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* EMOJI */));
       EXPECT_TRUE(menu->IsEnabledAt(menu_index++ /* Separator */));
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.html b/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.html
index 0390425..0fb625d 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.html
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.html
@@ -21,16 +21,6 @@
         width: 20px;
       }
 
-      /* Upper-left corner */
-      #technology {
-        --iron-icon-fill-color: #5a5a5a;
-        height: 20px;
-        left: 0;
-        position: absolute;
-        top: 1px;
-        width: 20px;
-      }
-
       /* Lower-right corner */
       #secure {
         --iron-icon-fill-color: #5a5a5a;
@@ -141,9 +131,6 @@
     <div id="icon"
         class$="[[getIconClass_(networkState, deviceState, isListItem)]]">
     </div>
-    <iron-icon id="technology" hidden="[[!showTechnology_(networkState)]]"
-        icon="[[getTechnology_(networkState)]]">
-    </iron-icon>
     <iron-icon id="secure" hidden="[[!showSecure_(networkState)]]"
         icon="network8:badge-secure">
     </iron-icon>
diff --git a/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js b/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
index d6df9694..255983c 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
+++ b/ui/webui/resources/cr_elements/chromeos/network/cr_network_icon.js
@@ -108,64 +108,6 @@
    * @return {boolean}
    * @private
    */
-  showTechnology_: function() {
-    return this.getTechnology_() != '';
-  },
-
-  /**
-   * @return {string}
-   * @private
-   */
-  getTechnology_: function() {
-    const networkState = this.networkState;
-    if (!networkState)
-      return '';
-    const type = networkState.Type;
-    if (type == CrOnc.Type.WI_MAX)
-      return 'network:4g';
-    if (type == CrOnc.Type.CELLULAR && networkState.Cellular) {
-      const technology =
-          this.getTechnologyId_(networkState.Cellular.NetworkTechnology);
-      if (technology != '')
-        return 'network:' + technology;
-    }
-    return '';
-  },
-
-  /**
-   * @param {string|undefined} networkTechnology
-   * @return {string}
-   * @private
-   */
-  getTechnologyId_: function(networkTechnology) {
-    switch (networkTechnology) {
-      case CrOnc.NetworkTechnology.CDMA1XRTT:
-        return 'badge-1x';
-      case CrOnc.NetworkTechnology.EDGE:
-        return 'badge-edge';
-      case CrOnc.NetworkTechnology.EVDO:
-        return 'badge-evdo';
-      case CrOnc.NetworkTechnology.GPRS:
-      case CrOnc.NetworkTechnology.GSM:
-        return 'badge-gsm';
-      case CrOnc.NetworkTechnology.HSPA:
-        return 'badge-hspa';
-      case CrOnc.NetworkTechnology.HSPA_PLUS:
-        return 'badge-hspa-plus';
-      case CrOnc.NetworkTechnology.LTE:
-        return 'badge-lte';
-      case CrOnc.NetworkTechnology.LTE_ADVANCED:
-        return 'badge-lte-advanced';
-      case CrOnc.NetworkTechnology.UMTS:
-        return 'badge-3g';
-    }
-    return '';
-  },
-
-  /**
-   * @return {boolean}
-   * @private
-   */
   showSecure_: function() {
     const networkState = this.networkState;
     if (!this.networkState)
diff --git a/ui/webui/resources/cr_elements/chromeos/network/network_icons.html b/ui/webui/resources/cr_elements/chromeos/network/network_icons.html
index df5f47c..62e6f831 100644
--- a/ui/webui/resources/cr_elements/chromeos/network/network_icons.html
+++ b/ui/webui/resources/cr_elements/chromeos/network/network_icons.html
@@ -4,24 +4,6 @@
 
 <!-- These icons were converted from source .svg files. -->
 
-<iron-iconset-svg name="network" size="20">
-  <svg>
-    <defs>
-      <!-- Badges -->
-      <g id="badge-1x"><path d="M0 1h1V0h1v5H1V2H0M3 2h1v1H3V2zm1 1h1v1H4V3zM3 4h1v1H3V4zm2 0h1v1H5V4zm0-2h1v1H5V2z"></path></g>
-      <g id="badge-3g"><path d="M9 0H5v5h4V2H7v1h1v1H6V1h3M3 3v2h1V0H0v1h3v1H1v1h2zM0 4h3v1H0V4z"></path></g>
-      <g id="badge-4g"><path d="M3 4v1h1V0H3v3H0v1h3zM0 2h1v1H0V2zm1-1h1v1H1V1zm1-1h1v1H2V0zM9 0H5v5h4V2H7v1h1v1H6V1h3"></path></g>
-      <g id="badge-edge"><path d="M0 0v5h3V4H1V3h1V2H1V1h2V0"></path></g>
-      <g id="badge-evdo"><path d="M0 0v5h3V4H1V3h1V2H1V1h2V0M4 0h1v2H4V0zm1 2h1v2H5V2zm2 0h1v2H7V2zm1-2h1v2H8V0zM6 4h1v1H6V4z"></path></g>
-      <g id="badge-gsm"><path d="M4 0H0v5h4V2H2v1h1v1H1V1h3"></path></g>
-      <g id="badge-hspa"><path d="M0 0h1v2h2V0h1v5H3V3H1v2H0"></path></g>
-      <g id="badge-hspa-plus"><path d="M0 0h1v2h2V0h1v5H3V3H1v2H0M7 1V0H6v1H5v1h1v1h1V2h1V1H7z"></path></g>
-      <g id="badge-lte"><path d="M0 0v5h3V4H1V0M3 0h5v1H6v4H5V1H3M9 0v5h3V4h-2V3h1V2h-1V1h2V0"></path></g>
-      <g id="badge-lte-advanced"><path d="M0 0v5h3V4H1V0M3 0h5v1H6v4H5V1H3M9 0v5h3V4h-2V3h1V2h-1V1h2V0M15 1V0h-1v1h-1v1h1v1h1V2h1V1h-1z"></path></g>
-    </defs>
-  </svg>
-</iron-iconset-svg>
-
 <iron-iconset-svg name="network8" size="8">
   <svg>
     <defs>