diff --git a/DEPS b/DEPS
index ef63b83..03ab669 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,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': 'a16339297859f37df69230e64f05624cef511ad3',
+  'skia_revision': '1e74cad9b4ed8079433d4e62ab3198d97436f5ec',
   # 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': '2b047d6004cf40f27b2b637fc341e3d79b098155',
+  'v8_revision': '5f24a96d070a02d9c4f3b41884e86636a2b9a5b1',
   # 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.
@@ -64,7 +64,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': '5e9066cbfa252b84d49f8b4adba445ba7761e81f',
+  'pdfium_revision': '3128d1c45d8bc313abb8aae151f86bbe62c52e56',
   # 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.
@@ -96,7 +96,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': 'f1ec9eb8cd1564cc3b2e4cc06720d84fe46f9c91',
+  'catapult_revision': 'd49320dbc4480f2961d215cfc79bbbe394f6fdb5',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/WATCHLISTS b/WATCHLISTS
index acc5b161..efb84a2 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -782,7 +782,7 @@
     'payments': {
       'filepath': 'chrome/android/java/src/org/chromium/chrome/browser/payments'\
                   '|chrome/android/javatests/src/org/chromium/chrome/browser/payments'\
-                  '|chrome/test/data/android/payments'\
+                  '|chrome/test/data/payments'\
                   '|components/payments'\
                   '|third_party/WebKit/LayoutTests/payments/'\
                   '|third_party/WebKit/Source/modules/payments'\
diff --git a/ash/common/frame/caption_buttons/frame_caption_button.cc b/ash/common/frame/caption_buttons/frame_caption_button.cc
index 74f1ef9..d496f1b 100644
--- a/ash/common/frame/caption_buttons/frame_caption_button.cc
+++ b/ash/common/frame/caption_buttons/frame_caption_button.cc
@@ -56,10 +56,9 @@
 
 void FrameCaptionButton::SetImage(CaptionButtonIcon icon,
                                   Animate animate,
-                                  const gfx::VectorIcon& icon_definition) {
+                                  gfx::VectorIconId icon_image_id) {
   gfx::ImageSkia new_icon_image = gfx::CreateVectorIcon(
-      icon_definition,
-      use_light_images_ ? SK_ColorWHITE : gfx::kChromeIconGrey);
+      icon_image_id, use_light_images_ ? SK_ColorWHITE : gfx::kChromeIconGrey);
 
   // The early return is dependent on |animate| because callers use SetImage()
   // with ANIMATE_NO to progress the crossfade animation to the end.
@@ -73,7 +72,7 @@
     crossfade_icon_image_ = icon_image_;
 
   icon_ = icon;
-  icon_definition_ = &icon_definition;
+  icon_image_id_ = icon_image_id;
   icon_image_ = new_icon_image;
 
   if (animate == ANIMATE_YES) {
diff --git a/ash/common/frame/caption_buttons/frame_caption_button.h b/ash/common/frame/caption_buttons/frame_caption_button.h
index 8b6df285..3f80862 100644
--- a/ash/common/frame/caption_buttons/frame_caption_button.h
+++ b/ash/common/frame/caption_buttons/frame_caption_button.h
@@ -15,7 +15,7 @@
 
 namespace gfx {
 class SlideAnimation;
-struct VectorIcon;
+enum class VectorIconId;
 }
 
 namespace ash {
@@ -32,12 +32,12 @@
   ~FrameCaptionButton() override;
 
   // Sets the image to use to paint the button. If |animate| is ANIMATE_YES,
-  // the button crossfades to the new visuals. If the image matches the one
+  // the button crossfades to the new visuals. If the image id matches the one
   // currently used by the button and |animate| is ANIMATE_NO, the crossfade
   // animation is progressed to the end.
   void SetImage(CaptionButtonIcon icon,
                 Animate animate,
-                const gfx::VectorIcon& icon_image);
+                gfx::VectorIconId icon_image_id);
 
   // Returns true if the button is crossfading to new visuals set in
   // SetImage().
@@ -59,6 +59,8 @@
 
   CaptionButtonIcon icon() const { return icon_; }
 
+  gfx::VectorIconId icon_image_id() const { return icon_image_id_; }
+
   void set_size(const gfx::Size& size) { size_ = size; }
 
  protected:
@@ -88,7 +90,7 @@
 
   // The image id (kept for the purposes of testing) and image used to paint the
   // button's icon.
-  const gfx::VectorIcon* icon_definition_ = nullptr;
+  gfx::VectorIconId icon_image_id_;
   gfx::ImageSkia icon_image_;
 
   // The icon image to crossfade from.
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc
index 3539a04..77f8006 100644
--- a/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -19,7 +19,7 @@
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/point.h"
-#include "ui/gfx/vector_icon_types.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "ui/strings/grit/ui_strings.h"  // Accessibility names
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -148,15 +148,14 @@
 
 void FrameCaptionButtonContainerView::SetButtonImage(
     CaptionButtonIcon icon,
-    const gfx::VectorIcon& icon_definition) {
-  button_icon_map_[icon] = &icon_definition;
+    gfx::VectorIconId icon_image_id) {
+  button_icon_id_map_[icon] = icon_image_id;
 
   FrameCaptionButton* buttons[] = {minimize_button_, size_button_,
                                    close_button_};
   for (size_t i = 0; i < arraysize(buttons); ++i) {
     if (buttons[i]->icon() == icon)
-      buttons[i]->SetImage(icon, FrameCaptionButton::ANIMATE_NO,
-                           icon_definition);
+      buttons[i]->SetImage(icon, FrameCaptionButton::ANIMATE_NO, icon_image_id);
   }
 }
 
@@ -300,9 +299,9 @@
   FrameCaptionButton::Animate fcb_animate =
       (animate == ANIMATE_YES) ? FrameCaptionButton::ANIMATE_YES
                                : FrameCaptionButton::ANIMATE_NO;
-  auto it = button_icon_map_.find(icon);
-  if (it != button_icon_map_.end())
-    button->SetImage(icon, fcb_animate, *it->second);
+  auto it = button_icon_id_map_.find(icon);
+  if (it != button_icon_id_map_.end())
+    button->SetImage(icon, fcb_animate, it->second);
 }
 
 bool FrameCaptionButtonContainerView::ShouldSizeButtonBeVisible() const {
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view.h b/ash/common/frame/caption_buttons/frame_caption_button_container_view.h
index 014071a..55fd39c 100644
--- a/ash/common/frame/caption_buttons/frame_caption_button_container_view.h
+++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view.h
@@ -16,7 +16,7 @@
 
 namespace gfx {
 class SlideAnimation;
-struct VectorIcon;
+enum class VectorIconId;
 }
 
 namespace views {
@@ -68,8 +68,7 @@
   // Sets the id of the vector image to paint the button for |icon|. The
   // FrameCaptionButtonContainerView will keep track of the image to use for
   // |icon| even if none of the buttons currently use |icon|.
-  void SetButtonImage(CaptionButtonIcon icon,
-                      const gfx::VectorIcon& icon_definition);
+  void SetButtonImage(CaptionButtonIcon icon, gfx::VectorIconId icon_image_id);
 
   // Sets whether the buttons should be painted as active. Does not schedule
   // a repaint.
@@ -142,9 +141,9 @@
   FrameCaptionButton* size_button_;
   FrameCaptionButton* close_button_;
 
-  // Mapping of the image needed to paint a button for each of the values of
+  // Mapping of the image ID needed to paint a button for each of the values of
   // CaptionButtonIcon.
-  std::map<CaptionButtonIcon, const gfx::VectorIcon*> button_icon_map_;
+  std::map<CaptionButtonIcon, gfx::VectorIconId> button_icon_id_map_;
 
   // Animation that affects the position of |minimize_button_| and the
   // visibility of |size_button_|.
diff --git a/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc b/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
index 21fce7ca..067e868 100644
--- a/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
+++ b/ash/common/frame/caption_buttons/frame_caption_button_container_view_unittest.cc
@@ -8,10 +8,10 @@
 #include "ash/common/frame/caption_buttons/frame_caption_button.h"
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm_shell.h"
-#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/test/ash_test_base.h"
 #include "grit/ash_resources.h"
 #include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -71,7 +71,7 @@
         GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON));
     for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) {
       container->SetButtonImage(static_cast<CaptionButtonIcon>(icon),
-                                ash::kWindowControlCloseIcon);
+                                gfx::VectorIconId::WINDOW_CONTROL_CLOSE);
     }
   }
 
diff --git a/ash/common/frame/default_header_painter.cc b/ash/common/frame/default_header_painter.cc
index 4856f7e9..f333bf1 100644
--- a/ash/common/frame/default_header_painter.cc
+++ b/ash/common/frame/default_header_painter.cc
@@ -7,7 +7,6 @@
 #include "ash/common/ash_layout_constants.h"
 #include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/common/frame/header_painter_util.h"
-#include "ash/resources/vector_icons/vector_icons.h"
 #include "base/debug/leak_annotations.h"
 #include "base/logging.h"  // DCHECK
 #include "grit/ash_resources.h"
@@ -22,6 +21,7 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/native_widget_aura.h"
 #include "ui/views/widget/widget.h"
@@ -283,27 +283,29 @@
 
 void DefaultHeaderPainter::UpdateAllButtonImages() {
   caption_button_container_->SetUseLightImages(ShouldUseLightImages());
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_MINIMIZE,
-                                            kWindowControlMinimizeIcon);
+  caption_button_container_->SetButtonImage(
+      CAPTION_BUTTON_ICON_MINIMIZE, gfx::VectorIconId::WINDOW_CONTROL_MINIMIZE);
 
   UpdateSizeButtonImages();
 
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_CLOSE,
-                                            kWindowControlCloseIcon);
+  caption_button_container_->SetButtonImage(
+      CAPTION_BUTTON_ICON_CLOSE, gfx::VectorIconId::WINDOW_CONTROL_CLOSE);
 
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_LEFT_SNAPPED,
-                                            kWindowControlLeftSnappedIcon);
+  caption_button_container_->SetButtonImage(
+      CAPTION_BUTTON_ICON_LEFT_SNAPPED,
+      gfx::VectorIconId::WINDOW_CONTROL_LEFT_SNAPPED);
 
-  caption_button_container_->SetButtonImage(CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
-                                            kWindowControlRightSnappedIcon);
+  caption_button_container_->SetButtonImage(
+      CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
+      gfx::VectorIconId::WINDOW_CONTROL_RIGHT_SNAPPED);
 }
 
 void DefaultHeaderPainter::UpdateSizeButtonImages() {
-  const gfx::VectorIcon& icon = frame_->IsMaximized() || frame_->IsFullscreen()
-                                    ? kWindowControlRestoreIcon
-                                    : kWindowControlMaximizeIcon;
+  gfx::VectorIconId icon_id = frame_->IsMaximized() || frame_->IsFullscreen()
+                                  ? gfx::VectorIconId::WINDOW_CONTROL_RESTORE
+                                  : gfx::VectorIconId::WINDOW_CONTROL_MAXIMIZE;
   caption_button_container_->SetButtonImage(
-      CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, icon);
+      CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, icon_id);
 }
 
 gfx::Rect DefaultHeaderPainter::GetLocalBounds() const {
diff --git a/ash/common/system/tray/tray_popup_header_button.cc b/ash/common/system/tray/tray_popup_header_button.cc
index 576ec92e..804fcb8 100644
--- a/ash/common/system/tray/tray_popup_header_button.cc
+++ b/ash/common/system/tray/tray_popup_header_button.cc
@@ -44,7 +44,7 @@
   SetToggledImage(views::Button::STATE_NORMAL,
                   bundle.GetImageNamed(disabled_resource_id).ToImageSkia());
   SetImage(views::Button::STATE_HOVERED,
-           *bundle.GetImageNamed(enabled_resource_id_hover).ToImageSkia());
+           bundle.GetImageNamed(enabled_resource_id_hover).ToImageSkia());
   SetToggledImage(
       views::Button::STATE_HOVERED,
       bundle.GetImageNamed(disabled_resource_id_hover).ToImageSkia());
@@ -74,7 +74,7 @@
 void TrayPopupHeaderButton::Initialize(const gfx::ImageSkia& icon,
                                        int accessible_name_id) {
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  SetImage(views::Button::STATE_NORMAL, icon);
+  SetImage(views::Button::STATE_NORMAL, &icon);
   SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                     views::ImageButton::ALIGN_MIDDLE);
   SetAccessibleName(bundle.GetLocalizedString(accessible_name_id));
diff --git a/ash/common/wm/overview/window_selector_item.cc b/ash/common/wm/overview/window_selector_item.cc
index 647b739..182beb5 100644
--- a/ash/common/wm/overview/window_selector_item.cc
+++ b/ash/common/wm/overview/window_selector_item.cc
@@ -23,7 +23,6 @@
 #include "ash/common/wm_window.h"
 #include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
-#include "ash/resources/vector_icons/vector_icons.h"
 #include "base/auto_reset.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -38,6 +37,7 @@
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/transform_util.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "ui/strings/grit/ui_strings.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
@@ -130,8 +130,9 @@
 WindowSelectorItem::OverviewCloseButton::OverviewCloseButton(
     views::ButtonListener* listener)
     : views::ImageButton(listener) {
-  SetImage(views::CustomButton::STATE_NORMAL,
-           gfx::CreateVectorIcon(kWindowControlCloseIcon, kCloseButtonColor));
+  icon_image_ = gfx::CreateVectorIcon(gfx::VectorIconId::WINDOW_CONTROL_CLOSE,
+                                      kCloseButtonColor);
+  SetImage(views::CustomButton::STATE_NORMAL, &icon_image_);
   SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                     views::ImageButton::ALIGN_MIDDLE);
   SetMinimumImageSize(gfx::Size(kHeaderHeight, kHeaderHeight));
diff --git a/ash/common/wm/overview/window_selector_item.h b/ash/common/wm/overview/window_selector_item.h
index 65b4293..f2ff9df 100644
--- a/ash/common/wm/overview/window_selector_item.h
+++ b/ash/common/wm/overview/window_selector_item.h
@@ -75,6 +75,8 @@
     void ResetListener() { listener_ = nullptr; }
 
    private:
+    gfx::ImageSkia icon_image_;
+
     DISALLOW_COPY_AND_ASSIGN(OverviewCloseButton);
   };
 
diff --git a/ash/frame/caption_buttons/frame_size_button_unittest.cc b/ash/frame/caption_buttons/frame_size_button_unittest.cc
index a14c83d6..0de43d49 100644
--- a/ash/frame/caption_buttons/frame_size_button_unittest.cc
+++ b/ash/frame/caption_buttons/frame_size_button_unittest.cc
@@ -8,7 +8,6 @@
 #include "ash/common/frame/caption_buttons/frame_caption_button.h"
 #include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/common/wm/window_state.h"
-#include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/window_state_aura.h"
@@ -19,6 +18,7 @@
 #include "ui/display/screen.h"
 #include "ui/events/gesture_detection/gesture_configuration.h"
 #include "ui/events/test/event_generator.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
@@ -65,7 +65,8 @@
           GetAshLayoutSize(AshLayoutSize::NON_BROWSER_CAPTION_BUTTON));
       for (int icon = 0; icon < CAPTION_BUTTON_ICON_COUNT; ++icon) {
         caption_button_container_->SetButtonImage(
-            static_cast<CaptionButtonIcon>(icon), kWindowControlCloseIcon);
+            static_cast<CaptionButtonIcon>(icon),
+            gfx::VectorIconId::WINDOW_CONTROL_CLOSE);
       }
 
       AddChildView(caption_button_container_);
diff --git a/ash/resources/vector_icons/BUILD.gn b/ash/resources/vector_icons/BUILD.gn
index 14b065bb..9eddf84 100644
--- a/ash/resources/vector_icons/BUILD.gn
+++ b/ash/resources/vector_icons/BUILD.gn
@@ -206,20 +206,6 @@
     "system_tray_update.icon",
     "system_tray_volume_mute.1x.icon",
     "system_tray_volume_mute.icon",
-    "window_control_back.1x.icon",
-    "window_control_back.icon",
-    "window_control_close.1x.icon",
-    "window_control_close.icon",
-    "window_control_left_snapped.1x.icon",
-    "window_control_left_snapped.icon",
-    "window_control_maximize.1x.icon",
-    "window_control_maximize.icon",
-    "window_control_minimize.1x.icon",
-    "window_control_minimize.icon",
-    "window_control_restore.1x.icon",
-    "window_control_restore.icon",
-    "window_control_right_snapped.1x.icon",
-    "window_control_right_snapped.icon",
   ]
 
   output_cc = "$target_gen_dir/vector_icons.cc"
diff --git a/base/allocator/partition_allocator/partition_alloc.cc b/base/allocator/partition_allocator/partition_alloc.cc
index c2dbb578..29cde93 100644
--- a/base/allocator/partition_allocator/partition_alloc.cc
+++ b/base/allocator/partition_allocator/partition_alloc.cc
@@ -245,60 +245,6 @@
   *bucketPtr = &PartitionRootGeneric::gPagedBucket;
 }
 
-static bool PartitionAllocShutdownBucket(PartitionBucket* bucket) {
-  // Failure here indicates a memory leak.
-  bool foundLeak = bucket->num_full_pages != 0;
-  for (PartitionPage* page = bucket->active_pages_head; page;
-       page = page->next_page)
-    foundLeak |= (page->num_allocated_slots > 0);
-  return foundLeak;
-}
-
-static bool PartitionAllocBaseShutdown(PartitionRootBase* root) {
-  DCHECK(root->initialized);
-  root->initialized = false;
-
-  // Now that we've examined all partition pages in all buckets, it's safe
-  // to free all our super pages. Since the super page extent entries are
-  // stored in the super pages, we need to be careful not to access them
-  // after we've released the corresponding super page.
-  PartitionSuperPageExtentEntry* entry = root->first_extent;
-  while (entry) {
-    PartitionSuperPageExtentEntry* nextEntry = entry->next;
-    char* super_page = entry->super_page_base;
-    char* super_pages_end = entry->super_pages_end;
-    while (super_page < super_pages_end) {
-      FreePages(super_page, kSuperPageSize);
-      super_page += kSuperPageSize;
-    }
-    entry = nextEntry;
-  }
-  return root->direct_map_list != nullptr;
-}
-
-bool PartitionAllocShutdown(PartitionRoot* root) {
-  bool foundLeak = false;
-  size_t i;
-  for (i = 0; i < root->num_buckets; ++i) {
-    PartitionBucket* bucket = &root->buckets()[i];
-    foundLeak |= PartitionAllocShutdownBucket(bucket);
-  }
-  foundLeak |= PartitionAllocBaseShutdown(root);
-  return !foundLeak;
-}
-
-bool PartitionAllocGenericShutdown(PartitionRootGeneric* root) {
-  subtle::SpinLock::Guard guard(root->lock);
-  bool foundLeak = false;
-  size_t i;
-  for (i = 0; i < kGenericNumBuckets; ++i) {
-    PartitionBucket* bucket = &root->buckets[i];
-    foundLeak |= PartitionAllocShutdownBucket(bucket);
-  }
-  foundLeak |= PartitionAllocBaseShutdown(root);
-  return !foundLeak;
-}
-
 #if !defined(ARCH_CPU_64_BITS)
 static NOINLINE void partitionOutOfMemoryWithLotsOfUncommitedPages() {
   OOM_CRASH();
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index 0fafdf6..15a501ae 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -406,9 +406,7 @@
 BASE_EXPORT void PartitionAllocInit(PartitionRoot*,
                                     size_t num_buckets,
                                     size_t max_allocation);
-BASE_EXPORT bool PartitionAllocShutdown(PartitionRoot*);
 BASE_EXPORT void PartitionAllocGenericInit(PartitionRootGeneric*);
-BASE_EXPORT bool PartitionAllocGenericShutdown(PartitionRootGeneric*);
 
 enum PartitionPurgeFlags {
   // Decommitting the ring list of empty pages is reasonably fast.
@@ -886,7 +884,6 @@
   void init() {
     PartitionAllocInit(&partition_root_, kNumBuckets, kMaxAllocation);
   }
-  bool shutdown() { return PartitionAllocShutdown(&partition_root_); }
   ALWAYS_INLINE PartitionRoot* root() { return &partition_root_; }
 
  private:
@@ -897,7 +894,6 @@
 class PartitionAllocatorGeneric {
  public:
   void init() { PartitionAllocGenericInit(&partition_root_); }
-  bool shutdown() { return PartitionAllocGenericShutdown(&partition_root_); }
   ALWAYS_INLINE PartitionRootGeneric* root() { return &partition_root_; }
 
  private:
diff --git a/base/allocator/partition_allocator/partition_alloc_unittest.cc b/base/allocator/partition_allocator/partition_alloc_unittest.cc
index dd1136f..2ddde105b 100644
--- a/base/allocator/partition_allocator/partition_alloc_unittest.cc
+++ b/base/allocator/partition_allocator/partition_alloc_unittest.cc
@@ -60,13 +60,6 @@
   generic_allocator.init();
 }
 
-void TestShutdown() {
-  // We expect no leaks in the general case. We have a test for leak
-  // detection.
-  EXPECT_TRUE(allocator.shutdown());
-  EXPECT_TRUE(generic_allocator.shutdown());
-}
-
 #if !defined(ARCH_CPU_64_BITS) || defined(OS_POSIX)
 bool SetAddressSpaceLimit() {
 #if !defined(ARCH_CPU_64_BITS)
@@ -270,20 +263,6 @@
   // decommitted.
   EXPECT_TRUE(bucket->empty_pages_head);
   EXPECT_FALSE(bucket->decommitted_pages_head);
-
-  TestShutdown();
-}
-
-// Check that we can detect a memory leak.
-TEST(PartitionAllocTest, SimpleLeak) {
-  TestSetup();
-  void* leakedPtr = PartitionAlloc(allocator.root(), kTestAllocSize, type_name);
-  (void)leakedPtr;
-  void* leakedPtr2 = PartitionAllocGeneric(generic_allocator.root(),
-                                           kTestAllocSize, type_name);
-  (void)leakedPtr2;
-  EXPECT_FALSE(allocator.shutdown());
-  EXPECT_FALSE(generic_allocator.shutdown());
 }
 
 // Test multiple allocations, and freelist handling.
@@ -322,8 +301,6 @@
   PartitionFree(ptr1);
   PartitionFree(ptr2);
   PartitionFree(ptr3);
-
-  TestShutdown();
 }
 
 // Test a bucket with multiple pages.
@@ -366,8 +343,6 @@
   EXPECT_EQ(0, page2->num_allocated_slots);
   EXPECT_EQ(0, page2->num_unprovisioned_slots);
   EXPECT_NE(-1, page2->empty_cache_index);
-
-  TestShutdown();
 }
 
 // Test some finer aspects of internal page transitions.
@@ -428,8 +403,6 @@
   ptr = reinterpret_cast<char*>(
       PartitionAlloc(allocator.root(), kTestAllocSize, type_name));
   PartitionFree(ptr);
-
-  TestShutdown();
 }
 
 // Test some corner cases relating to page transitions in the internal
@@ -473,8 +446,6 @@
     FreeFullPage(pages[i]);
   EXPECT_EQ(&PartitionRootGeneric::gSeedPage, bucket->active_pages_head);
   EXPECT_TRUE(bucket->empty_pages_head);
-
-  TestShutdown();
 }
 
 // Test a large series of allocations that cross more than one underlying
@@ -511,8 +482,6 @@
   }
   for (i = 0; i < numPagesNeeded; ++i)
     FreeFullPage(pages[i]);
-
-  TestShutdown();
 }
 
 // Test the generic allocation functions that can handle arbitrary sizes and
@@ -607,7 +576,6 @@
   EXPECT_EQ(*newCharPtr, 'F');
 
   PartitionFreeGeneric(generic_allocator.root(), newPtr);
-  TestShutdown();
 }
 
 // Test the generic allocation functions can handle some specific sizes of
@@ -705,8 +673,6 @@
   EXPECT_EQ(0, PartitionAllocGenericFlags(generic_allocator.root(),
                                           PartitionAllocReturnNull,
                                           3u * 1024 * 1024 * 1024, type_name));
-
-  TestShutdown();
 }
 
 // Test that we can fetch the real allocated size after an allocation.
@@ -778,8 +744,6 @@
   predictedSize =
       PartitionAllocActualSize(generic_allocator.root(), requestedSize);
   EXPECT_EQ(requestedSize, predictedSize);
-
-  TestShutdown();
 }
 
 // Test the realloc() contract.
@@ -852,8 +816,6 @@
   EXPECT_NE(ptr, ptr2);
 
   PartitionFreeGeneric(generic_allocator.root(), ptr2);
-
-  TestShutdown();
 }
 
 // Tests the handing out of freelists for partial pages.
@@ -1010,8 +972,6 @@
       (pageSize + kExtraAllocSize);
   EXPECT_EQ(totalSlots - 1, page->num_unprovisioned_slots);
   PartitionFreeGeneric(generic_allocator.root(), ptr);
-
-  TestShutdown();
 }
 
 // Test some of the fragmentation-resistant properties of the allocator.
@@ -1047,8 +1007,6 @@
   FreeFullPage(page2);
   FreeFullPage(page1);
   PartitionFree(ptr);
-
-  TestShutdown();
 }
 
 // Basic tests to ensure that allocations work for partial page buckets.
@@ -1071,8 +1029,6 @@
   PartitionPage* page2 = GetFullPage(size);
   FreeFullPage(page2);
   FreeFullPage(page1);
-
-  TestShutdown();
 }
 
 // Test correct handling if our mapping collides with another.
@@ -1155,8 +1111,6 @@
     FreeFullPage(firstSuperPagePages[i]);
     FreeFullPage(secondSuperPagePages[i]);
   }
-
-  TestShutdown();
 }
 
 // Tests that pages in the free page cache do get freed as appropriate.
@@ -1210,7 +1164,6 @@
   }
   EXPECT_EQ(kPartitionPageSize,
             allocator.root()->total_size_of_committed_pages);
-  TestShutdown();
 }
 
 // Tests for a bug we had with losing references to free pages.
@@ -1274,8 +1227,6 @@
   EXPECT_TRUE(bucket->active_pages_head);
   EXPECT_TRUE(bucket->empty_pages_head);
   EXPECT_TRUE(bucket->decommitted_pages_head);
-
-  TestShutdown();
 }
 
 #if !defined(ARCH_CPU_64_BITS) || defined(OS_POSIX)
@@ -1333,8 +1284,6 @@
   PartitionFreeGeneric(generic_allocator.root(), ptrs);
 
   EXPECT_TRUE(ClearAddressSpaceLimit());
-
-  TestShutdown();
 }
 
 // Tests that if an allocation fails in "return null" mode, repeating it doesn't
@@ -1387,8 +1336,6 @@
       PartitionAllocGeneric(generic_allocator.root(),
                             static_cast<size_t>(INT_MAX) + 1, type_name),
       "");
-
-  TestShutdown();
 }
 
 // Check that our immediate double-free detection works.
@@ -1401,8 +1348,6 @@
   PartitionFreeGeneric(generic_allocator.root(), ptr);
 
   EXPECT_DEATH(PartitionFreeGeneric(generic_allocator.root(), ptr), "");
-
-  TestShutdown();
 }
 
 // Check that our refcount-based double-free detection works.
@@ -1421,8 +1366,6 @@
   // fire. However, it does take the "refcount" of the partition page to -1,
   // which is illegal and should be trapped.
   EXPECT_DEATH(PartitionFreeGeneric(generic_allocator.root(), ptr), "");
-
-  TestShutdown();
 }
 
 // Check that guard pages are present where expected.
@@ -1458,8 +1401,6 @@
   EXPECT_DEATH(*(charPtr + size + kExtraAllocSize) = 'A', "");
 
   PartitionFreeGeneric(generic_allocator.root(), ptr);
-
-  TestShutdown();
 }
 
 // Check that a bad free() is caught where the free() refers to an unused
@@ -1477,8 +1418,6 @@
   EXPECT_DEATH(PartitionFreeGeneric(generic_allocator.root(), badPtr), "");
 
   PartitionFreeGeneric(generic_allocator.root(), ptr);
-
-  TestShutdown();
 }
 
 #endif  // !defined(OS_ANDROID) && !defined(OS_IOS)
@@ -1755,8 +1694,6 @@
 
     PartitionFreeGeneric(generic_allocator.root(), ptr2);
   }
-
-  TestShutdown();
 }
 
 // Tests the API to purge freeable memory.
@@ -1807,8 +1744,6 @@
 
   CheckPageInCore(ptr - kPointerOffset, false);
   CheckPageInCore(bigPtr - kPointerOffset, false);
-
-  TestShutdown();
 }
 
 // Tests that we prefer to allocate into a non-empty partition page over an
@@ -1862,8 +1797,6 @@
 
   PartitionFreeGeneric(generic_allocator.root(), ptr5);
   PartitionFreeGeneric(generic_allocator.root(), ptr7);
-
-  TestShutdown();
 }
 
 // Tests the API to purge discardable memory.
@@ -2140,8 +2073,6 @@
     PartitionFreeGeneric(generic_allocator.root(), ptr1);
     PartitionFreeGeneric(generic_allocator.root(), ptr2);
   }
-
-  TestShutdown();
 }
 
 }  // namespace base
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
index ecb08421..2911b36 100644
--- a/base/process/kill_win.cc
+++ b/base/process/kill_win.cc
@@ -17,8 +17,7 @@
 #include "base/macros.h"
 #include "base/process/memory.h"
 #include "base/process/process_iterator.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/win/object_watcher.h"
+#include "base/task_scheduler/post_task.h"
 
 namespace base {
 
@@ -38,62 +37,6 @@
 // process goes away.
 const DWORD kProcessKilledExitCode = 1;
 
-// Maximum amount of time (in milliseconds) to wait for the process to exit.
-static const int kWaitInterval = 2000;
-
-class TimerExpiredTask : public win::ObjectWatcher::Delegate {
- public:
-  explicit TimerExpiredTask(Process process);
-  ~TimerExpiredTask() override;
-
-  void TimedOut();
-
-  // win::ObjectWatcher::Delegate implementation.
-  void OnObjectSignaled(HANDLE object) override;
-
- private:
-  void KillProcess();
-
-  // The process that we are watching.
-  Process process_;
-
-  win::ObjectWatcher watcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
-};
-
-TimerExpiredTask::TimerExpiredTask(Process process)
-    : process_(std::move(process)) {
-  watcher_.StartWatchingOnce(process_.Handle(), this);
-}
-
-TimerExpiredTask::~TimerExpiredTask() {
-  TimedOut();
-}
-
-void TimerExpiredTask::TimedOut() {
-  if (process_.IsValid())
-    KillProcess();
-}
-
-void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
-  process_.Close();
-}
-
-void TimerExpiredTask::KillProcess() {
-  // Stop watching the process handle since we're killing it.
-  watcher_.StopWatching();
-
-  // OK, time to get frisky.  We don't actually care when the process
-  // terminates.  We just care that it eventually terminates, and that's what
-  // TerminateProcess should do for us. Don't check for the result code since
-  // it fails quite often. This should be investigated eventually.
-  process_.Terminate(kProcessKilledExitCode, false);
-
-  // Now, just cleanup as if the process exited normally.
-  OnObjectSignaled(process_.Handle());
-}
-
 }  // namespace
 
 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
@@ -196,14 +139,22 @@
   DCHECK(!process.is_current());
 
   // If already signaled, then we are done!
-  if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) {
+  if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0)
     return;
-  }
 
-  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, Bind(&TimerExpiredTask::TimedOut,
-                      Owned(new TimerExpiredTask(std::move(process)))),
-      TimeDelta::FromMilliseconds(kWaitInterval));
+  PostDelayedTaskWithTraits(
+      FROM_HERE,
+      TaskTraits()
+          .WithPriority(TaskPriority::BACKGROUND)
+          .WithShutdownBehavior(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN),
+      Bind(
+          [](Process process) {
+            if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0)
+              return;
+            process.Terminate(kProcessKilledExitCode, false);
+          },
+          Passed(&process)),
+      TimeDelta::FromSeconds(2));
 }
 
 }  // namespace base
diff --git a/build/nocompile.gni b/build/nocompile.gni
index d425b79..f93ac94 100644
--- a/build/nocompile.gni
+++ b/build/nocompile.gni
@@ -59,7 +59,7 @@
 
 declare_args() {
   # TODO(crbug.com/105388): make sure no-compile test is not flaky.
-  enable_nocompile_tests = is_linux && is_clang
+  enable_nocompile_tests = is_linux && is_clang && host_cpu == target_cpu
 }
 
 if (enable_nocompile_tests) {
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index eca238a..2c185ad 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -459,6 +459,7 @@
     "//chrome/test/data/image_search/valid.png",
     "//chrome/test/data/navigation_interception/",
     "//chrome/test/data/notifications/",
+    "//chrome/test/data/payments/",
     "//chrome/test/data/popup_blocker/",
     "//chrome/test/data/push_messaging/",
     "//chrome/test/data/translate/",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 3fca8463..5196282 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -413,6 +413,12 @@
             android:hardwareAccelerated="false">
         </activity>
 
+        <activity android:name="org.chromium.chrome.browser.suggestions.ContentSuggestionsActivity"
+            android:theme="@style/FullscreenWhiteActivityTheme"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|mcc|mnc|screenLayout|smallestScreenSize"
+            android:windowSoftInputMode="stateAlwaysHidden">
+        </activity>
+
         <activity android:name="org.chromium.chrome.browser.sync.ui.PassphraseActivity"
             android:theme="@style/MainTheme"
             android:autoRemoveFromRecents="true">
diff --git a/chrome/android/java/res/menu/main_menu.xml b/chrome/android/java/res/menu/main_menu.xml
index 63900b37..9d87b740 100644
--- a/chrome/android/java/res/menu/main_menu.xml
+++ b/chrome/android/java/res/menu/main_menu.xml
@@ -70,6 +70,9 @@
             android:title="@string/menu_help" />
         <item android:id="@+id/enter_vr_id"
             android:title="@string/enter_vr" />
+        <item android:id="@+id/content_suggestions_standalone_ui"
+            android:title="@null"
+            android:visible="false" />
     </group>
 
     <!-- Items shown only in the tab switcher -->
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 65c55a4..872eabe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -91,6 +91,8 @@
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.nfc.BeamController;
 import org.chromium.chrome.browser.nfc.BeamProvider;
+import org.chromium.chrome.browser.ntp.NewTabPage;
+import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.omaha.UpdateMenuItemHelper;
@@ -1712,11 +1714,14 @@
             WebsiteSettingsPopup.show(
                     this, currentTab, null, WebsiteSettingsPopup.OPENED_FROM_MENU);
         } else if (id == R.id.open_history_menu_id) {
+            if (NewTabPage.isNTPUrl(currentTab.getUrl())) {
+                NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_HISTORY_MANAGER);
+            }
+            RecordUserAction.record("MobileMenuHistory");
             if (!HistoryManagerUtils.showHistoryManager(this, currentTab)) {
                 currentTab.loadUrl(
                         new LoadUrlParams(UrlConstants.HISTORY_URL, PageTransition.AUTO_TOPLEVEL));
             }
-            RecordUserAction.record("MobileMenuHistory");
             StartupMetrics.getInstance().recordOpenedHistory();
         } else if (id == R.id.share_menu_id || id == R.id.direct_share_menu_id) {
             onShareMenuItemSelected(id == R.id.direct_share_menu_id,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 0918dbb..285d9b51 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -70,6 +70,7 @@
     public static final String NTP_SNIPPETS_SAVE_TO_OFFLINE = "NTPSaveToOffline";
     public static final String NTP_SNIPPETS_OFFLINE_BADGE = "NTPOfflineBadge";
     public static final String NTP_SUGGESTIONS_SECTION_DISMISSAL = "NTPSuggestionsSectionDismissal";
+    public static final String NTP_SUGGESTIONS_STANDALONE_UI = "NTPSuggestionsStandaloneUI";
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
     public static final String TAB_REPARENTING = "TabReparenting";
     public static final String VR_SHELL = "VrShell";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 155ee312..0b1db2b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -79,6 +79,7 @@
 import org.chromium.chrome.browser.metrics.UmaUtils;
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.ntp.NativePageAssassin;
+import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig;
@@ -91,6 +92,7 @@
 import org.chromium.chrome.browser.preferences.datareduction.DataReductionPromoScreen;
 import org.chromium.chrome.browser.signin.SigninPromoUtil;
 import org.chromium.chrome.browser.snackbar.undo.UndoBarController;
+import org.chromium.chrome.browser.suggestions.ContentSuggestionsActivity;
 import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabDelegateFactory;
@@ -1167,6 +1169,7 @@
     @Override
     public boolean onMenuOrKeyboardAction(final int id, boolean fromMenu) {
         final Tab currentTab = getActivityTab();
+        boolean currentTabIsNtp = currentTab != null && NewTabPage.isNTPUrl(currentTab.getUrl());
         if (id == R.id.move_to_other_window_menu_id) {
             if (currentTab != null) moveTabToOtherWindow(currentTab);
         } else if (id == R.id.new_tab_menu_id) {
@@ -1195,6 +1198,9 @@
                         BookmarkUtils.showBookmarkManager(ChromeTabbedActivity.this);
                     }
                 });
+                if (currentTabIsNtp) {
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARKS_MANAGER);
+                }
                 RecordUserAction.record("MobileMenuAllBookmarks");
             }
         } else if (id == R.id.recent_tabs_menu_id) {
@@ -1202,6 +1208,9 @@
                 currentTab.loadUrl(new LoadUrlParams(
                         UrlConstants.RECENT_TABS_URL,
                         PageTransition.AUTO_BOOKMARK));
+                if (currentTabIsNtp) {
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_RECENT_TABS_MANAGER);
+                }
                 RecordUserAction.record("MobileMenuRecentTabs");
             }
         } else if (id == R.id.close_all_tabs_menu_id) {
@@ -1231,6 +1240,9 @@
             }
         } else if (id == R.id.downloads_menu_id) {
             DownloadUtils.showDownloadManager(this, currentTab);
+            if (currentTabIsNtp) {
+                NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_DOWNLOADS_MANAGER);
+            }
             RecordUserAction.record("MobileMenuDownloadManager");
         } else if (id == R.id.open_recently_closed_tab) {
             TabModel currentModel = mTabModelSelectorImpl.getCurrentModel();
@@ -1238,6 +1250,8 @@
             RecordUserAction.record("MobileTabClosedUndoShortCut");
         } else if (id == R.id.enter_vr_id) {
             mVrShellDelegate.enterVRIfNecessary();
+        } else if (id == R.id.content_suggestions_standalone_ui) {
+            ContentSuggestionsActivity.launch(getApplicationContext());
         } else {
             return super.onMenuOrKeyboardAction(id, fromMenu);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
index 79187b6..6f574fce 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -13,6 +13,7 @@
 import org.chromium.base.CommandLine;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ShortcutHelper;
 import org.chromium.chrome.browser.UrlConstants;
@@ -188,6 +189,14 @@
             // Only display the Enter VR button if VR Shell Dev environment is enabled.
             menu.findItem(R.id.enter_vr_id).setVisible(
                     CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV));
+
+            // Only display the standalone content suggestions UI if the corresponding feature
+            // is enabled.
+            if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SUGGESTIONS_STANDALONE_UI)) {
+                MenuItem item = menu.findItem(R.id.content_suggestions_standalone_ui);
+                item.setTitle("🔰🆕👌");
+                item.setVisible(true);
+            }
         }
 
         if (isOverviewMenu) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
index 4fe5ae4..84fec0b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkUtils.java
@@ -22,7 +22,6 @@
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
-import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.snackbar.Snackbar;
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarController;
@@ -240,7 +239,7 @@
 
         String url = model.getBookmarkById(bookmarkId).getUrl();
 
-        NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARK);
+        RecordUserAction.record("MobileBookmarkManagerEntryOpened");
         RecordHistogram.recordEnumeratedHistogram(
                 "Stars.LaunchLocation", launchLocation, BookmarkLaunchLocation.COUNT);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
index dc92632..cea90a8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationConstants.java
@@ -9,31 +9,29 @@
  */
 public class NotificationConstants {
     // These actions have to be synchronized with the receiver defined in AndroidManifest.xml.
-    public static final String ACTION_CLICK_NOTIFICATION =
+    static final String ACTION_CLICK_NOTIFICATION =
             "org.chromium.chrome.browser.notifications.CLICK_NOTIFICATION";
-    public static final String ACTION_CLOSE_NOTIFICATION =
+    static final String ACTION_CLOSE_NOTIFICATION =
             "org.chromium.chrome.browser.notifications.CLOSE_NOTIFICATION";
 
     /**
      * Name of the Intent extra set by the framework when a notification preferences intent has
      * been triggered from there, which could be one of the setting gears in system UI.
      */
-    public static final String EXTRA_NOTIFICATION_TAG = "notification_tag";
+    static final String EXTRA_NOTIFICATION_TAG = "notification_tag";
 
     /**
      * Names of the Intent extras used for Intents related to notifications. These intents are set
      * and owned by Chromium.
      */
-    public static final String EXTRA_NOTIFICATION_ID = "notification_id";
-    public static final String EXTRA_NOTIFICATION_INFO_ORIGIN = "notification_info_origin";
-    public static final String EXTRA_NOTIFICATION_INFO_PROFILE_ID = "notification_info_profile_id";
-    public static final String EXTRA_NOTIFICATION_INFO_PROFILE_INCOGNITO =
+    static final String EXTRA_NOTIFICATION_ID = "notification_id";
+    static final String EXTRA_NOTIFICATION_INFO_ORIGIN = "notification_info_origin";
+    static final String EXTRA_NOTIFICATION_INFO_PROFILE_ID = "notification_info_profile_id";
+    static final String EXTRA_NOTIFICATION_INFO_PROFILE_INCOGNITO =
             "notification_info_profile_incognito";
-    public static final String EXTRA_NOTIFICATION_INFO_TAG = "notification_info_tag";
-    public static final String EXTRA_NOTIFICATION_INFO_ACTION_INDEX =
-            "notification_info_action_index";
-    public static final String EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE =
-            "notification_info_webapk_package";
+    static final String EXTRA_NOTIFICATION_INFO_TAG = "notification_info_tag";
+    static final String EXTRA_NOTIFICATION_INFO_ACTION_INDEX = "notification_info_action_index";
+    static final String EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE = "notification_info_webapk_package";
 
     /**
      * Unique identifier for a single sync notification. Since the notification ID is reused,
@@ -43,6 +41,7 @@
     /**
      * Unique identifier for the "Signed in to Chrome" notification.
      */
+    @SuppressWarnings("unused")
     public static final int NOTIFICATION_ID_SIGNED_IN = 2;
     /**
      * Unique identifier for the Physical Web notification.
@@ -53,7 +52,7 @@
      * Separator used to separate the notification origin from additional data such as the
      * developer specified tag.
      */
-    public static final String NOTIFICATION_TAG_SEPARATOR = ";";
+    static final String NOTIFICATION_TAG_SEPARATOR = ";";
 
     /**
      * Key for retrieving the results of user input from notification text action intents.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
index 26a96f9..3399dae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java
@@ -72,11 +72,11 @@
     private static final int[] EMPTY_VIBRATION_PATTERN = new int[0];
 
     private static NotificationPlatformBridge sInstance;
+
     private static NotificationManagerProxy sNotificationManagerOverride;
 
     private final long mNativeNotificationPlatformBridge;
 
-    private final Context mAppContext;
     private final NotificationManagerProxy mNotificationManager;
 
     private long mLastNotificationClickMs;
@@ -114,24 +114,22 @@
      * Android framework. Should only be used for testing. Tests are expected to clean up after
      * themselves by setting this to NULL again.
      *
-     * @param proxy The notification manager instance to use instead of the system's.
+     * @param notificationManager The notification manager instance to use instead of the system's.
      */
     @VisibleForTesting
-    public static void overrideNotificationManagerForTesting(
+    static void overrideNotificationManagerForTesting(
             NotificationManagerProxy notificationManager) {
         sNotificationManagerOverride = notificationManager;
     }
 
     private NotificationPlatformBridge(long nativeNotificationPlatformBridge) {
         mNativeNotificationPlatformBridge = nativeNotificationPlatformBridge;
-        mAppContext = ContextUtils.getApplicationContext();
-
+        Context context = ContextUtils.getApplicationContext();
         if (sNotificationManagerOverride != null) {
             mNotificationManager = sNotificationManagerOverride;
         } else {
             mNotificationManager = new NotificationManagerProxyImpl(
-                    (NotificationManager) mAppContext.getSystemService(
-                            Context.NOTIFICATION_SERVICE));
+                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE));
         }
     }
 
@@ -157,7 +155,7 @@
         if (!ChromeWebApkHost.isEnabled()) return "";
 
         String webApkPackage =
-                WebApkValidator.queryWebApkPackage(mAppContext, url);
+                WebApkValidator.queryWebApkPackage(ContextUtils.getApplicationContext(), url);
         return webApkPackage == null ? "" : webApkPackage;
     }
 
@@ -169,7 +167,7 @@
      * @param intent The intent as received by the Notification service.
      * @return Whether the event could be handled by the native Notification bridge.
      */
-    public static boolean dispatchNotificationEvent(Intent intent) {
+    static boolean dispatchNotificationEvent(Intent intent) {
         if (sInstance == null) {
             nativeInitializeNotificationPlatformBridge();
             if (sInstance == null) {
@@ -314,22 +312,23 @@
      * Returns the PendingIntent for completing |action| on the notification identified by the data
      * in the other parameters.
      *
+     * @param context An appropriate context for the intent class and broadcast.
      * @param action The action this pending intent will represent.
-     * @paramn notificationId The id of the notification.
+     * @param notificationId The id of the notification.
      * @param origin The origin to whom the notification belongs.
      * @param profileId Id of the profile to which the notification belongs.
      * @param incognito Whether the profile was in incognito mode.
      * @param tag The tag of the notification. May be NULL.
      * @param webApkPackage The package of the WebAPK associated with the notification. Empty if
-     *        the notification is not associated with a WebAPK.
+*        the notification is not associated with a WebAPK.
      * @param actionIndex The zero-based index of the action button, or -1 if not applicable.
      */
-    private PendingIntent makePendingIntent(String action, String notificationId, String origin,
-            String profileId, boolean incognito, @Nullable String tag, String webApkPackage,
-            int actionIndex) {
+    private PendingIntent makePendingIntent(Context context, String action, String notificationId,
+            String origin, String profileId, boolean incognito, @Nullable String tag,
+            String webApkPackage, int actionIndex) {
         Uri intentData = makeIntentData(notificationId, origin, actionIndex);
         Intent intent = new Intent(action, intentData);
-        intent.setClass(mAppContext, NotificationService.Receiver.class);
+        intent.setClass(context, NotificationService.Receiver.class);
 
         intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_ID, notificationId);
         intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ORIGIN, origin);
@@ -340,8 +339,8 @@
                 NotificationConstants.EXTRA_NOTIFICATION_INFO_WEBAPK_PACKAGE, webApkPackage);
         intent.putExtra(NotificationConstants.EXTRA_NOTIFICATION_INFO_ACTION_INDEX, actionIndex);
 
-        return PendingIntent.getBroadcast(mAppContext, PENDING_INTENT_REQUEST_CODE, intent,
-                PendingIntent.FLAG_UPDATE_CURRENT);
+        return PendingIntent.getBroadcast(
+                context, PENDING_INTENT_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
     }
 
     /**
@@ -482,42 +481,43 @@
      *                 notification is replacing another notification.
      * @param silent Whether the default sound, vibration and lights should be suppressed.
      * @param actions Action buttons to display alongside the notification.
-     * @see https://developer.android.com/reference/android/app/Notification.html
+     * @see <a href="https://developer.android.com/reference/android/app/Notification.html">
+     *     Android Notification API</a>
      */
     @CalledByNative
     private void displayNotification(String notificationId, String origin, String profileId,
             boolean incognito, String tag, String webApkPackage, String title, String body,
             Bitmap image, Bitmap icon, Bitmap badge, int[] vibrationPattern, long timestamp,
             boolean renotify, boolean silent, ActionInfo[] actions) {
-        Resources res = mAppContext.getResources();
+        Context context = ContextUtils.getApplicationContext();
+        Resources res = context.getResources();
 
         // Record whether it's known whether notifications can be shown to the user at all.
-        RecordHistogram.recordEnumeratedHistogram(
-                "Notifications.AppNotificationStatus",
-                NotificationSystemStatusUtil.determineAppNotificationStatus(mAppContext),
+        RecordHistogram.recordEnumeratedHistogram("Notifications.AppNotificationStatus",
+                NotificationSystemStatusUtil.determineAppNotificationStatus(context),
                 NotificationSystemStatusUtil.APP_NOTIFICATIONS_STATUS_BOUNDARY);
 
         // Set up a pending intent for going to the settings screen for |origin|.
         Intent settingsIntent = PreferencesLauncher.createIntentForSettingsPage(
-                mAppContext, SingleWebsitePreferences.class.getName());
+                context, SingleWebsitePreferences.class.getName());
         settingsIntent.setData(makeIntentData(notificationId, origin, -1 /* actionIndex */));
         settingsIntent.putExtra(Preferences.EXTRA_SHOW_FRAGMENT_ARGUMENTS,
                 SingleWebsitePreferences.createFragmentArgsForSite(origin));
 
-        PendingIntent pendingSettingsIntent = PendingIntent.getActivity(mAppContext,
+        PendingIntent pendingSettingsIntent = PendingIntent.getActivity(context,
                 PENDING_INTENT_REQUEST_CODE, settingsIntent, PendingIntent.FLAG_UPDATE_CURRENT);
 
-        PendingIntent clickIntent =
-                makePendingIntent(NotificationConstants.ACTION_CLICK_NOTIFICATION, notificationId,
-                        origin, profileId, incognito, tag, webApkPackage, -1 /* actionIndex */);
-        PendingIntent closeIntent =
-                makePendingIntent(NotificationConstants.ACTION_CLOSE_NOTIFICATION, notificationId,
-                        origin, profileId, incognito, tag, webApkPackage, -1 /* actionIndex */);
+        PendingIntent clickIntent = makePendingIntent(context,
+                NotificationConstants.ACTION_CLICK_NOTIFICATION, notificationId, origin, profileId,
+                incognito, tag, webApkPackage, -1 /* actionIndex */);
+        PendingIntent closeIntent = makePendingIntent(context,
+                NotificationConstants.ACTION_CLOSE_NOTIFICATION, notificationId, origin, profileId,
+                incognito, tag, webApkPackage, -1 /* actionIndex */);
 
         boolean hasImage = image != null;
 
         NotificationBuilderBase notificationBuilder =
-                createNotificationBuilder(hasImage)
+                createNotificationBuilder(context, hasImage)
                         .setTitle(title)
                         .setBody(body)
                         .setImage(image)
@@ -533,7 +533,7 @@
                                 origin, false /* showScheme */));
 
         for (int actionIndex = 0; actionIndex < actions.length; actionIndex++) {
-            PendingIntent intent = makePendingIntent(
+            PendingIntent intent = makePendingIntent(context,
                     NotificationConstants.ACTION_CLICK_NOTIFICATION, notificationId, origin,
                     profileId, incognito, tag, webApkPackage, actionIndex);
             ActionInfo action = actions[actionIndex];
@@ -581,11 +581,11 @@
         }
     }
 
-    private NotificationBuilderBase createNotificationBuilder(boolean hasImage) {
+    private NotificationBuilderBase createNotificationBuilder(Context context, boolean hasImage) {
         if (useCustomLayouts(hasImage)) {
-            return new CustomNotificationBuilder(mAppContext);
+            return new CustomNotificationBuilder(context);
         }
-        return new StandardNotificationBuilder(mAppContext);
+        return new StandardNotificationBuilder(context);
     }
 
     /**
@@ -686,7 +686,7 @@
      * @param tag The tag of the notification. May be NULL.
      * @param webApkPackage The package of the WebAPK associated with the notification.
      *        Empty if the notification is not associated with a WebAPK.
-     * @param actionIndex
+     * @param actionIndex The index of the action button that was clicked, or -1 if not applicable.
      * @param reply User reply to a text action on the notification. Null if the user did not click
      *              on a text action or if inline replies are not supported.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java
index 79910e58..8a290a9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java
@@ -17,7 +17,6 @@
 import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.ui.base.WindowAndroid.OnCloseContextMenuListener;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 
@@ -43,9 +42,10 @@
     public static final int ID_SAVE_FOR_OFFLINE = 3;
     public static final int ID_REMOVE = 4;
 
+    private final Activity mActivity;
     private final NewTabPageManager mManager;
-    private final Tab mTab;
     private final TouchDisableableView mOuterView;
+    private boolean mContextMenuOpen;
 
     /** Defines callback to configure the context menu and respond to user interaction. */
     public interface Delegate {
@@ -65,10 +65,10 @@
     /** Interface for a view that can be set to stop responding to touches. */
     public interface TouchDisableableView { void setTouchEnabled(boolean enabled); }
 
-    public ContextMenuManager(
-            NewTabPageManager newTabPageManager, Tab tab, TouchDisableableView outerView) {
+    public ContextMenuManager(Activity activity, NewTabPageManager newTabPageManager,
+            TouchDisableableView outerView) {
+        mActivity = activity;
         mManager = newTabPageManager;
-        mTab = tab;
         mOuterView = outerView;
     }
 
@@ -111,22 +111,19 @@
         // or swiping to dismiss an item (eg. https://crbug.com/638854, https://crbug.com/638555,
         // https://crbug.com/636296)
         mOuterView.setTouchEnabled(false);
-
-        mTab.getWindowAndroid().addContextMenuCloseListener(this);
+        mContextMenuOpen = true;
     }
 
     @Override
     public void onContextMenuClosed() {
+        if (!mContextMenuOpen) return;
         mOuterView.setTouchEnabled(true);
-        mTab.getWindowAndroid().removeContextMenuCloseListener(this);
+        mContextMenuOpen = false;
     }
 
     /** Closes the context menu, if open. */
     public void closeContextMenu() {
-        Activity activity = mTab.getWindowAndroid().getActivity().get();
-        if (activity == null) return;
-
-        activity.closeContextMenu();
+        mActivity.closeContextMenu();
     }
 
     private boolean shouldShowItem(@ContextMenuItemId int itemId, Delegate delegate) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index d9607fa..1d5a8082 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -254,7 +254,8 @@
 
         private void recordOpenedMostVisitedItem(MostVisitedItem item) {
             if (mIsDestroyed) return;
-            NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_MOST_VISITED_ENTRY);
+            NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_MOST_VISITED_TILE);
+            RecordUserAction.record("MobileNTPMostVisited");
             NewTabPageUma.recordExplicitUserNavigation(
                     item.getUrl(), NewTabPageUma.RAPPOR_ACTION_VISITED_SUGGESTED_TILE);
             RecordHistogram.recordMediumTimesHistogram("NewTabPage.MostVisitedTime",
@@ -349,6 +350,22 @@
         @Override
         public void trackSnippetCategoryActionClick(int category, int position) {
             mSnippetsBridge.onMoreButtonClicked(category, position);
+            switch (category) {
+                case KnownCategories.BOOKMARKS:
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARKS_MANAGER);
+                    break;
+                // MORE button in both categories leads to the recent tabs manager
+                case KnownCategories.FOREIGN_TABS:
+                case KnownCategories.RECENT_TABS:
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_RECENT_TABS_MANAGER);
+                    break;
+                case KnownCategories.DOWNLOADS:
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_DOWNLOADS_MANAGER);
+                    break;
+                default:
+                    // No action associated
+                    break;
+            }
         }
 
         @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java
index 96ef6e50..f468200 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageUma.java
@@ -26,7 +26,7 @@
 
 /**
  * Records UMA stats for which actions the user takes on the NTP in the
- * "NewTabPage.ActionAndroid" histogram.
+ * "NewTabPage.ActionAndroid2" histogram.
  */
 public final class NewTabPageUma {
     private NewTabPageUma() {}
@@ -40,16 +40,18 @@
     private static final int ACTION_NAVIGATED_TO_GOOGLE_HOMEPAGE = 1;
     // User navigated to any other page using the omnibox
     private static final int ACTION_NAVIGATED_USING_OMNIBOX = 2;
-    // User opened a most visited page
-    public static final int ACTION_OPENED_MOST_VISITED_ENTRY = 3;
-    // User opened a recently closed tab
-    public static final int ACTION_OPENED_RECENTLY_CLOSED_ENTRY = 4;
-    // User opened a bookmark
-    public static final int ACTION_OPENED_BOOKMARK = 5;
-    // User opened a foreign session (from recent tabs section)
-    public static final int ACTION_OPENED_FOREIGN_SESSION = 6;
+    // User opened a most visited tile
+    public static final int ACTION_OPENED_MOST_VISITED_TILE = 3;
+    // User opened the recent tabs manager
+    public static final int ACTION_OPENED_RECENT_TABS_MANAGER = 4;
+    // User opened the history manager
+    public static final int ACTION_OPENED_HISTORY_MANAGER = 5;
+    // User opened the bookmarks manager
+    public static final int ACTION_OPENED_BOOKMARKS_MANAGER = 6;
+    // User opened the downloads manager
+    public static final int ACTION_OPENED_DOWNLOADS_MANAGER = 7;
     // User navigated to the webpage for a snippet shown on the NTP.
-    public static final int ACTION_OPENED_SNIPPET = 7;
+    public static final int ACTION_OPENED_SNIPPET = 8;
     // User clicked on the "learn more" link in the footer.
     public static final int ACTION_CLICKED_LEARN_MORE = 9;
     // User clicked on the "Refresh" button in the "all dismissed" state.
@@ -109,24 +111,7 @@
     public static void recordAction(int action) {
         assert action >= 0;
         assert action < NUM_ACTIONS;
-        switch (action) {
-            case ACTION_OPENED_MOST_VISITED_ENTRY:
-                RecordUserAction.record("MobileNTPMostVisited");
-                break;
-            case ACTION_OPENED_RECENTLY_CLOSED_ENTRY:
-                RecordUserAction.record("MobileNTPRecentlyClosed");
-                break;
-            case ACTION_OPENED_BOOKMARK:
-                RecordUserAction.record("MobileNTPBookmark");
-                break;
-            case ACTION_OPENED_FOREIGN_SESSION:
-                RecordUserAction.record("MobileNTPForeignSession");
-                break;
-            default:
-                // No UMA action associated with this type.
-                break;
-        }
-        RecordHistogram.recordEnumeratedHistogram("NewTabPage.ActionAndroid", action, NUM_ACTIONS);
+        RecordHistogram.recordEnumeratedHistogram("NewTabPage.ActionAndroid2", action, NUM_ACTIONS);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 8412e5c9..78ff652 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -361,8 +361,15 @@
             mScrollView.enableBottomShadow(SHADOW_COLOR);
             mNewTabPageLayout = (NewTabPageLayout) findViewById(R.id.ntp_content);
         }
-        mContextMenuManager =
-                new ContextMenuManager(mManager, tab, mUseCardsUi ? mRecyclerView : mScrollView);
+        mContextMenuManager = new ContextMenuManager(mActivity, mManager,
+                mUseCardsUi ? mRecyclerView : mScrollView);
+        mActivity.getWindowAndroid().addContextMenuCloseListener(mContextMenuManager);
+        manager.addDestructionObserver(new DestructionObserver() {
+            @Override
+            public void onDestroy() {
+                mActivity.getWindowAndroid().removeContextMenuCloseListener(mContextMenuManager);
+            }
+        });
 
         mMostVisitedDesign = new MostVisitedDesign(getContext());
         mMostVisitedLayout =
@@ -499,12 +506,14 @@
             toolbar.getRecentTabsButton().setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_RECENT_TABS_MANAGER);
                     mManager.navigateToRecentTabs();
                 }
             });
             toolbar.getBookmarksButton().setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
+                    NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_BOOKMARKS_MANAGER);
                     mManager.navigateToBookmarks();
                 }
             });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
index e8fe642..d2fc46f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
@@ -11,6 +11,7 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
@@ -180,7 +181,7 @@
     public void openForeignSessionTab(ForeignSession session, ForeignSessionTab tab,
             int windowDisposition) {
         if (mIsDestroyed) return;
-        NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_FOREIGN_SESSION);
+        RecordUserAction.record("MobileRecentTabManagerTabFromOtherDeviceOpened");
         mForeignSessionHelper.openForeignSessionTab(mTab, session, tab, windowDisposition);
     }
 
@@ -193,7 +194,7 @@
      */
     public void openRecentlyClosedTab(RecentlyClosedTab tab, int windowDisposition) {
         if (mIsDestroyed) return;
-        NewTabPageUma.recordAction(NewTabPageUma.ACTION_OPENED_RECENTLY_CLOSED_ENTRY);
+        RecordUserAction.record("MobileRecentTabManagerRecentTabOpened");
         mRecentlyClosedTabManager.openRecentlyClosedTab(mTab, tab, windowDisposition);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 4d748070..3299b34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.ntp.cards;
 
+import android.support.annotation.Nullable;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.Adapter;
 import android.support.v7.widget.RecyclerView.ViewHolder;
@@ -27,32 +28,34 @@
  */
 public class NewTabPageAdapter extends Adapter<NewTabPageViewHolder> implements NodeParent {
     private final NewTabPageManager mNewTabPageManager;
+    @Nullable
     private final View mAboveTheFoldView;
     private final UiConfig mUiConfig;
     private NewTabPageRecyclerView mRecyclerView;
 
     private final InnerNode mRoot;
 
-    private final AboveTheFoldItem mAboveTheFold = new AboveTheFoldItem();
+    @Nullable
+    private final AboveTheFoldItem mAboveTheFold;
     private final SectionList mSections;
     private final SignInPromo mSigninPromo;
     private final AllDismissedItem mAllDismissed;
     private final Footer mFooter;
-    private final SpacingItem mBottomSpacer = new SpacingItem();
+    private final SpacingItem mBottomSpacer;
 
     /**
      * Creates the adapter that will manage all the cards to display on the NTP.
      *
      * @param manager the NewTabPageManager to use to interact with the rest of the system.
      * @param aboveTheFoldView the layout encapsulating all the above-the-fold elements
-     *                         (logo, search box, most visited tiles)
+     *         (logo, search box, most visited tiles), or null if only suggestions should
+     *         be displayed.
      * @param uiConfig the NTP UI configuration, to be passed to created views.
      * @param offlinePageBridge the OfflinePageBridge used to determine if articles are available
-     *                              offline.
-     *
+     *         offline.
      */
-    public NewTabPageAdapter(NewTabPageManager manager, View aboveTheFoldView, UiConfig uiConfig,
-            OfflinePageBridge offlinePageBridge) {
+    public NewTabPageAdapter(NewTabPageManager manager, @Nullable View aboveTheFoldView,
+            UiConfig uiConfig, OfflinePageBridge offlinePageBridge) {
         mNewTabPageManager = manager;
         mAboveTheFoldView = aboveTheFoldView;
         mUiConfig = uiConfig;
@@ -63,8 +66,19 @@
         mAllDismissed = new AllDismissedItem();
         mFooter = new Footer();
 
-        mRoot.addChildren(
-                mAboveTheFold, mSections, mSigninPromo, mAllDismissed, mFooter, mBottomSpacer);
+        if (mAboveTheFoldView == null) {
+            mAboveTheFold = null;
+        } else {
+            mAboveTheFold = new AboveTheFoldItem();
+            mRoot.addChild(mAboveTheFold);
+        }
+        mRoot.addChildren(mSections, mSigninPromo, mAllDismissed, mFooter);
+        if (mAboveTheFoldView == null) {
+            mBottomSpacer = null;
+        } else {
+            mBottomSpacer = new SpacingItem();
+            mRoot.addChild(mBottomSpacer);
+        }
 
         updateAllDismissedVisibility();
         mRoot.setParent(this);
@@ -127,6 +141,8 @@
     }
 
     public int getAboveTheFoldPosition() {
+        if (mAboveTheFoldView == null) return RecyclerView.NO_POSITION;
+
         return getChildPositionOffset(mAboveTheFold);
     }
 
@@ -146,6 +162,8 @@
     }
 
     int getBottomSpacerPosition() {
+        if (mBottomSpacer == null) return RecyclerView.NO_POSITION;
+
         return getChildPositionOffset(mBottomSpacer);
     }
 
@@ -165,7 +183,7 @@
     public void onItemRangeInserted(TreeNode child, int itemPosition, int itemCount) {
         assert child == mRoot;
         notifyItemRangeInserted(itemPosition, itemCount);
-        mBottomSpacer.refresh();
+        if (mBottomSpacer != null) mBottomSpacer.refresh();
 
         updateAllDismissedVisibility();
     }
@@ -174,7 +192,7 @@
     public void onItemRangeRemoved(TreeNode child, int itemPosition, int itemCount) {
         assert child == mRoot;
         notifyItemRangeRemoved(itemPosition, itemCount);
-        mBottomSpacer.refresh();
+        if (mBottomSpacer != null) mBottomSpacer.refresh();
 
         updateAllDismissedVisibility();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java
new file mode 100644
index 0000000..3f356975
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java
@@ -0,0 +1,202 @@
+// 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.
+
+package org.chromium.chrome.browser.suggestions;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+
+import org.chromium.base.Callback;
+import org.chromium.base.ObserverList;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.SynchronousInitializationActivity;
+import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
+import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
+import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
+import org.chromium.chrome.browser.ntp.ContextMenuManager;
+import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver;
+import org.chromium.chrome.browser.ntp.MostVisitedItem;
+import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
+import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
+import org.chromium.chrome.browser.ntp.UiConfig;
+import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
+import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
+import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
+import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObserver;
+import org.chromium.chrome.browser.profiles.Profile;
+
+import java.util.Set;
+
+/**
+ * Experimental activity to show content suggestions outside of the New Tab Page.
+ */
+public class ContentSuggestionsActivity extends SynchronousInitializationActivity {
+    private final ObserverList<DestructionObserver> mDestructionObservers = new ObserverList<>();
+
+    private ContextMenuManager mContextMenuManager;
+    private SnippetsBridge mSnippetsBridge;
+    private NewTabPageRecyclerView mRecyclerView;
+
+    public static void launch(Context context) {
+        Intent intent = new Intent();
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setClass(context, ContentSuggestionsActivity.class);
+        context.startActivity(intent);
+    }
+
+    private class SuggestionsNewTabPageManager implements NewTabPageManager {
+        @Override
+        public void removeMostVisitedItem(MostVisitedItem item) {}
+
+        @Override
+        public void openMostVisitedItem(int windowDisposition, MostVisitedItem item) {}
+
+        @Override
+        public boolean isLocationBarShownInNTP() {
+            return false;
+        }
+
+        @Override
+        public boolean isVoiceSearchEnabled() {
+            return false;
+        }
+
+        @Override
+        public boolean isFakeOmniboxTextEnabledTablet() {
+            return false;
+        }
+
+        @Override
+        public boolean isOpenInNewWindowEnabled() {
+            return true;
+        }
+
+        @Override
+        public boolean isOpenInIncognitoEnabled() {
+            return true;
+        }
+
+        @Override
+        public void navigateToBookmarks() {}
+
+        @Override
+        public void navigateToRecentTabs() {}
+
+        @Override
+        public void navigateToDownloadManager() {}
+
+        @Override
+        public void trackSnippetsPageImpression(int[] categories, int[] suggestionsPerCategory) {}
+
+        @Override
+        public void trackSnippetImpression(SnippetArticle article) {}
+
+        @Override
+        public void trackSnippetMenuOpened(SnippetArticle article) {}
+
+        @Override
+        public void trackSnippetCategoryActionImpression(int category, int position) {}
+
+        @Override
+        public void trackSnippetCategoryActionClick(int category, int position) {}
+
+        @Override
+        public void openSnippet(int windowOpenDisposition, SnippetArticle article) {}
+
+        @Override
+        public void focusSearchBox(boolean beginVoiceSearch, String pastedText) {}
+
+        @Override
+        public void setMostVisitedURLsObserver(MostVisitedURLsObserver observer, int numResults) {}
+
+        @Override
+        public void getLocalFaviconImageForURL(
+                String url, int size, FaviconImageCallback faviconCallback) {}
+
+        @Override
+        public void getLargeIconForUrl(String url, int size, LargeIconCallback callback) {}
+
+        @Override
+        public void ensureIconIsAvailable(String pageUrl, String iconUrl, boolean isLargeIcon,
+                boolean isTemporary, IconAvailabilityCallback callback) {}
+
+        @Override
+        public void getUrlsAvailableOffline(Set<String> pageUrls, Callback<Set<String>> callback) {}
+
+        @Override
+        public void onLogoClicked(boolean isAnimatedLogoShowing) {}
+
+        @Override
+        public void getSearchProviderLogo(LogoObserver logoObserver) {}
+
+        @Override
+        public void onLoadingComplete(MostVisitedItem[] mostVisitedItems) {}
+
+        @Override
+        public void onLearnMoreClicked() {}
+
+        @Override
+        public SuggestionsSource getSuggestionsSource() {
+            return mSnippetsBridge;
+        }
+
+        @Override
+        public void addDestructionObserver(DestructionObserver destructionObserver) {
+            mDestructionObservers.addObserver(destructionObserver);
+        }
+
+        @Override
+        public boolean isCurrentPage() {
+            return true;
+        }
+
+        @Override
+        public ContextMenuManager getContextMenuManager() {
+            return mContextMenuManager;
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        assert ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_SUGGESTIONS_STANDALONE_UI);
+
+        mRecyclerView = (NewTabPageRecyclerView) LayoutInflater.from(this).inflate(
+                R.layout.new_tab_page_recycler_view, null, false);
+
+        Profile profile = Profile.getLastUsedProfile();
+        mSnippetsBridge = new SnippetsBridge(profile);
+
+        NewTabPageManager manager = new SuggestionsNewTabPageManager();
+        mContextMenuManager = new ContextMenuManager(this, manager, mRecyclerView);
+        UiConfig uiConfig = new UiConfig(mRecyclerView);
+        NewTabPageAdapter adapter = new NewTabPageAdapter(
+                manager, null, uiConfig, OfflinePageBridge.getForProfile(profile));
+        mRecyclerView.setAdapter(adapter);
+        mRecyclerView.setUpSwipeToDismiss();
+
+        setContentView(mRecyclerView);
+    }
+
+    @Override
+    public void onContextMenuClosed(Menu menu) {
+        mContextMenuManager.onContextMenuClosed();
+    }
+
+    @Override
+    protected void onDestroy() {
+        for (DestructionObserver observer : mDestructionObservers) {
+            observer.onDestroy();
+        }
+        super.onDestroy();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/OWNERS b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/OWNERS
new file mode 100644
index 0000000..c1e9864a9
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/OWNERS
@@ -0,0 +1 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
\ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 975b6300..22a428b 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -924,6 +924,7 @@
   "java/src/org/chromium/chrome/browser/snackbar/smartlockautosignin/AutoSigninSnackbarController.java",
   "java/src/org/chromium/chrome/browser/snackbar/undo/UndoBarController.java",
   "java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java",
+  "java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java",
   "java/src/org/chromium/chrome/browser/superviseduser/SupervisedUserContentProvider.java",
   "java/src/org/chromium/chrome/browser/sync/GmsCoreSyncListener.java",
   "java/src/org/chromium/chrome/browser/sync/GoogleServiceAuthError.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 23d2319d..4c37b57 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -210,7 +210,8 @@
      */
     private class MockNewTabPageManager implements NewTabPageManager {
         // TODO(dgn): provide a RecyclerView if we need to test the context menu.
-        private ContextMenuManager mContextMenuManager = new ContextMenuManager(this, null, null);
+        private ContextMenuManager mContextMenuManager =
+                new ContextMenuManager(getActivity(), this, null);
 
         @Override
         public void getLocalFaviconImageForURL(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
index 1c6045e..2dc0f2a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestBase.java
@@ -124,7 +124,7 @@
         mViewCoreRef = new AtomicReference<>();
         mWebContentsRef = new AtomicReference<>();
         mTestFilePath = UrlUtils.getIsolatedTestFilePath(
-                String.format("chrome/test/data/android/payments/%s", testFileName));
+                String.format("chrome/test/data/payments/%s", testFileName));
     }
 
     @Override
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index f35d98f..36f0bf7f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -29,6 +29,7 @@
 import android.content.res.Resources;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.view.View;
 
 import org.junit.After;
 import org.junit.Before;
@@ -971,7 +972,8 @@
     }
 
     private void reloadNtp() {
-        mAdapter = new NewTabPageAdapter(mNewTabPageManager, null, null, mOfflinePageBridge);
+        mAdapter = new NewTabPageAdapter(mNewTabPageManager, mock(View.class), null,
+                mOfflinePageBridge);
     }
 
     private void assertArticlesEqual(List<SnippetArticle> articles, int start, int end) {
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd
index 0cf119c..1e26e12 100644
--- a/chrome/app/chromium_strings.grd
+++ b/chrome/app/chromium_strings.grd
@@ -152,21 +152,6 @@
         </message>
       </if>
       <if expr="is_win">
-        <message name="IDS_PRODUCT_APP_LAUNCHER_NAME" desc="The Chrome App Launcher application name">
-          Chromium App Launcher
-        </message>
-        <message name="IDS_PRODUCT_BINARIES_NAME" desc="The Chrome Binaries application name">
-          Chromium Binaries
-        </message>
-        <message name="IDS_CHROME_FRAME_TURNDOWN_LEARN_MORE_URL" desc="Link to knowledge-base article about Chromium Frame's turndown">
-          https://support.google.com/chrome/?p=ib_chromeframe
-        </message>
-        <message name="IDS_CHROME_FRAME_TURNDOWN_TEXT_IE_OLDER" desc="Text of Chromium Frame turndown prompt for IE 6, 7, and 8">
-          This site is using the Chromium Frame plugin which will soon be unsupported. Please uninstall it and upgrade to a modern browser.
-        </message>
-        <message name="IDS_CHROME_FRAME_TURNDOWN_TEXT_IE_NEWER" desc="Text of Chromium Frame turndown prompt for IE 9 and 10">
-          This site is using the Chromium Frame plugin that will soon be unsupported. Please uninstall it and download a compatible browser.
-        </message>
         <message name="IDS_SHORTCUT_NEW_WINDOW" desc="The text label of the New window shortcut context menu entry as of Windows 8">
           New window
         </message>
@@ -427,12 +412,6 @@
         <message name="IDS_INSTALL_INSUFFICIENT_RIGHTS" desc="Error displayed when a non admin user tries to attempt system level install/uninstall.">
           You do not have appropriate rights for system-level install. Try running the installer again as Administrator.
         </message>
-        <message name="IDS_INSTALL_NO_PRODUCTS_TO_UPDATE" desc="Error displayed if the installer is not provided one or more products to install/update.">
-          No installation of Chromium found to update.
-        </message>
-        <message name="IDS_INSTALL_MULTI_INSTALLATION_EXISTS" desc="Error during install if a multi-install Chromium is present, thereby preventing the installation of a single-install Chromium.">
-          A conflicting installation of Chromium was found on the system. Please uninstall it and try again.
-        </message>
         <message name="IDS_INSTALL_EXISTING_VERSION_LAUNCHED" desc="A message shown to users who try to install Chrome in their user profile directory when their computer already has Chrome installed for all users. In this case, the installer silently launches the existing version of Chrome for all users rather than installing a second version of Chrome.">
           Chromium is already installed for all users on your computer.
         </message>
diff --git a/chrome/app/google_chrome_strings.grd b/chrome/app/google_chrome_strings.grd
index 0fc87a3..6852821 100644
--- a/chrome/app/google_chrome_strings.grd
+++ b/chrome/app/google_chrome_strings.grd
@@ -154,21 +154,6 @@
         </message>
       </if>
       <if expr="is_win">
-        <message name="IDS_PRODUCT_APP_LAUNCHER_NAME" desc="The Chrome App Launcher application name">
-          Google Chrome App Launcher
-        </message>
-        <message name="IDS_PRODUCT_BINARIES_NAME" desc="The Chrome Binaries application name">
-          Google Chrome Binaries
-        </message>
-        <message name="IDS_CHROME_FRAME_TURNDOWN_LEARN_MORE_URL" desc="Link to knowledge-base article about Chrome Frame turndown">
-          https://support.google.com/chrome/?p=ib_chromeframe
-        </message>
-        <message name="IDS_CHROME_FRAME_TURNDOWN_TEXT_IE_OLDER" desc="Text of Chrome Frame turndown prompt for IE 6, 7, and 8">
-          This site is using the retired Chrome Frame plugin which no longer receives security and stability updates. Please uninstall it and upgrade to a modern browser.
-        </message>
-        <message name="IDS_CHROME_FRAME_TURNDOWN_TEXT_IE_NEWER" desc="Text of Chrome Frame turndown prompt for IE 9 and 10">
-          This site is using the retired Chrome Frame plugin which no longer receives security and stability updates. Please uninstall it and upgrade to a modern browser.
-        </message>
         <message name="IDS_SHORTCUT_NEW_WINDOW" desc="The text label of the New window shortcut context menu entry as of Windows 8">
           New window
         </message>
@@ -428,12 +413,6 @@
         <message name="IDS_INSTALL_INSUFFICIENT_RIGHTS" desc="Error displayed when a non admin user tries to attempt system level install/uninstall.">
           You do not have appropriate rights for system-level install. Try running the installer again as Administrator.
         </message>
-        <message name="IDS_INSTALL_NO_PRODUCTS_TO_UPDATE" desc="Error displayed if the installer is not provided one or more products to install/update.">
-          No installation of Google Chrome found to update.
-        </message>
-        <message name="IDS_INSTALL_MULTI_INSTALLATION_EXISTS" desc="Error during install if a multi-install Google Chrome is present, thereby preventing the installation of a single-install Google Chrome.">
-          A conflicting installation of Google Chrome was found on the system. Please uninstall it and try again.
-        </message>
         <message name="IDS_INSTALL_EXISTING_VERSION_LAUNCHED" desc="A message shown to users who try to install Chrome in their user profile directory when their computer already has Chrome installed for all users. In this case, the installer silently launches the existing version of Chrome for all users rather than installing a second version of Chrome.">
           Google Chrome is already installed for all users on your computer.
         </message>
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index e5f2b079..1f1cfb3 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -53,6 +53,7 @@
     &kNoCreditCardAbort,
     &kNTPFakeOmniboxTextFeature,
     &kNTPOfflinePagesFeature,
+    &kNTPSuggestionsStandaloneUIFeature,
     &kPhysicalWebFeature,
     &kPhysicalWebIgnoreOtherClientsFeature,
     &kSpecialLocaleFeature,
@@ -121,6 +122,9 @@
 const base::Feature kNTPOfflinePagesFeature{"NTPOfflinePages",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kNTPSuggestionsStandaloneUIFeature{
+    "NTPSuggestionsStandaloneUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kPhysicalWebFeature{"PhysicalWeb",
                                         base::FEATURE_ENABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index 085e61a..e97b7df 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -28,6 +28,7 @@
 extern const base::Feature kNoCreditCardAbort;
 extern const base::Feature kNTPFakeOmniboxTextFeature;
 extern const base::Feature kNTPOfflinePagesFeature;
+extern const base::Feature kNTPSuggestionsStandaloneUIFeature;
 extern const base::Feature kPhysicalWebFeature;
 extern const base::Feature kPhysicalWebIgnoreOtherClientsFeature;
 extern const base::Feature kSpecialLocaleFeature;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index d813a2f..5169fb5 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -642,6 +642,8 @@
     "launcher_search_provider/launcher_search_provider_service.h",
     "launcher_search_provider/launcher_search_provider_service_factory.cc",
     "launcher_search_provider/launcher_search_provider_service_factory.h",
+    "libc_close_tracking.cc",
+    "libc_close_tracking.h",
     "locale_change_guard.cc",
     "locale_change_guard.h",
     "login/app_launch_controller.cc",
@@ -1536,6 +1538,7 @@
     "input_method/input_method_manager_impl_unittest.cc",
     "input_method/input_method_persistence_unittest.cc",
     "input_method/input_method_util_unittest.cc",
+    "libc_close_tracking_unittest.cc",
     "locale_change_guard_unittest.cc",
     "login/auth/cryptohome_authenticator_unittest.cc",
     "login/easy_unlock/easy_unlock_challenge_wrapper_unittest.cc",
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 236bc10..2a29666 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -51,6 +51,7 @@
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/input_method/input_method_util.h"
 #include "chrome/browser/chromeos/language_preferences.h"
+#include "chrome/browser/chromeos/libc_close_tracking.h"
 #include "chrome/browser/chromeos/login/helper.h"
 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
 #include "chrome/browser/chromeos/login/login_wizard.h"
@@ -136,6 +137,7 @@
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
 #include "components/user_manager/user_names.h"
+#include "components/version_info/version_info.h"
 #include "components/wallpaper/wallpaper_manager_base.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_service.h"
@@ -361,6 +363,14 @@
   memory_kills_monitor_ = base::MakeUnique<memory::MemoryKillsMonitor::Handle>(
       memory::MemoryKillsMonitor::StartMonitoring());
 
+  // Enable libc close tracking in browser process on unknown/canary channel for
+  // http://crbug.com/660960.
+  // TODO(xiyuan): Remove this.
+  if (chrome::GetChannel() == version_info::Channel::CANARY ||
+      chrome::GetChannel() == version_info::Channel::UNKNOWN) {
+    chromeos::InitCloseTracking();
+  }
+
   ChromeBrowserMainPartsLinux::PreEarlyInitialization();
 }
 
@@ -932,6 +942,8 @@
 
   // Destroy DeviceSettingsService after g_browser_process.
   DeviceSettingsService::Shutdown();
+
+  chromeos::ShutdownCloseTracking();
 }
 
 }  //  namespace chromeos
diff --git a/chrome/browser/chromeos/libc_close_tracking.cc b/chrome/browser/chromeos/libc_close_tracking.cc
new file mode 100644
index 0000000..3c491a2
--- /dev/null
+++ b/chrome/browser/chromeos/libc_close_tracking.cc
@@ -0,0 +1,181 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include <sstream>
+#include <string>
+#include <unordered_map>
+
+#include "base/debug/crash_logging.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "chrome/common/crash_keys.h"
+
+namespace {
+
+// Captures errno on construction and restores it on destruction.
+class ErrnoCapture {
+ public:
+  ErrnoCapture() : captured_errno_(errno) {}
+  ~ErrnoCapture() { errno = captured_errno_; }
+
+  int captured_errno() const { return captured_errno_; }
+
+ private:
+  const int captured_errno_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrnoCapture);
+};
+
+// Tracks per-FD stack traces on successful close() call in the process where
+// it gets created.
+class StackTracker {
+ public:
+  StackTracker() : creation_process_id_(base::GetCurrentProcId()) {}
+  ~StackTracker() = default;
+
+  // Whether the current process should be tracked.
+  bool ShouldTrack() const {
+    return ignore_pid_ || base::GetCurrentProcId() == creation_process_id_;
+  }
+
+  // Stores the stack associated with |fd|.
+  void SetStack(int fd, const base::debug::StackTrace& stack) {
+    base::AutoLock lock(lock_);
+    stacks_[fd] = stack;
+  }
+
+  // Retrieves the stack associated with |fd|. Returns nullptr if no stack
+  // is associated with it.
+  const base::debug::StackTrace* GetStack(int fd) {
+    base::AutoLock lock(lock_);
+
+    auto it = stacks_.find(fd);
+    return it != stacks_.end() ? &(it->second) : nullptr;
+  }
+
+  void set_ignore_pid(bool ignore_pid) { ignore_pid_ = ignore_pid; }
+
+ private:
+  // Process id of the creation process.
+  const base::ProcessId creation_process_id_;
+
+  bool ignore_pid_ = false;
+
+  // Guard access to |stacks_|.
+  base::Lock lock_;
+
+  // Tracks per-FD call stacks of the last successful close() calls.
+  std::unordered_map<int, base::debug::StackTrace> stacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackTracker);
+};
+
+// This could not be a LazyInstance because it is used in CloseOverride called
+// during early process start before base code is initialized and LazyInstance
+// also depends on AtExitManager, which needs to call close() during clean up.
+StackTracker* g_stack_tracker = nullptr;
+
+// Creates a stack string without symbolizing since the code is targeted
+// for debugging release code that has no symbols. StackTrace::ToString()
+// could not be used because it calls close() and CloseOverride currently
+// does not handle recursive close() calls.
+std::string GetStackString(const base::debug::StackTrace& stack) {
+  size_t count = 0;
+  const void* const* addresses = stack.Addresses(&count);
+  if (!count || !addresses)
+    return "<null>";
+
+  std::stringstream stream;
+  for (size_t i = 0; i < count; ++i)
+    stream << base::StringPrintf("%p ", addresses[i]);
+
+  return stream.str();
+}
+
+}  // namespace
+
+extern "C" {
+
+// Implementation of the overridden libc close() call.
+int CloseOverride(int fd) {
+  // Call real close via syscall.
+  const int ret = IGNORE_EINTR(syscall(SYS_close, fd));
+  // Captures errno and restores it later in case it is changed.
+  const ErrnoCapture close_errno;
+
+  // Return if tracking is not enabled for the current process.
+  if (!g_stack_tracker || !g_stack_tracker->ShouldTrack())
+    return ret;
+
+  // Capture stack for successful close.
+  if (ret == 0) {
+#if HAVE_TRACE_STACK_FRAME_POINTERS
+    // Use TraceStackFramePointers because the backtrack() based default
+    // capturing gets only the last stack frame and is not useful.
+    const void* frames[64];
+    const size_t frame_count =
+        base::debug::TraceStackFramePointers(frames, arraysize(frames), 0);
+    g_stack_tracker->SetStack(fd, base::debug::StackTrace(frames, frame_count));
+#else
+    // Use default StackTrace when TraceStackFramePointers is not available.
+    // Hopefully it will capture something useful.
+    g_stack_tracker->SetStack(fd, base::debug::StackTrace());
+#endif
+    return ret;
+  }
+
+  const base::debug::StackTrace* const last_close_stack =
+      g_stack_tracker->GetStack(fd);
+  if (!last_close_stack) {
+    // No previous stack. Return and let existing code to catch it.
+    return ret;
+  }
+
+  // Crash with the stack of the last success close on the fd.
+  base::debug::SetCrashKeyToStackTrace(crash_keys::kLastGoodCloseStack,
+                                       *last_close_stack);
+  LOG(FATAL) << "Failed to close a fd, attach info to http://crbug.com/660960"
+             << ", fd=" << fd << ", errno=" << close_errno.captured_errno()
+             << ", stack=" << GetStackString(*last_close_stack);
+  return ret;
+}
+
+// Export "close" symbol and make it an alias of "CloseOverride" to interpose
+// libc close().
+int close(int fd)
+    __attribute__((alias("CloseOverride"), visibility("default")));
+
+}  // extern "C"
+
+namespace chromeos {
+
+void InitCloseTracking() {
+  DCHECK(!g_stack_tracker);
+  g_stack_tracker = new StackTracker;
+}
+
+void ShutdownCloseTracking() {
+  delete g_stack_tracker;
+  g_stack_tracker = nullptr;
+}
+
+const base::debug::StackTrace* GetLastCloseStackForTest(int fd) {
+  return g_stack_tracker ? g_stack_tracker->GetStack(fd) : nullptr;
+}
+
+void SetCloseTrackingIgnorePidForTest(bool ignore_pid) {
+  DCHECK(g_stack_tracker);
+  g_stack_tracker->set_ignore_pid(ignore_pid);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/libc_close_tracking.h b/chrome/browser/chromeos/libc_close_tracking.h
new file mode 100644
index 0000000..0529391
--- /dev/null
+++ b/chrome/browser/chromeos/libc_close_tracking.h
@@ -0,0 +1,58 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LIBC_CLOSE_TRACKING_H_
+#define CHROME_BROWSER_CHROMEOS_LIBC_CLOSE_TRACKING_H_
+
+// Debugging code for http://crbug.com/660960 where close() fails with EBADF.
+// The primary suspicion is that some piece of code is closing a FD that does
+// not belong to it. Unfortunately the PCHECK in ScopedFDCloseTraits::Free
+// is too late and reports only victim rather than the culprit. Another
+// possibility is memory corruption (or object holding fd released and its
+// memory got over-written). In such case, LOG(FATAL) includes fd and errno
+// and it should help us to identify the case.
+//
+// The code here interposes libc close() calls to track the last good calls
+// on a fd and reports it when libc close() on it fails.
+//
+// Note:
+// 1. The libc close() interposition happens at build time by exporting
+//    "close" symbol and alias it to our CloseOverride function. All close()
+//    calls will be redirected regardless whether stack tracking is enabled
+//    or not.
+// 2. Interposition captures libc close() calls but not direct syscalls.
+//    To capture direct syscalls, ptrace is needed and it needs to run in a
+//    master process with chrome browser process as its debuggee.  This would
+//    need a complicated setup and introduce significant overhead as all close
+//    calls are hooked to the master process to extract stacks etc.  Since
+//    most (all?) chrome code calls libc close() instead of direct syscalls,
+//    the interposition way is a better first step.
+//
+// TODO(xiyuan): Remove after http://crbug.com/660960.
+
+namespace base {
+namespace debug {
+class StackTrace;
+}  // namespace debug
+}  // namespace base
+
+namespace chromeos {
+
+// Enables the stack tracking for the process where InitCloseTracking gets
+// called (this should be the browser process) so that last good close stacks
+// are collected and sent along with crash reports.
+void InitCloseTracking();
+
+// Cleans up and disables the stack tracking for close().
+void ShutdownCloseTracking();
+
+// Gets the last close stack trace for the given fd.
+const base::debug::StackTrace* GetLastCloseStackForTest(int fd);
+
+// Sets the boolean flag to ignore pid check for tracking in test.
+void SetCloseTrackingIgnorePidForTest(bool ignore_pid);
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_LIBC_CLOSE_TRACKING_H_
diff --git a/chrome/browser/chromeos/libc_close_tracking_unittest.cc b/chrome/browser/chromeos/libc_close_tracking_unittest.cc
new file mode 100644
index 0000000..86aa4b6d
--- /dev/null
+++ b/chrome/browser/chromeos/libc_close_tracking_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/libc_close_tracking.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "base/debug/stack_trace.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr char kTestData[] = "test data";
+
+// Helper class to enable close tracking on construction and turns it off
+// on destruction.
+class ScopedCloseTracking {
+ public:
+  ScopedCloseTracking() { chromeos::InitCloseTracking(); }
+  ~ScopedCloseTracking() { chromeos::ShutdownCloseTracking(); }
+};
+
+class CloseTrackingTest : public testing::Test {
+ public:
+  CloseTrackingTest() = default;
+  ~CloseTrackingTest() override = default;
+
+  // testing::Test
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  // Creates a file, writes some data, close it and verifies that the
+  // underlying fd is closed by attempting to write after close.
+  void TestFileClose(base::PlatformFile* out_fd) {
+    base::FilePath file_path = temp_dir_.GetPath().AppendASCII("test_file");
+    base::File file(file_path,
+                    base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_WRITE);
+
+    ASSERT_TRUE(file.IsValid());
+    const base::PlatformFile fd = file.GetPlatformFile();
+    EXPECT_EQ(static_cast<ssize_t>(arraysize(kTestData)),
+              write(fd, kTestData, arraysize(kTestData)));
+    file.Close();
+
+    EXPECT_EQ(-1, write(fd, kTestData, arraysize(kTestData)));
+    EXPECT_EQ(errno, EBADF);
+
+    if (out_fd)
+      *out_fd = fd;
+  }
+
+ private:
+  base::ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(CloseTrackingTest);
+};
+
+// Test that a file can be closed normally with no stack tracking.
+TEST_F(CloseTrackingTest, CloseWithNoTracking) {
+  TestFileClose(nullptr);
+}
+
+// Test that a file can be closed normally with stack tracking and a StackTrace
+// is collected.
+TEST_F(CloseTrackingTest, CloseWithTracking) {
+  ScopedCloseTracking tracking;
+
+  base::PlatformFile fd;
+  TestFileClose(&fd);
+
+  const base::debug::StackTrace* stack = chromeos::GetLastCloseStackForTest(fd);
+  EXPECT_NE(nullptr, stack);
+}
+
+// Test that we crash on bad close with expected error.
+TEST_F(CloseTrackingTest, CrashOn2ndClose) {
+  ScopedCloseTracking tracking;
+
+  base::PlatformFile fd;
+  TestFileClose(&fd);
+
+  const base::debug::StackTrace* stack = chromeos::GetLastCloseStackForTest(fd);
+  EXPECT_NE(nullptr, stack);
+
+  // Disable pid check because death test runs in a forked process and have
+  // a different pid than where InitCloseTracking() is called above.
+  chromeos::SetCloseTrackingIgnorePidForTest(true);
+
+  EXPECT_DEATH_IF_SUPPORTED(close(fd), "Failed to close a fd");
+
+  // Last good close stack on the fd is not changed.
+  const base::debug::StackTrace* stack_after_bad_close =
+      chromeos::GetLastCloseStackForTest(fd);
+  EXPECT_EQ(stack, stack_after_bad_close);
+}
+
+}  // namespace
diff --git a/chrome/browser/chromeos/options/wifi_config_view.cc b/chrome/browser/chromeos/options/wifi_config_view.cc
index 84140764..48ff949 100644
--- a/chrome/browser/chromeos/options/wifi_config_view.cc
+++ b/chrome/browser/chromeos/options/wifi_config_view.cc
@@ -1119,12 +1119,12 @@
             IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE_HIDE));
     passphrase_visible_button_->SetImage(
         views::ImageButton::STATE_NORMAL,
-        *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_NETWORK_SHOW_PASSWORD));
+        ResourceBundle::GetSharedInstance().
+        GetImageSkiaNamed(IDR_NETWORK_SHOW_PASSWORD));
     passphrase_visible_button_->SetImage(
         views::ImageButton::STATE_HOVERED,
-        *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_NETWORK_SHOW_PASSWORD_HOVER));
+        ResourceBundle::GetSharedInstance().
+        GetImageSkiaNamed(IDR_NETWORK_SHOW_PASSWORD_HOVER));
     passphrase_visible_button_->SetToggledImage(
         views::ImageButton::STATE_NORMAL,
         ResourceBundle::GetSharedInstance().
diff --git a/chrome/browser/chromeos/options/wimax_config_view.cc b/chrome/browser/chromeos/options/wimax_config_view.cc
index 92534666..1236787f 100644
--- a/chrome/browser/chromeos/options/wimax_config_view.cc
+++ b/chrome/browser/chromeos/options/wimax_config_view.cc
@@ -280,12 +280,12 @@
             IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PASSPHRASE_HIDE));
     passphrase_visible_button_->SetImage(
         views::ImageButton::STATE_NORMAL,
-        *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_NETWORK_SHOW_PASSWORD));
+        ResourceBundle::GetSharedInstance().
+        GetImageSkiaNamed(IDR_NETWORK_SHOW_PASSWORD));
     passphrase_visible_button_->SetImage(
         views::ImageButton::STATE_HOVERED,
-        *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
-            IDR_NETWORK_SHOW_PASSWORD_HOVER));
+        ResourceBundle::GetSharedInstance().
+        GetImageSkiaNamed(IDR_NETWORK_SHOW_PASSWORD_HOVER));
     passphrase_visible_button_->SetToggledImage(
         views::ImageButton::STATE_NORMAL,
         ResourceBundle::GetSharedInstance().
diff --git a/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc b/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc
index d4bb9fb3..ccf23dd 100644
--- a/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc
+++ b/chrome/browser/payments/payment_request_web_contents_manager_browsertest.cc
@@ -34,7 +34,7 @@
     https_server_.reset(
         new net::EmbeddedTestServer(net::EmbeddedTestServer::TYPE_HTTPS));
     ASSERT_TRUE(https_server_->InitializeAndListen());
-    https_server_->ServeFilesFromSourceDirectory("chrome/test/data");
+    https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments");
     https_server_->StartAcceptingConnections();
   }
 
diff --git a/chrome/browser/payments/site_per_process_payments_browsertest.cc b/chrome/browser/payments/site_per_process_payments_browsertest.cc
index e352968..330c4a3 100644
--- a/chrome/browser/payments/site_per_process_payments_browsertest.cc
+++ b/chrome/browser/payments/site_per_process_payments_browsertest.cc
@@ -44,7 +44,7 @@
     host_resolver()->AddRule("*", "127.0.0.1");
     ASSERT_TRUE(https_server_->InitializeAndListen());
     content::SetupCrossSiteRedirector(https_server_.get());
-    https_server_->ServeFilesFromSourceDirectory("chrome/test/data");
+    https_server_->ServeFilesFromSourceDirectory("chrome/test/data/payments");
     https_server_->StartAcceptingConnections();
   }
 
diff --git a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
index 18990ba..522c0a4 100644
--- a/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
+++ b/chrome/browser/prerender/prerender_nostate_prefetch_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/command_line.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/task_scheduler/post_task.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/history/history_test_utils.h"
@@ -20,6 +21,8 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/result_codes.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "net/base/escape.h"
@@ -49,6 +52,7 @@
     "prerender/prefetch_response_csp.html";
 const char kPrefetchScript[] = "prerender/prefetch.js";
 const char kPrefetchScript2[] = "prerender/prefetch2.js";
+const char kServiceWorkerLoader[] = "prerender/service_worker.html";
 const char kPrefetchSubresourceRedirectPage[] =
     "prerender/prefetch_subresource_redirect.html";
 
@@ -558,4 +562,44 @@
   script_counter.WaitForCount(1);
 }
 
+// Checks that a registered ServiceWorker (SW) that is not currently running
+// will intercepts a prefetch request.
+IN_PROC_BROWSER_TEST_F(NoStatePrefetchBrowserTest, ServiceWorkerIntercept) {
+  // Register and launch a SW.
+  base::string16 expected_title = base::ASCIIToUTF16("SW READY");
+  content::TitleWatcher title_watcher(GetActiveWebContents(), expected_title);
+  ui_test_utils::NavigateToURL(
+      current_browser(),
+      src_server()->GetURL(MakeAbsolute(kServiceWorkerLoader)));
+  EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
+
+  // Stop any SW, killing the render process in order to test that the
+  // lightweight renderer created for NoState prefetch does not interfere with
+  // SW startup.
+  int host_count = 0;
+  for (content::RenderProcessHost::iterator iter(
+           content::RenderProcessHost::AllHostsIterator());
+       !iter.IsAtEnd(); iter.Advance()) {
+    ++host_count;
+    iter.GetCurrentValue()->Shutdown(content::RESULT_CODE_KILLED,
+                                     true /* wait */);
+  }
+  // There should be at most one render_process_host, that created for the SW.
+  EXPECT_EQ(1, host_count);
+
+  // Open a new tab to replace the one closed with all the RenderProcessHosts.
+  ui_test_utils::NavigateToURLWithDisposition(
+      current_browser(), GURL(url::kAboutBlankURL),
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  // The SW intercepts kPrefetchPage and replaces it with a body that contains
+  // an <img> tage for kPrefetchPng. This verifies that the SW ran correctly by
+  // observing the fetch of the image.
+  RequestCounter image_counter;
+  CountRequestFor(kPrefetchPng, &image_counter);
+  PrefetchFromFile(kPrefetchPage, FINAL_STATUS_NOSTATE_PREFETCH_FINISHED);
+  image_counter.WaitForCount(1);
+}
+
 }  // namespace prerender
diff --git a/chrome/browser/resources/settings/internet_page/network_summary.js b/chrome/browser/resources/settings/internet_page/network_summary.js
index 1a1ae37..d2950a3 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary.js
@@ -387,6 +387,11 @@
       if (!device)
         continue;
       let state = activeNetworkStatesByType.get(type) || {GUID: '', Type: type};
+      if (state.Source === undefined &&
+          device.State == chrome.networkingPrivate.DeviceStateType.PROHIBITED) {
+        // Prohibited technologies are enforced by the device policy.
+        state.Source = CrOnc.Source.DEVICE_POLICY;
+      }
       newActiveNetworkStates.push(state);
       this.activeNetworkIds_.add(state.GUID);
     }
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chrome/browser/resources/settings/internet_page/network_summary_item.html
index 5616c42c..ce221d4 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -83,10 +83,11 @@
         </template>
       </div>
 
-      <template is="dom-if" if="[[enableIsVisible_(deviceState)]]">
+      <template is="dom-if" if="[[enableToggleIsVisible_(deviceState)]]">
         <div class="secondary-action">
           <paper-toggle-button  id="deviceEnabledButton"
               checked="[[deviceIsEnabled_(deviceState)]]"
+              enabled="[[enableToggleIsEnabled_(deviceState)]]"
               on-tap="onDeviceEnabledTap_">
           </paper-toggle-button>
         </div>
diff --git a/chrome/browser/resources/settings/internet_page/network_summary_item.js b/chrome/browser/resources/settings/internet_page/network_summary_item.js
index a9e06d3..a1d7a55 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.js
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.js
@@ -181,12 +181,23 @@
   },
 
   /**
+   * @param {!DeviceStateProperties} deviceState
    * @return {boolean}
    * @private
    */
-  enableIsVisible_: function() {
-    return this.deviceState.Type != CrOnc.Type.ETHERNET &&
-        this.deviceState.Type != CrOnc.Type.VPN;
+  enableToggleIsVisible_: function(deviceState) {
+    return deviceState.Type != CrOnc.Type.ETHERNET &&
+        deviceState.Type != CrOnc.Type.VPN;
+  },
+
+  /**
+   * @param {!DeviceStateProperties} deviceState
+   * @return {boolean}
+   * @private
+   */
+  enableToggleIsEnabled_: function(deviceState) {
+    return deviceState.State !=
+        chrome.networkingPrivate.DeviceStateType.PROHIBITED;
   },
 
   /**
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc
index cf28ba99..5c9bde96 100644
--- a/chrome/browser/ssl/security_state_tab_helper.cc
+++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -201,16 +201,5 @@
   // information is still being initialized, thus no need to check for that.
   state->malicious_content_status = GetMaliciousContentStatus();
 
-  // If the chain contains SHA1, populate the display policy field.
-  // In M56, we want to display a Neutral security state if the SHA1
-  // certificate was not blocked because the kCertEnableSha1LocalAnchors
-  // policy has been set.
-  // TODO(elawrence): remove this in M57, https://crbug.com/676826
-  if (state->cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT) {
-    state->display_sha1_from_local_anchors_as_neutral =
-        g_browser_process->local_state()->GetBoolean(
-            ssl_config::prefs::kCertEnableSha1LocalAnchors);
-  }
-
   return state;
 }
diff --git a/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc b/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
index e503b432..cf2101d 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browser_tests.cc
@@ -205,7 +205,7 @@
 void CheckSecurityInfoForSecure(
     content::WebContents* contents,
     security_state::SecurityLevel expect_security_level,
-    security_state::SHA1DeprecationStatus expect_sha1_status,
+    bool expect_sha1_in_chain,
     security_state::ContentStatus expect_mixed_content_status,
     bool pkp_bypassed,
     bool expect_cert_error) {
@@ -217,7 +217,7 @@
   security_state::SecurityInfo security_info;
   helper->GetSecurityInfo(&security_info);
   EXPECT_EQ(expect_security_level, security_info.security_level);
-  EXPECT_EQ(expect_sha1_status, security_info.sha1_deprecation_status);
+  EXPECT_EQ(expect_sha1_in_chain, security_info.sha1_in_chain);
   EXPECT_EQ(expect_mixed_content_status, security_info.mixed_content_status);
   EXPECT_TRUE(security_info.sct_verify_statuses.empty());
   EXPECT_TRUE(security_info.scheme_is_cryptographic);
@@ -237,8 +237,7 @@
   security_state::SecurityInfo security_info;
   helper->GetSecurityInfo(&security_info);
   EXPECT_EQ(security_state::NONE, security_info.security_level);
-  EXPECT_EQ(security_state::NO_DEPRECATED_SHA1,
-            security_info.sha1_deprecation_status);
+  EXPECT_FALSE(security_info.sha1_in_chain);
   EXPECT_EQ(security_state::CONTENT_STATUS_NONE,
             security_info.mixed_content_status);
   EXPECT_TRUE(security_info.sct_verify_statuses.empty());
@@ -369,8 +368,7 @@
   security_state::SecurityInfo security_info;
   helper->GetSecurityInfo(&security_info);
   EXPECT_EQ(security_state::NONE, security_info.security_level);
-  EXPECT_EQ(security_state::NO_DEPRECATED_SHA1,
-            security_info.sha1_deprecation_status);
+  EXPECT_FALSE(security_info.sha1_in_chain);
   EXPECT_EQ(security_state::CONTENT_STATUS_NONE,
             security_info.mixed_content_status);
   EXPECT_TRUE(security_info.sct_verify_statuses.empty());
@@ -389,23 +387,75 @@
                                https_server_.GetURL("/ssl/google.html"));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::SECURE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, false,
+      security_state::SECURE, false, security_state::CONTENT_STATUS_NONE, false,
       false /* expect cert status error */);
 }
 
-IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest, SHA1Certificate) {
+// Test security state after clickthrough for a SHA-1 certificate that is
+// blocked by default.
+IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest, SHA1CertificateBlocked) {
   ASSERT_TRUE(https_server_.Start());
-  SetUpMockCertVerifierForHttpsServer(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT,
-                                      net::OK);
+  SetUpMockCertVerifierForHttpsServer(
+      net::CERT_STATUS_SHA1_SIGNATURE_PRESENT |
+          net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM,
+      net::ERR_CERT_WEAK_SIGNATURE_ALGORITHM);
 
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  SecurityStyleTestObserver observer(web_contents);
   ui_test_utils::NavigateToURL(browser(),
                                https_server_.GetURL("/ssl/google.html"));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::DEPRECATED_SHA1_MAJOR,
-      security_state::CONTENT_STATUS_NONE, false,
+      security_state::DANGEROUS, true, security_state::CONTENT_STATUS_NONE,
+      false, true /* expect cert status error */);
+
+  const content::SecurityStyleExplanations& interstitial_explanation =
+      observer.latest_explanations();
+  ASSERT_EQ(1u, interstitial_explanation.broken_explanations.size());
+  ASSERT_EQ(1u, interstitial_explanation.unauthenticated_explanations.size());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SHA1),
+            interstitial_explanation.unauthenticated_explanations[0].summary);
+
+  ProceedThroughInterstitial(
+      browser()->tab_strip_model()->GetActiveWebContents());
+
+  CheckSecurityInfoForSecure(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      security_state::DANGEROUS, true, security_state::CONTENT_STATUS_NONE,
+      false, true /* expect cert status error */);
+
+  const content::SecurityStyleExplanations& page_explanation =
+      observer.latest_explanations();
+  ASSERT_EQ(1u, page_explanation.broken_explanations.size());
+  ASSERT_EQ(1u, page_explanation.unauthenticated_explanations.size());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SHA1),
+            page_explanation.unauthenticated_explanations[0].summary);
+}
+
+// Test security state for a SHA-1 certificate that is allowed by policy.
+IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest, SHA1CertificateWarning) {
+  ASSERT_TRUE(https_server_.Start());
+  SetUpMockCertVerifierForHttpsServer(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT,
+                                      net::OK);
+
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  SecurityStyleTestObserver observer(web_contents);
+  ui_test_utils::NavigateToURL(browser(),
+                               https_server_.GetURL("/ssl/google.html"));
+  CheckSecurityInfoForSecure(
+      browser()->tab_strip_model()->GetActiveWebContents(),
+      security_state::NONE, true, security_state::CONTENT_STATUS_NONE, false,
       false /* expect cert status error */);
+
+  const content::SecurityStyleExplanations& explanation =
+      observer.latest_explanations();
+
+  ASSERT_EQ(0u, explanation.broken_explanations.size());
+  ASSERT_EQ(1u, explanation.unauthenticated_explanations.size());
+  EXPECT_EQ(l10n_util::GetStringUTF8(IDS_SHA1),
+            explanation.unauthenticated_explanations[0].summary);
 }
 
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest, MixedContent) {
@@ -427,9 +477,8 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::NONE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_DISPLAYED, false,
-      false /* expect cert status error */);
+      security_state::NONE, false, security_state::CONTENT_STATUS_DISPLAYED,
+      false, false /* expect cert status error */);
 
   // Navigate to an HTTPS page that displays mixed content dynamically.
   GetFilePathWithHostAndPortReplacement(
@@ -439,8 +488,7 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::SECURE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, false,
+      security_state::SECURE, false, security_state::CONTENT_STATUS_NONE, false,
       false /* expect cert status error */);
   // Load the insecure image.
   bool js_result = false;
@@ -450,9 +498,8 @@
   EXPECT_TRUE(js_result);
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::NONE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_DISPLAYED, false,
-      false /* expect cert status error */);
+      security_state::NONE, false, security_state::CONTENT_STATUS_DISPLAYED,
+      false, false /* expect cert status error */);
 
   // Navigate to an HTTPS page that runs mixed content.
   GetFilePathWithHostAndPortReplacement("/ssl/page_runs_insecure_content.html",
@@ -461,9 +508,8 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_RAN, false,
-      false /* expect cert status error */);
+      security_state::DANGEROUS, false, security_state::CONTENT_STATUS_RAN,
+      false, false /* expect cert status error */);
 
   // Navigate to an HTTPS page that runs and displays mixed content.
   GetFilePathWithHostAndPortReplacement(
@@ -473,7 +519,7 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::NO_DEPRECATED_SHA1,
+      security_state::DANGEROUS, false,
       security_state::CONTENT_STATUS_DISPLAYED_AND_RAN, false,
       false /* expect cert status error */);
 
@@ -493,9 +539,8 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_RAN, false,
-      false /* expect cert status error */);
+      security_state::DANGEROUS, false, security_state::CONTENT_STATUS_RAN,
+      false, false /* expect cert status error */);
 }
 
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest,
@@ -587,7 +632,8 @@
             security_info.content_with_cert_errors_status);
 }
 
-// Same as the test above but with a long-lived SHA1 cert.
+// Same as SecurityStateTabHelperTest.ActiveAndPassiveContentWithCertErrors but
+// with a SHA1 cert.
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest, MixedContentWithSHA1Cert) {
   ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(https_server_.Start());
@@ -609,9 +655,8 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::DEPRECATED_SHA1_MAJOR,
-      security_state::CONTENT_STATUS_DISPLAYED, false,
-      false /* expect cert status error */);
+      security_state::NONE, true, security_state::CONTENT_STATUS_DISPLAYED,
+      false, false /* expect cert status error */);
 
   // Navigate to an HTTPS page that displays mixed content dynamically.
   GetFilePathWithHostAndPortReplacement(
@@ -621,8 +666,7 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::DEPRECATED_SHA1_MAJOR,
-      security_state::CONTENT_STATUS_NONE, false,
+      security_state::NONE, true, security_state::CONTENT_STATUS_NONE, false,
       false /* expect cert status error */);
   // Load the insecure image.
   bool js_result = false;
@@ -632,9 +676,8 @@
   EXPECT_TRUE(js_result);
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::DEPRECATED_SHA1_MAJOR,
-      security_state::CONTENT_STATUS_DISPLAYED, false,
-      false /* expect cert status error */);
+      security_state::NONE, true, security_state::CONTENT_STATUS_DISPLAYED,
+      false, false /* expect cert status error */);
 
   // Navigate to an HTTPS page that runs mixed content.
   GetFilePathWithHostAndPortReplacement("/ssl/page_runs_insecure_content.html",
@@ -643,9 +686,8 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::DEPRECATED_SHA1_MAJOR,
-      security_state::CONTENT_STATUS_RAN, false,
-      false /* expect cert status error */);
+      security_state::DANGEROUS, true, security_state::CONTENT_STATUS_RAN,
+      false, false /* expect cert status error */);
 
   // Navigate to an HTTPS page that runs and displays mixed content.
   GetFilePathWithHostAndPortReplacement(
@@ -655,7 +697,7 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::DEPRECATED_SHA1_MAJOR,
+      security_state::DANGEROUS, true,
       security_state::CONTENT_STATUS_DISPLAYED_AND_RAN, false,
       false /* expect cert status error */);
 }
@@ -681,8 +723,7 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::SECURE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, false,
+      security_state::SECURE, false, security_state::CONTENT_STATUS_NONE, false,
       false /* expect cert status error */);
 }
 
@@ -696,18 +737,16 @@
                                https_server_.GetURL("/ssl/google.html"));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, false,
-      true /* expect cert status error */);
+      security_state::DANGEROUS, false, security_state::CONTENT_STATUS_NONE,
+      false, true /* expect cert status error */);
 
   ProceedThroughInterstitial(
       browser()->tab_strip_model()->GetActiveWebContents());
 
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, false,
-      true /* expect cert status error */);
+      security_state::DANGEROUS, false, security_state::CONTENT_STATUS_NONE,
+      false, true /* expect cert status error */);
 
   // Navigate to a broken HTTPS page that displays mixed content.
   std::string replacement_path;
@@ -718,7 +757,7 @@
                                https_server_.GetURL(replacement_path));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::DANGEROUS, security_state::NO_DEPRECATED_SHA1,
+      security_state::DANGEROUS, false,
       security_state::CONTENT_STATUS_DISPLAYED, false,
       true /* expect cert status error */);
 }
@@ -779,8 +818,8 @@
 
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::SECURE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, true, false);
+      security_state::SECURE, false, security_state::CONTENT_STATUS_NONE, true,
+      false);
 
   const content::SecurityStyleExplanations& explanation =
       observer.latest_explanations();
@@ -865,8 +904,7 @@
                                https_server_.GetURL("/ssl/google.html"));
   CheckSecurityInfoForSecure(
       browser()->tab_strip_model()->GetActiveWebContents(),
-      security_state::SECURE, security_state::NO_DEPRECATED_SHA1,
-      security_state::CONTENT_STATUS_NONE, false,
+      security_state::SECURE, false, security_state::CONTENT_STATUS_NONE, false,
       false /* expect cert status error */);
 
   // Navigate to a page that doesn't finish loading. Test that the
@@ -1479,15 +1517,13 @@
   controller.LoadURL(https_server_.GetURL("/title1.html"), content::Referrer(),
                      ui::PAGE_TRANSITION_TYPED, std::string());
   EXPECT_TRUE(content::WaitForLoadStop(new_contents));
-  CheckSecurityInfoForSecure(new_contents, security_state::SECURE,
-                             security_state::NO_DEPRECATED_SHA1,
+  CheckSecurityInfoForSecure(new_contents, security_state::SECURE, false,
                              security_state::CONTENT_STATUS_NONE, false,
                              false /* expect cert status error */);
 
   browser()->tab_strip_model()->InsertWebContentsAt(0, new_contents,
                                                     TabStripModel::ADD_NONE);
-  CheckSecurityInfoForSecure(new_contents, security_state::SECURE,
-                             security_state::NO_DEPRECATED_SHA1,
+  CheckSecurityInfoForSecure(new_contents, security_state::SECURE, false,
                              security_state::CONTENT_STATUS_NONE, false,
                              false /* expect cert status error */);
 }
diff --git a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
index c61cb3f..45d2a559 100644
--- a/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
+++ b/chrome/browser/ui/views/frame/browser_header_painter_ash.cc
@@ -7,7 +7,6 @@
 #include "ash/common/ash_layout_constants.h"
 #include "ash/common/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/common/frame/header_painter_util.h"
-#include "ash/resources/vector_icons/vector_icons.h"
 #include "base/logging.h"  // DCHECK
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser.h"
@@ -23,6 +22,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/gfx/vector_icons_public.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
@@ -285,27 +285,29 @@
 }
 
 void BrowserHeaderPainterAsh::UpdateCaptionButtons() {
-  caption_button_container_->SetButtonImage(ash::CAPTION_BUTTON_ICON_MINIMIZE,
-                                            ash::kWindowControlMinimizeIcon);
-  caption_button_container_->SetButtonImage(ash::CAPTION_BUTTON_ICON_CLOSE,
-                                            ash::kWindowControlCloseIcon);
+  caption_button_container_->SetButtonImage(
+      ash::CAPTION_BUTTON_ICON_MINIMIZE,
+      gfx::VectorIconId::WINDOW_CONTROL_MINIMIZE);
+  caption_button_container_->SetButtonImage(
+      ash::CAPTION_BUTTON_ICON_CLOSE, gfx::VectorIconId::WINDOW_CONTROL_CLOSE);
   caption_button_container_->SetButtonImage(
       ash::CAPTION_BUTTON_ICON_LEFT_SNAPPED,
-      ash::kWindowControlLeftSnappedIcon);
+      gfx::VectorIconId::WINDOW_CONTROL_LEFT_SNAPPED);
   caption_button_container_->SetButtonImage(
       ash::CAPTION_BUTTON_ICON_RIGHT_SNAPPED,
-      ash::kWindowControlRightSnappedIcon);
+      gfx::VectorIconId::WINDOW_CONTROL_RIGHT_SNAPPED);
 
-  const gfx::VectorIcon* size_icon = &ash::kWindowControlMaximizeIcon;
+  gfx::VectorIconId size_icon_id = gfx::VectorIconId::WINDOW_CONTROL_MAXIMIZE;
   gfx::Size button_size(
       GetAshLayoutSize(AshLayoutSize::BROWSER_RESTORED_CAPTION_BUTTON));
   if (frame_->IsMaximized() || frame_->IsFullscreen()) {
-    size_icon = &ash::kWindowControlRestoreIcon;
+    size_icon_id = gfx::VectorIconId::WINDOW_CONTROL_RESTORE;
     button_size =
         GetAshLayoutSize(AshLayoutSize::BROWSER_MAXIMIZED_CAPTION_BUTTON);
   }
   caption_button_container_->SetButtonImage(
-      ash::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE, *size_icon);
+      ash::CAPTION_BUTTON_ICON_MAXIMIZE_RESTORE,
+      size_icon_id);
   caption_button_container_->SetButtonSize(button_size);
 }
 
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index 9a7f925..a0afe6d8 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -492,31 +492,13 @@
         site_identity_details_.assign(l10n_util::GetStringFUTF16(
             IDS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY_VERIFIED, issuer_name));
       }
-      switch (security_info.sha1_deprecation_status) {
-        case security_state::DEPRECATED_SHA1_MINOR:
-          site_identity_status_ =
-              SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MINOR;
-          site_identity_details_ +=
-              UTF8ToUTF16("\n\n") +
-              l10n_util::GetStringUTF16(
-                  IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MINOR);
-          break;
-        case security_state::DEPRECATED_SHA1_MAJOR:
-          site_identity_status_ =
-              SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR;
-          site_identity_details_ +=
-              UTF8ToUTF16("\n\n") +
-              l10n_util::GetStringUTF16(
-                  IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR);
-          break;
-        case security_state::NO_DEPRECATED_SHA1:
-          // Nothing to do.
-          break;
-        case security_state::UNKNOWN_SHA1:
-          // UNKNOWN_SHA1 should only appear when certificate info has not been
-          // initialized, in which case this if-statement should not be running
-          // because there is no other cert info.
-          NOTREACHED();
+      if (security_info.sha1_in_chain) {
+        site_identity_status_ =
+            SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM;
+        site_identity_details_ +=
+            UTF8ToUTF16("\n\n") +
+            l10n_util::GetStringUTF16(
+                IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM);
       }
     }
   } else {
diff --git a/chrome/browser/ui/website_settings/website_settings.h b/chrome/browser/ui/website_settings/website_settings.h
index bac9695..66b8ea7a 100644
--- a/chrome/browser/ui/website_settings/website_settings.h
+++ b/chrome/browser/ui/website_settings/website_settings.h
@@ -75,8 +75,7 @@
     SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT,
     // The website provided a valid certificate, but the certificate or chain
     // is using a deprecated signature algorithm.
-    SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MINOR,
-    SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR,
+    SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM,
     // The website has been flagged by Safe Browsing as dangerous for
     // containing malware, social engineering, or unwanted software.
     SITE_IDENTITY_STATUS_MALWARE,
diff --git a/chrome/browser/ui/website_settings/website_settings_ui.cc b/chrome/browser/ui/website_settings/website_settings_ui.cc
index fffcdb8..62370e0 100644
--- a/chrome/browser/ui/website_settings/website_settings_ui.cc
+++ b/chrome/browser/ui/website_settings/website_settings_ui.cc
@@ -192,10 +192,7 @@
       return CreateSecurityDescription(
           IDS_WEBSITE_SETTINGS_UNWANTED_SOFTWARE_SUMMARY,
           IDS_WEBSITE_SETTINGS_UNWANTED_SOFTWARE_DETAILS);
-    case WebsiteSettings::
-        SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MINOR:
-    case WebsiteSettings::
-        SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR:
+    case WebsiteSettings::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM:
     case WebsiteSettings::SITE_IDENTITY_STATUS_UNKNOWN:
     case WebsiteSettings::SITE_IDENTITY_STATUS_NO_CERT:
     default:
@@ -348,14 +345,9 @@
     case WebsiteSettings::SITE_IDENTITY_STATUS_ADMIN_PROVIDED_CERT:
       resource_id = IDR_PAGEINFO_ENTERPRISE_MANAGED;
       break;
-    case WebsiteSettings::
-        SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MINOR:
+    case WebsiteSettings::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM:
       resource_id = IDR_PAGEINFO_WARNING_MINOR;
       break;
-    case WebsiteSettings::
-        SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR:
-      resource_id = IDR_PAGEINFO_BAD;
-      break;
     default:
       NOTREACHED();
       break;
diff --git a/chrome/browser/ui/website_settings/website_settings_unittest.cc b/chrome/browser/ui/website_settings/website_settings_unittest.cc
index 024e5ae6..89119f6a 100644
--- a/chrome/browser/ui/website_settings/website_settings_unittest.cc
+++ b/chrome/browser/ui/website_settings/website_settings_unittest.cc
@@ -593,7 +593,7 @@
   EXPECT_EQ(base::string16(), website_settings()->organization_name());
 }
 
-TEST_F(WebsiteSettingsTest, HTTPSSHA1Minor) {
+TEST_F(WebsiteSettingsTest, HTTPSSHA1) {
   security_info_.security_level = security_state::NONE;
   security_info_.scheme_is_cryptographic = true;
   security_info_.certificate = cert();
@@ -603,48 +603,21 @@
   status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
   status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
   security_info_.connection_status = status;
-  security_info_.sha1_deprecation_status =
-      security_state::DEPRECATED_SHA1_MINOR;
+  security_info_.sha1_in_chain = true;
 
   SetDefaultUIExpectations(mock_ui());
 
   EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED,
             website_settings()->site_connection_status());
-  EXPECT_EQ(WebsiteSettings::
-                SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MINOR,
-            website_settings()->site_identity_status());
+  EXPECT_EQ(
+      WebsiteSettings::SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM,
+      website_settings()->site_identity_status());
   EXPECT_EQ(base::string16(), website_settings()->organization_name());
   EXPECT_EQ(IDR_PAGEINFO_WARNING_MINOR,
             WebsiteSettingsUI::GetIdentityIconID(
                 website_settings()->site_identity_status()));
 }
 
-TEST_F(WebsiteSettingsTest, HTTPSSHA1Major) {
-  security_info_.security_level = security_state::NONE;
-  security_info_.scheme_is_cryptographic = true;
-  security_info_.certificate = cert();
-  security_info_.cert_status = 0;
-  security_info_.security_bits = 81;  // No error if > 80.
-  int status = 0;
-  status = SetSSLVersion(status, net::SSL_CONNECTION_VERSION_TLS1);
-  status = SetSSLCipherSuite(status, CR_TLS_RSA_WITH_AES_256_CBC_SHA256);
-  security_info_.connection_status = status;
-  security_info_.sha1_deprecation_status =
-      security_state::DEPRECATED_SHA1_MAJOR;
-
-  SetDefaultUIExpectations(mock_ui());
-
-  EXPECT_EQ(WebsiteSettings::SITE_CONNECTION_STATUS_ENCRYPTED,
-            website_settings()->site_connection_status());
-  EXPECT_EQ(WebsiteSettings::
-                SITE_IDENTITY_STATUS_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR,
-            website_settings()->site_identity_status());
-  EXPECT_EQ(base::string16(), website_settings()->organization_name());
-  EXPECT_EQ(IDR_PAGEINFO_BAD,
-            WebsiteSettingsUI::GetIdentityIconID(
-                website_settings()->site_identity_status()));
-}
-
 #if !defined(OS_ANDROID)
 TEST_F(WebsiteSettingsTest, NoInfoBar) {
   SetDefaultUIExpectations(mock_ui());
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index 63eb8a5..05c1d60 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -69,6 +69,8 @@
 
 #if defined(OS_CHROMEOS)
 const char kNumberOfUsers[] = "num-users";
+// Temporary for https://crbug.com/660960
+const char kLastGoodCloseStack[] = "last-good-close-stack";
 #endif
 
 #if defined(OS_MACOSX)
@@ -155,6 +157,8 @@
     { kInputEventFilterSendFailure, kSmallSize },
 #if defined(OS_CHROMEOS)
     { kNumberOfUsers, kSmallSize },
+    // Temporary for https://crbug.com/660960
+    { kLastGoodCloseStack, kMediumSize },
 #endif
 #if defined(OS_MACOSX)
     { mac::kFirstNSException, kMediumSize },
diff --git a/chrome/common/crash_keys.h b/chrome/common/crash_keys.h
index 3a811f7..2b6106c 100644
--- a/chrome/common/crash_keys.h
+++ b/chrome/common/crash_keys.h
@@ -117,6 +117,10 @@
 #if defined(OS_CHROMEOS)
 // The number of simultaneous users in multi profile sessions.
 extern const char kNumberOfUsers[];
+
+// The stack trace of the last good close of a fd that just fails a close.
+// Temporary for https://crbug.com/660960
+extern const char kLastGoodCloseStack[];
 #endif
 
 #if defined(OS_MACOSX)
diff --git a/chrome/installer/util/prebuild/create_string_rc.py b/chrome/installer/util/prebuild/create_string_rc.py
index ac068be..9f73dac 100755
--- a/chrome/installer/util/prebuild/create_string_rc.py
+++ b/chrome/installer/util/prebuild/create_string_rc.py
@@ -47,8 +47,6 @@
 STRING_IDS = [
   'IDS_PRODUCT_NAME',
   'IDS_SXS_SHORTCUT_NAME',
-  'IDS_PRODUCT_APP_LAUNCHER_NAME',  # Used in App Launcher registry.
-  'IDS_PRODUCT_BINARIES_NAME',
   'IDS_PRODUCT_DESCRIPTION',
   'IDS_ABOUT_VERSION_COMPANY_NAME',
   'IDS_INSTALL_HIGHER_VERSION',
@@ -62,8 +60,6 @@
   'IDS_INSTALL_UNCOMPRESSION_FAILED',
   'IDS_INSTALL_INVALID_ARCHIVE',
   'IDS_INSTALL_INSUFFICIENT_RIGHTS',
-  'IDS_INSTALL_NO_PRODUCTS_TO_UPDATE',
-  'IDS_INSTALL_MULTI_INSTALLATION_EXISTS',
   'IDS_SHORTCUT_TOOLTIP',
   'IDS_SHORTCUT_NEW_WINDOW',
   'IDS_APP_SHORTCUTS_SUBDIR_NAME',
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index fc8d9b2..1e2aca4c 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2939,7 +2939,7 @@
 
 group("angle_perftests") {
   testonly = true
-  if (is_win) {
+  if (is_win || is_linux) {
     data_deps = [
       "//third_party/angle/src/tests:angle_perftests",
     ]
diff --git a/chrome/test/data/android/payments/abort.js b/chrome/test/data/payments/abort.js
similarity index 100%
rename from chrome/test/data/android/payments/abort.js
rename to chrome/test/data/payments/abort.js
diff --git a/chrome/test/data/android/payments/basic_card.js b/chrome/test/data/payments/basic_card.js
similarity index 100%
rename from chrome/test/data/android/payments/basic_card.js
rename to chrome/test/data/payments/basic_card.js
diff --git a/chrome/test/data/android/payments/bobpay.js b/chrome/test/data/payments/bobpay.js
similarity index 100%
rename from chrome/test/data/android/payments/bobpay.js
rename to chrome/test/data/payments/bobpay.js
diff --git a/chrome/test/data/android/payments/bobpay_and_cards.js b/chrome/test/data/payments/bobpay_and_cards.js
similarity index 100%
rename from chrome/test/data/android/payments/bobpay_and_cards.js
rename to chrome/test/data/payments/bobpay_and_cards.js
diff --git a/chrome/test/data/android/payments/can_make_payment_query.js b/chrome/test/data/payments/can_make_payment_query.js
similarity index 100%
rename from chrome/test/data/android/payments/can_make_payment_query.js
rename to chrome/test/data/payments/can_make_payment_query.js
diff --git a/chrome/test/data/android/payments/can_make_payment_query_bobpay.js b/chrome/test/data/payments/can_make_payment_query_bobpay.js
similarity index 100%
rename from chrome/test/data/android/payments/can_make_payment_query_bobpay.js
rename to chrome/test/data/payments/can_make_payment_query_bobpay.js
diff --git a/chrome/test/data/android/payments/can_make_payment_query_cc.js b/chrome/test/data/payments/can_make_payment_query_cc.js
similarity index 100%
rename from chrome/test/data/android/payments/can_make_payment_query_cc.js
rename to chrome/test/data/payments/can_make_payment_query_cc.js
diff --git a/chrome/test/data/android/payments/contact_details.js b/chrome/test/data/payments/contact_details.js
similarity index 100%
rename from chrome/test/data/android/payments/contact_details.js
rename to chrome/test/data/payments/contact_details.js
diff --git a/chrome/test/data/android/payments/contact_details_and_free_shipping.js b/chrome/test/data/payments/contact_details_and_free_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/contact_details_and_free_shipping.js
rename to chrome/test/data/payments/contact_details_and_free_shipping.js
diff --git a/chrome/test/data/android/payments/dynamic_shipping.js b/chrome/test/data/payments/dynamic_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/dynamic_shipping.js
rename to chrome/test/data/payments/dynamic_shipping.js
diff --git a/chrome/test/data/android/payments/email.js b/chrome/test/data/payments/email.js
similarity index 100%
rename from chrome/test/data/android/payments/email.js
rename to chrome/test/data/payments/email.js
diff --git a/chrome/test/data/android/payments/email_and_free_shipping.js b/chrome/test/data/payments/email_and_free_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/email_and_free_shipping.js
rename to chrome/test/data/payments/email_and_free_shipping.js
diff --git a/chrome/test/data/android/payments/email_and_phone.js b/chrome/test/data/payments/email_and_phone.js
similarity index 100%
rename from chrome/test/data/android/payments/email_and_phone.js
rename to chrome/test/data/payments/email_and_phone.js
diff --git a/chrome/test/data/android/payments/extra_shipping_options.js b/chrome/test/data/payments/extra_shipping_options.js
similarity index 100%
rename from chrome/test/data/android/payments/extra_shipping_options.js
rename to chrome/test/data/payments/extra_shipping_options.js
diff --git a/chrome/test/data/android/payments/fail_complete.js b/chrome/test/data/payments/fail_complete.js
similarity index 100%
rename from chrome/test/data/android/payments/fail_complete.js
rename to chrome/test/data/payments/fail_complete.js
diff --git a/chrome/test/data/android/payments/free_shipping.js b/chrome/test/data/payments/free_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/free_shipping.js
rename to chrome/test/data/payments/free_shipping.js
diff --git a/chrome/test/data/android/payments/metrics.js b/chrome/test/data/payments/metrics.js
similarity index 100%
rename from chrome/test/data/android/payments/metrics.js
rename to chrome/test/data/payments/metrics.js
diff --git a/chrome/test/data/android/payments/name.js b/chrome/test/data/payments/name.js
similarity index 100%
rename from chrome/test/data/android/payments/name.js
rename to chrome/test/data/payments/name.js
diff --git a/chrome/test/data/android/payments/name_and_free_shipping.js b/chrome/test/data/payments/name_and_free_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/name_and_free_shipping.js
rename to chrome/test/data/payments/name_and_free_shipping.js
diff --git a/chrome/test/data/android/payments/no_shipping.js b/chrome/test/data/payments/no_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/no_shipping.js
rename to chrome/test/data/payments/no_shipping.js
diff --git a/chrome/test/data/android/payments/payment_request_abort_test.html b/chrome/test/data/payments/payment_request_abort_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_abort_test.html
rename to chrome/test/data/payments/payment_request_abort_test.html
diff --git a/chrome/test/data/android/payments/payment_request_basic_card_test.html b/chrome/test/data/payments/payment_request_basic_card_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_basic_card_test.html
rename to chrome/test/data/payments/payment_request_basic_card_test.html
diff --git a/chrome/test/data/android/payments/payment_request_bobpay_and_cards_test.html b/chrome/test/data/payments/payment_request_bobpay_and_cards_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_bobpay_and_cards_test.html
rename to chrome/test/data/payments/payment_request_bobpay_and_cards_test.html
diff --git a/chrome/test/data/android/payments/payment_request_bobpay_test.html b/chrome/test/data/payments/payment_request_bobpay_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_bobpay_test.html
rename to chrome/test/data/payments/payment_request_bobpay_test.html
diff --git a/chrome/test/data/android/payments/payment_request_can_make_payment_query_bobpay_test.html b/chrome/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_can_make_payment_query_bobpay_test.html
rename to chrome/test/data/payments/payment_request_can_make_payment_query_bobpay_test.html
diff --git a/chrome/test/data/android/payments/payment_request_can_make_payment_query_cc_test.html b/chrome/test/data/payments/payment_request_can_make_payment_query_cc_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_can_make_payment_query_cc_test.html
rename to chrome/test/data/payments/payment_request_can_make_payment_query_cc_test.html
diff --git a/chrome/test/data/android/payments/payment_request_can_make_payment_query_test.html b/chrome/test/data/payments/payment_request_can_make_payment_query_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_can_make_payment_query_test.html
rename to chrome/test/data/payments/payment_request_can_make_payment_query_test.html
diff --git a/chrome/test/data/android/payments/payment_request_contact_details_and_free_shipping_test.html b/chrome/test/data/payments/payment_request_contact_details_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_contact_details_and_free_shipping_test.html
rename to chrome/test/data/payments/payment_request_contact_details_and_free_shipping_test.html
diff --git a/chrome/test/data/android/payments/payment_request_contact_details_test.html b/chrome/test/data/payments/payment_request_contact_details_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_contact_details_test.html
rename to chrome/test/data/payments/payment_request_contact_details_test.html
diff --git a/chrome/test/data/android/payments/payment_request_dynamic_shipping_test.html b/chrome/test/data/payments/payment_request_dynamic_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_dynamic_shipping_test.html
rename to chrome/test/data/payments/payment_request_dynamic_shipping_test.html
diff --git a/chrome/test/data/android/payments/payment_request_email_and_free_shipping_test.html b/chrome/test/data/payments/payment_request_email_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_email_and_free_shipping_test.html
rename to chrome/test/data/payments/payment_request_email_and_free_shipping_test.html
diff --git a/chrome/test/data/android/payments/payment_request_email_and_phone_test.html b/chrome/test/data/payments/payment_request_email_and_phone_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_email_and_phone_test.html
rename to chrome/test/data/payments/payment_request_email_and_phone_test.html
diff --git a/chrome/test/data/android/payments/payment_request_email_test.html b/chrome/test/data/payments/payment_request_email_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_email_test.html
rename to chrome/test/data/payments/payment_request_email_test.html
diff --git a/chrome/test/data/android/payments/payment_request_extra_shipping_options_test.html b/chrome/test/data/payments/payment_request_extra_shipping_options_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_extra_shipping_options_test.html
rename to chrome/test/data/payments/payment_request_extra_shipping_options_test.html
diff --git a/chrome/test/data/android/payments/payment_request_fail_complete_test.html b/chrome/test/data/payments/payment_request_fail_complete_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_fail_complete_test.html
rename to chrome/test/data/payments/payment_request_fail_complete_test.html
diff --git a/chrome/test/data/android/payments/payment_request_free_shipping_test.html b/chrome/test/data/payments/payment_request_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_free_shipping_test.html
rename to chrome/test/data/payments/payment_request_free_shipping_test.html
diff --git a/chrome/test/data/payment_request_iframe.html b/chrome/test/data/payments/payment_request_iframe.html
similarity index 100%
rename from chrome/test/data/payment_request_iframe.html
rename to chrome/test/data/payments/payment_request_iframe.html
diff --git a/chrome/test/data/payment_request_main.html b/chrome/test/data/payments/payment_request_main.html
similarity index 100%
rename from chrome/test/data/payment_request_main.html
rename to chrome/test/data/payments/payment_request_main.html
diff --git a/chrome/test/data/android/payments/payment_request_metrics_test.html b/chrome/test/data/payments/payment_request_metrics_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_metrics_test.html
rename to chrome/test/data/payments/payment_request_metrics_test.html
diff --git a/chrome/test/data/payment_request_multiple_requests.html b/chrome/test/data/payments/payment_request_multiple_requests.html
similarity index 100%
rename from chrome/test/data/payment_request_multiple_requests.html
rename to chrome/test/data/payments/payment_request_multiple_requests.html
diff --git a/chrome/test/data/android/payments/payment_request_name_and_free_shipping_test.html b/chrome/test/data/payments/payment_request_name_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_name_and_free_shipping_test.html
rename to chrome/test/data/payments/payment_request_name_and_free_shipping_test.html
diff --git a/chrome/test/data/android/payments/payment_request_name_test.html b/chrome/test/data/payments/payment_request_name_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_name_test.html
rename to chrome/test/data/payments/payment_request_name_test.html
diff --git a/chrome/test/data/android/payments/payment_request_no_shipping_test.html b/chrome/test/data/payments/payment_request_no_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_no_shipping_test.html
rename to chrome/test/data/payments/payment_request_no_shipping_test.html
diff --git a/chrome/test/data/android/payments/payment_request_phone_and_free_shipping_test.html b/chrome/test/data/payments/payment_request_phone_and_free_shipping_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_phone_and_free_shipping_test.html
rename to chrome/test/data/payments/payment_request_phone_and_free_shipping_test.html
diff --git a/chrome/test/data/android/payments/payment_request_phone_test.html b/chrome/test/data/payments/payment_request_phone_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_phone_test.html
rename to chrome/test/data/payments/payment_request_phone_test.html
diff --git a/chrome/test/data/android/payments/payment_request_show_twice_test.html b/chrome/test/data/payments/payment_request_show_twice_test.html
similarity index 100%
rename from chrome/test/data/android/payments/payment_request_show_twice_test.html
rename to chrome/test/data/payments/payment_request_show_twice_test.html
diff --git a/chrome/test/data/android/payments/phone.js b/chrome/test/data/payments/phone.js
similarity index 100%
rename from chrome/test/data/android/payments/phone.js
rename to chrome/test/data/payments/phone.js
diff --git a/chrome/test/data/android/payments/phone_and_free_shipping.js b/chrome/test/data/payments/phone_and_free_shipping.js
similarity index 100%
rename from chrome/test/data/android/payments/phone_and_free_shipping.js
rename to chrome/test/data/payments/phone_and_free_shipping.js
diff --git a/chrome/test/data/android/payments/show_twice.js b/chrome/test/data/payments/show_twice.js
similarity index 100%
rename from chrome/test/data/android/payments/show_twice.js
rename to chrome/test/data/payments/show_twice.js
diff --git a/chrome/test/data/android/payments/style.css b/chrome/test/data/payments/style.css
similarity index 100%
rename from chrome/test/data/android/payments/style.css
rename to chrome/test/data/payments/style.css
diff --git a/chrome/test/data/android/payments/util.js b/chrome/test/data/payments/util.js
similarity index 100%
rename from chrome/test/data/android/payments/util.js
rename to chrome/test/data/payments/util.js
diff --git a/chrome/test/data/prerender/service_worker.html b/chrome/test/data/prerender/service_worker.html
new file mode 100644
index 0000000..103b5d0
--- /dev/null
+++ b/chrome/test/data/prerender/service_worker.html
@@ -0,0 +1,21 @@
+<html>
+<head>
+  <title>ServiceWorker Loader</title>
+  <script type="text/javascript">
+    window.addEventListener('load', function() {
+      navigator.serviceWorker.register('/prerender/service_worker.js')
+        .then(function(registration) {
+          console.log('ServiceWorker registered');
+          return navigator.serviceWorker.ready;
+        })
+        .then(function(registration) {
+          document.title = 'SW READY';
+        })
+        .catch(function(err) {
+          console.log(err);
+        });
+    });
+  </script>
+<head>
+<body></body>
+</html>
diff --git a/chrome/test/data/prerender/service_worker.js b/chrome/test/data/prerender/service_worker.js
new file mode 100644
index 0000000..62128dd
--- /dev/null
+++ b/chrome/test/data/prerender/service_worker.js
@@ -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.
+
+console.log('ServiceWorker executed');
+
+self.addEventListener('install', function (event) {
+  console.log('ServiceWorker install');
+});
+
+self.addEventListener('fetch', function (event) {
+  // Replace main page with one that includes an image tag that can be
+  // preload scanned and prefetched.
+  console.log('Saw request ' + event.request.url);
+  if (event.request.url.endsWith('prerender/prefetch_page.html')) {
+    console.log('Intercepting ' + event.request.url);
+    var headers = new Headers;
+    headers.set('Content-Type', 'text/html; charset=UTF-8');
+    var content = '<html><body><img src="/prerender/image.png"/></body></html>';
+    var response = new Response(content, {
+      status: 200,
+      headers: headers });
+    event.respondWith(response);
+  }
+});
diff --git a/chrome/test/data/prerender/service_worker.js.mock-http-headers b/chrome/test/data/prerender/service_worker.js.mock-http-headers
new file mode 100644
index 0000000..c9a3625
--- /dev/null
+++ b/chrome/test/data/prerender/service_worker.js.mock-http-headers
@@ -0,0 +1,2 @@
+HTTP/1.1 200 OK
+Content-Type: text/javascript
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 3833eda..5281b7de 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -325,6 +325,7 @@
     "webdata/autofill_profile_syncable_service_unittest.cc",
     "webdata/autofill_table_unittest.cc",
     "webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
+    "webdata/autofill_wallet_syncable_service_unittest.cc",
     "webdata/web_data_service_unittest.cc",
   ]
 
diff --git a/components/autofill/core/browser/webdata/autofill_table.cc b/components/autofill/core/browser/webdata/autofill_table.cc
index 3c1d9b3c..8d03d93 100644
--- a/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/components/autofill/core/browser/webdata/autofill_table.cc
@@ -942,7 +942,7 @@
 }
 
 bool AutofillTable::GetServerProfiles(
-    std::vector<std::unique_ptr<AutofillProfile>>* profiles) {
+    std::vector<std::unique_ptr<AutofillProfile>>* profiles) const {
   profiles->clear();
 
   sql::Statement s(db_->GetUniqueStatement(
@@ -1205,7 +1205,7 @@
 }
 
 bool AutofillTable::GetServerCreditCards(
-    std::vector<std::unique_ptr<CreditCard>>* credit_cards) {
+    std::vector<std::unique_ptr<CreditCard>>* credit_cards) const {
   credit_cards->clear();
 
   sql::Statement s(db_->GetUniqueStatement(
diff --git a/components/autofill/core/browser/webdata/autofill_table.h b/components/autofill/core/browser/webdata/autofill_table.h
index e223d5c..c01775f 100644
--- a/components/autofill/core/browser/webdata/autofill_table.h
+++ b/components/autofill/core/browser/webdata/autofill_table.h
@@ -167,10 +167,10 @@
 //                      with locally stored cards and generating descriptions.
 //   exp_month          Expiration month: 1-12
 //   exp_year           Four-digit year: 2017
-//   billing_address_id The guid string that identifies the local profile which
-//                      is the billing address for this card. Can be null in the
-//                      database, but always returned as an empty string in
-//                      CreditCard. Added in version 67.
+//   billing_address_id The string that identifies the local or server profile
+//                      which is the billing address for this card. Can be null
+//                      in the database, but always returned as an empty string
+//                      in CreditCard. Added in version 67.
 //
 // unmasked_credit_cards
 //                      When a masked credit credit card is unmasked and the
@@ -339,7 +339,7 @@
   virtual bool GetAutofillProfiles(
       std::vector<std::unique_ptr<AutofillProfile>>* profiles);
   virtual bool GetServerProfiles(
-      std::vector<std::unique_ptr<AutofillProfile>>* profiles);
+      std::vector<std::unique_ptr<AutofillProfile>>* profiles) const;
 
   // Sets the server profiles. All old profiles are deleted and replaced with
   // the given ones.
@@ -362,7 +362,7 @@
   virtual bool GetCreditCards(
       std::vector<std::unique_ptr<CreditCard>>* credit_cards);
   virtual bool GetServerCreditCards(
-      std::vector<std::unique_ptr<CreditCard>>* credit_cards);
+      std::vector<std::unique_ptr<CreditCard>>* credit_cards) const;
 
   // Replaces all server credit cards with the given vector. Unmasked cards
   // present in the new list will be preserved (even if the input is MASKED).
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
index de80ecd..8ad4333 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.cc
@@ -12,8 +12,6 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/browser/autofill_profile.h"
-#include "components/autofill/core/browser/credit_card.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_backend.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
@@ -24,6 +22,10 @@
 
 namespace {
 
+// The length of the GUIDs used for local autofill data. It is different than
+// the length used for server autofill data.
+const int kLocalGuidSize = 36;
+
 void* UserDataKey() {
   // Use the address of a static so that COMDAT folding won't ever fold
   // with something else.
@@ -75,6 +77,7 @@
                     base::UTF8ToUTF16(card.name_on_card()));
   result.SetExpirationMonth(card.exp_month());
   result.SetExpirationYear(card.exp_year());
+  result.set_billing_address_id(card.billing_address_id());
   return result;
 }
 
@@ -118,25 +121,6 @@
   return profile;
 }
 
-// Searches for CreditCards with identical server IDs and copies the billing
-// address ID from the existing cards on disk into the new cards from server.
-// The credit card's IDs do not change over time.
-void CopyBillingAddressesFromDisk(AutofillTable* table,
-                                  std::vector<CreditCard>* cards_from_server) {
-  std::vector<std::unique_ptr<CreditCard>> cards_on_disk;
-  table->GetServerCreditCards(&cards_on_disk);
-
-  // The reasons behind brute-force search are explained in SetDataIfChanged.
-  for (const auto& saved_card : cards_on_disk) {
-    for (CreditCard& server_card : *cards_from_server) {
-      if (saved_card->server_id() == server_card.server_id()) {
-        server_card.set_billing_address_id(saved_card->billing_address_id());
-        break;
-      }
-    }
-  }
-}
-
 // This function handles conditionally updating the AutofillTable with either
 // a set of CreditCards or AutocompleteProfiles only when the existing data
 // doesn't match.
@@ -154,7 +138,7 @@
 bool SetDataIfChanged(
     AutofillTable* table,
     const std::vector<Data>& data,
-    bool (AutofillTable::*getter)(std::vector<std::unique_ptr<Data>>*),
+    bool (AutofillTable::*getter)(std::vector<std::unique_ptr<Data>>*) const,
     void (AutofillTable::*setter)(const std::vector<Data>&),
     size_t* prev_item_count) {
   std::vector<std::unique_ptr<Data>> existing_data;
@@ -270,10 +254,12 @@
   flare_ = flare;
 }
 
-syncer::SyncMergeResult AutofillWalletSyncableService::SetSyncData(
-    const syncer::SyncDataList& data_list) {
-  std::vector<CreditCard> wallet_cards;
-  std::vector<AutofillProfile> wallet_addresses;
+// static
+void AutofillWalletSyncableService::PopulateWalletCardsAndAddresses(
+    const syncer::SyncDataList& data_list,
+    std::vector<CreditCard>* wallet_cards,
+    std::vector<AutofillProfile>* wallet_addresses) {
+  std::map<std::string, std::string> ids;
 
   for (const syncer::SyncData& data : data_list) {
     DCHECK_EQ(syncer::AUTOFILL_WALLET_DATA, data.GetDataType());
@@ -281,23 +267,64 @@
         data.GetSpecifics().autofill_wallet();
     if (autofill_specifics.type() ==
         sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD) {
-      wallet_cards.push_back(
+      wallet_cards->push_back(
           CardFromSpecifics(autofill_specifics.masked_card()));
     } else {
       DCHECK_EQ(sync_pb::AutofillWalletSpecifics::POSTAL_ADDRESS,
                 autofill_specifics.type());
-      wallet_addresses.push_back(
+      wallet_addresses->push_back(
           ProfileFromSpecifics(autofill_specifics.address()));
+
+      // Map the sync billing address id to the profile's id.
+      ids[autofill_specifics.address().id()] =
+          wallet_addresses->back().server_id();
     }
   }
 
+  // Set the billing address of the wallet cards to the id of the appropriate
+  // profile.
+  for (CreditCard& card : *wallet_cards) {
+    auto it = ids.find(card.billing_address_id());
+    if (it != ids.end())
+      card.set_billing_address_id(it->second);
+  }
+}
+
+// static
+void AutofillWalletSyncableService::CopyRelevantBillingAddressesFromDisk(
+    const AutofillTable& table,
+    std::vector<CreditCard>* cards_from_server) {
+  std::vector<std::unique_ptr<CreditCard>> cards_on_disk;
+  table.GetServerCreditCards(&cards_on_disk);
+
+  // The reasons behind brute-force search are explained in SetDataIfChanged.
+  for (const auto& saved_card : cards_on_disk) {
+    for (CreditCard& server_card : *cards_from_server) {
+      if (saved_card->server_id() == server_card.server_id()) {
+        // Keep the billing address id of the saved cards only if it points to
+        // a local address.
+        if (saved_card->billing_address_id().length() == kLocalGuidSize) {
+          server_card.set_billing_address_id(saved_card->billing_address_id());
+          break;
+        }
+      }
+    }
+  }
+}
+
+syncer::SyncMergeResult AutofillWalletSyncableService::SetSyncData(
+    const syncer::SyncDataList& data_list) {
+  std::vector<CreditCard> wallet_cards;
+  std::vector<AutofillProfile> wallet_addresses;
+  PopulateWalletCardsAndAddresses(data_list, &wallet_cards, &wallet_addresses);
+
   // Users can set billing address of the server credit card locally, but that
   // information does not propagate to either Chrome Sync or Google Payments
   // server. To preserve user's preferred billing address, copy the billing
   // addresses from disk into |wallet_cards|.
   AutofillTable* table =
       AutofillTable::FromWebDatabase(webdata_backend_->GetDatabase());
-  CopyBillingAddressesFromDisk(table, &wallet_cards);
+  CopyRelevantBillingAddressesFromDisk(*table, &wallet_cards);
 
   // In the common case, the database won't have changed. Committing an update
   // to the database will require at least one DB page write and will schedule
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
index eb4b9e0..03f1311 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h
@@ -8,10 +8,13 @@
 #include "base/macros.h"
 #include "base/supports_user_data.h"
 #include "base/threading/thread_checker.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
 #include "components/sync/model/syncable_service.h"
 
 namespace autofill {
 
+class AutofillTable;
 class AutofillWebDataBackend;
 class AutofillWebDataService;
 
@@ -58,8 +61,33 @@
       const std::string& app_locale);
 
  private:
+  FRIEND_TEST_ALL_PREFIXES(
+      AutofillWalletSyncableServiceTest,
+      CopyRelevantBillingAddressesFromDisk_KeepLocalAddresses);
+  FRIEND_TEST_ALL_PREFIXES(
+      AutofillWalletSyncableServiceTest,
+      CopyRelevantBillingAddressesFromDisk_OverwriteOtherAddresses);
+  FRIEND_TEST_ALL_PREFIXES(
+      AutofillWalletSyncableServiceTest,
+      PopulateWalletCardsAndAddresses_BillingAddressIdTransfer);
+
   syncer::SyncMergeResult SetSyncData(const syncer::SyncDataList& data_list);
 
+  // Populates the wallet cards and addresses from the sync data and uses the
+  // sync data to link the card to its billing address.
+  static void PopulateWalletCardsAndAddresses(
+      const syncer::SyncDataList& data_list,
+      std::vector<CreditCard>* wallet_cards,
+      std::vector<AutofillProfile>* wallet_addresses);
+
+  // Finds the copies of the same credit card from the server and on disk and
+  // overwrites the server version with the billing id saved on disk if it
+  // refers to a local autofill profile. The credit card's IDs do not change
+  // over time.
+  static void CopyRelevantBillingAddressesFromDisk(
+      const AutofillTable& table,
+      std::vector<CreditCard>* cards_from_server);
+
   base::ThreadChecker thread_checker_;
 
   AutofillWebDataBackend* webdata_backend_;  // Weak ref.
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc
new file mode 100644
index 0000000..9561a8b
--- /dev/null
+++ b/components/autofill/core/browser/webdata/autofill_wallet_syncable_service_unittest.cc
@@ -0,0 +1,165 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/webdata/autofill_wallet_syncable_service.h"
+
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "components/autofill/core/browser/autofill_profile.h"
+#include "components/autofill/core/browser/credit_card.h"
+#include "components/autofill/core/browser/webdata/autofill_table.h"
+#include "components/sync/protocol/autofill_specifics.pb.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+namespace {
+
+syncer::SyncData CreateSyncDataForWalletCreditCard(
+    const std::string& id,
+    const std::string& billing_address_id) {
+  sync_pb::EntitySpecifics specifics;
+
+  sync_pb::AutofillWalletSpecifics* wallet_specifics =
+      specifics.mutable_autofill_wallet();
+  wallet_specifics->set_type(
+      sync_pb::AutofillWalletSpecifics_WalletInfoType::
+          AutofillWalletSpecifics_WalletInfoType_MASKED_CREDIT_CARD);
+
+  sync_pb::WalletMaskedCreditCard* card_specifics =
+      wallet_specifics->mutable_masked_card();
+  card_specifics->set_id(id);
+  card_specifics->set_billing_address_id(billing_address_id);
+  return syncer::SyncData::CreateLocalData(id, id, specifics);
+}
+
+syncer::SyncData CreateSyncDataForWalletAddress(const std::string& id) {
+  sync_pb::EntitySpecifics specifics;
+
+  sync_pb::AutofillWalletSpecifics* wallet_specifics =
+      specifics.mutable_autofill_wallet();
+  wallet_specifics->set_type(
+      sync_pb::AutofillWalletSpecifics_WalletInfoType::
+          AutofillWalletSpecifics_WalletInfoType_POSTAL_ADDRESS);
+
+  sync_pb::WalletPostalAddress* address_specifics =
+      wallet_specifics->mutable_address();
+  address_specifics->set_id(id);
+  return syncer::SyncData::CreateLocalData(id, id, specifics);
+}
+
+class TestAutofillTable : public AutofillTable {
+ public:
+  explicit TestAutofillTable(std::vector<CreditCard> cards_on_disk)
+      : cards_on_disk_(cards_on_disk) {}
+
+  ~TestAutofillTable() override {}
+
+  bool GetServerCreditCards(
+      std::vector<std::unique_ptr<CreditCard>>* cards) const override {
+    for (const auto& card_on_disk : cards_on_disk_)
+      cards->push_back(base::MakeUnique<CreditCard>(card_on_disk));
+    return true;
+  }
+
+ private:
+  std::vector<CreditCard> cards_on_disk_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestAutofillTable);
+};
+
+}  // anonymous namespace
+
+// Verify that the link between a card and its billing address from sync is
+// present in the generated Autofill objects.
+TEST(AutofillWalletSyncableServiceTest,
+     PopulateWalletCardsAndAddresses_BillingAddressIdTransfer) {
+  std::vector<CreditCard> wallet_cards;
+  std::vector<AutofillProfile> wallet_addresses;
+  syncer::SyncDataList data_list;
+
+  // Create a Sync data for a card and its billing address.
+  data_list.push_back(CreateSyncDataForWalletAddress("1" /* id */));
+  data_list.push_back(CreateSyncDataForWalletCreditCard(
+      "card1" /* id */, "1" /* billing_address_id */));
+
+  AutofillWalletSyncableService::PopulateWalletCardsAndAddresses(
+      data_list, &wallet_cards, &wallet_addresses);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+  ASSERT_EQ(1U, wallet_addresses.size());
+
+  // Make sure the card's billing address id is equal to the address' server id.
+  EXPECT_EQ(wallet_addresses.back().server_id(),
+            wallet_cards.back().billing_address_id());
+}
+
+// Verify that the billing address id from the card saved on disk is kept if it
+// is a local profile guid.
+TEST(AutofillWalletSyncableServiceTest,
+     CopyRelevantBillingAddressesFromDisk_KeepLocalAddresses) {
+  std::vector<CreditCard> cards_on_disk;
+  std::vector<CreditCard> wallet_cards;
+
+  // Create a local profile to be used as a billing address.
+  AutofillProfile billing_address;
+
+  // Create a card on disk that refers to that local profile as its billing
+  // address.
+  cards_on_disk.push_back(CreditCard());
+  cards_on_disk.back().set_billing_address_id(billing_address.guid());
+
+  // Create a card pulled from wallet with the same id, but a different billing
+  // address id.
+  wallet_cards.push_back(CreditCard(cards_on_disk.back()));
+  wallet_cards.back().set_billing_address_id("1234");
+
+  // Setup the TestAutofillTable with the cards_on_disk.
+  TestAutofillTable table(cards_on_disk);
+
+  AutofillWalletSyncableService::CopyRelevantBillingAddressesFromDisk(
+      table, &wallet_cards);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+
+  // Make sure the wallet card replace its billind address id for the one that
+  // was saved on disk.
+  EXPECT_EQ(cards_on_disk.back().billing_address_id(),
+            wallet_cards.back().billing_address_id());
+}
+
+// Verify that the billing address id from the card saved on disk is overwritten
+// if it does not refer to a local profile.
+TEST(AutofillWalletSyncableServiceTest,
+     CopyRelevantBillingAddressesFromDisk_OverwriteOtherAddresses) {
+  std::string old_billing_id = "1234";
+  std::string new_billing_id = "9876";
+  std::vector<CreditCard> cards_on_disk;
+  std::vector<CreditCard> wallet_cards;
+
+  // Create a card on disk that does not refer to a local profile (which have 36
+  // chars ids).
+  cards_on_disk.push_back(CreditCard());
+  cards_on_disk.back().set_billing_address_id(old_billing_id);
+
+  // Create a card pulled from wallet with the same id, but a different billing
+  // address id.
+  wallet_cards.push_back(CreditCard(cards_on_disk.back()));
+  wallet_cards.back().set_billing_address_id(new_billing_id);
+
+  // Setup the TestAutofillTable with the cards_on_disk.
+  TestAutofillTable table(cards_on_disk);
+
+  AutofillWalletSyncableService::CopyRelevantBillingAddressesFromDisk(
+      table, &wallet_cards);
+
+  ASSERT_EQ(1U, wallet_cards.size());
+
+  // Make sure the local address billing id that was saved on disk did not
+  // replace the new one.
+  EXPECT_EQ(new_billing_id, wallet_cards.back().billing_address_id());
+}
+
+}  // namespace autofill
\ No newline at end of file
diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn
index 4bdcc707..75526469 100644
--- a/components/crash/content/app/BUILD.gn
+++ b/components/crash/content/app/BUILD.gn
@@ -66,6 +66,8 @@
     sources = [
       "crash_switches.cc",
       "crash_switches.h",
+      "fallback_crash_handler_launcher_win.cc",
+      "fallback_crash_handler_launcher_win.h",
       "run_as_crashpad_handler_win.cc",
       "run_as_crashpad_handler_win.h",
     ]
@@ -213,15 +215,20 @@
   testonly = true
   sources = [
     "crash_keys_win_unittest.cc",
+    "fallback_crash_handler_launcher_win_unittest.cc",
   ]
   deps = [
     ":lib",
     "//base",
+    "//base/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
 
   if (is_win) {
-    deps += [ "//breakpad:client" ]
+    deps += [
+      ":run_as_crashpad_handler",
+      "//breakpad:client",
+    ]
   }
 }
diff --git a/components/crash/content/app/fallback_crash_handler_launcher_win.cc b/components/crash/content/app/fallback_crash_handler_launcher_win.cc
new file mode 100644
index 0000000..2bf60ec
--- /dev/null
+++ b/components/crash/content/app/fallback_crash_handler_launcher_win.cc
@@ -0,0 +1,131 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/crash/content/app/fallback_crash_handler_launcher_win.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/win/win_util.h"
+
+namespace crash_reporter {
+
+namespace {
+
+// The number of characters reserved at the tail of the command line for the
+// thread ID parameter.
+const size_t kCommandLineTailSize = 32;
+
+}  // namespace
+
+FallbackCrashHandlerLauncher::FallbackCrashHandlerLauncher() {
+  memset(&exception_pointers_, 0, sizeof(exception_pointers_));
+}
+
+FallbackCrashHandlerLauncher::~FallbackCrashHandlerLauncher() {}
+
+bool FallbackCrashHandlerLauncher::Initialize(
+    const base::CommandLine& program,
+    const base::FilePath& crashpad_database) {
+  // Open an inheritable handle to self. This will be inherited to the handler.
+  const DWORD kAccessMask =
+      PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_DUP_HANDLE;
+  self_process_handle_.Set(
+      OpenProcess(kAccessMask, TRUE, ::GetCurrentProcessId()));
+  if (!self_process_handle_.IsValid())
+    return false;
+
+  // Setup the startup info for inheriting the self process handle into the
+  // fallback crash handler.
+  if (!startup_info_.InitializeProcThreadAttributeList(1))
+    return false;
+
+  HANDLE raw_self_process_handle = self_process_handle_.Get();
+  if (!startup_info_.UpdateProcThreadAttribute(
+          PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &raw_self_process_handle,
+          sizeof(raw_self_process_handle))) {
+    return false;
+  }
+
+  // Build the command line from a copy of the command line passed in.
+  base::CommandLine cmd_line(program);
+  cmd_line.AppendSwitchPath("database", crashpad_database);
+  cmd_line.AppendSwitchASCII(
+      "exception-pointers",
+      base::UintToString(reinterpret_cast<uintptr_t>(&exception_pointers_)));
+  cmd_line.AppendSwitchASCII(
+      "process", base::UintToString(
+                     base::win::HandleToUint32(self_process_handle_.Get())));
+
+  std::wstring str_cmd_line = cmd_line.GetCommandLineString();
+
+  // Append the - for now abortive - thread argument manually.
+  str_cmd_line.append(L" --thread=");
+  // Store the command line string for easy use later.
+  cmd_line_.assign(str_cmd_line.begin(), str_cmd_line.end());
+
+  // Resize the vector to reserve space for the thread ID.
+  cmd_line_.resize(cmd_line_.size() + kCommandLineTailSize, '\0');
+
+  return true;
+}
+
+DWORD FallbackCrashHandlerLauncher::LaunchAndWaitForHandler(
+    EXCEPTION_POINTERS* exception_pointers) {
+  DCHECK(!cmd_line_.empty());
+  DCHECK_EQ('=', cmd_line_[cmd_line_.size() - kCommandLineTailSize - 1]);
+  // This program has crashed. Try and not use anything but the stack.
+
+  // Append the current thread's ID to the command line in-place.
+  int chars_appended = wsprintf(&cmd_line_.back() - kCommandLineTailSize + 1,
+                                L"%d", GetCurrentThreadId());
+  DCHECK_GT(static_cast<int>(kCommandLineTailSize), chars_appended);
+
+  // Copy the exception pointers to our member variable, whose address is
+  // already baked into the command line.
+  exception_pointers_ = *exception_pointers;
+
+  // Launch the pre-cooked command line.
+
+  PROCESS_INFORMATION process_info = {};
+  if (!CreateProcess(nullptr,                       // Application name.
+                     &cmd_line_[0],                 // Command line.
+                     nullptr,                       // Process attributes.
+                     nullptr,                       // Thread attributes.
+                     true,                          // Inherit handles.
+                     0,                             // Creation flags.
+                     nullptr,                       // Environment.
+                     nullptr,                       // Current directory.
+                     startup_info_.startup_info(),  // Startup info.
+                     &process_info)) {
+    return GetLastError();
+  }
+
+  // Wait on the fallback crash handler process. The expectation is that this
+  // will never return, as the fallback crash handler will terminate this
+  // process. For testing, and full-on belt and suspenders, cover for this
+  // returning.
+  DWORD error = WaitForSingleObject(process_info.hProcess, INFINITE);
+  if (error != WAIT_OBJECT_0) {
+    // This should never happen, barring handle abuse.
+    // TODO(siggi): Record an UMA metric here.
+    NOTREACHED();
+    error = GetLastError();
+  } else {
+    // On successful wait, return the exit code of the fallback crash handler
+    // process.
+    if (!GetExitCodeProcess(process_info.hProcess, &error)) {
+      // This should never happen, barring handle abuse.
+      NOTREACHED();
+      error = GetLastError();
+    }
+  }
+
+  // Close the handles returned from CreateProcess.
+  CloseHandle(process_info.hProcess);
+  CloseHandle(process_info.hThread);
+
+  return error;
+}
+
+}  // namespace crash_reporter
diff --git a/components/crash/content/app/fallback_crash_handler_launcher_win.h b/components/crash/content/app/fallback_crash_handler_launcher_win.h
new file mode 100644
index 0000000..96ba9c0
--- /dev/null
+++ b/components/crash/content/app/fallback_crash_handler_launcher_win.h
@@ -0,0 +1,68 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRASH_CONTENT_APP_FALLBACK_CRASH_HANDLER_LAUNCHER_WIN_H_
+#define COMPONENTS_CRASH_CONTENT_APP_FALLBACK_CRASH_HANDLER_LAUNCHER_WIN_H_
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/startup_information.h"
+
+#include <windows.h>
+
+namespace crash_reporter {
+
+// This class is a last-ditch crash handler for the Crashpad handler process.
+// It prepares and stores a command line, ready for dispatching when
+// an exception occurs. Everything needed to call CreateProcess is pre-allocated
+// to minimize the odds of re-faulting due to e.g. tripping over the same issue
+// that caused the initial crash.
+// This is still very much best-effort, as doing anything at all inside a
+// process that's crashed is always going to be iffy^2.
+class FallbackCrashHandlerLauncher {
+ public:
+  FallbackCrashHandlerLauncher();
+  ~FallbackCrashHandlerLauncher();
+
+  // Initializes everything that's needed in LaunchAndWaitForHandler.
+  bool Initialize(const base::CommandLine& program,
+                  const base::FilePath& crashpad_database);
+
+  // Launch the pre-computed command line for the fallback error handler.
+  // The expectation is that this function will never return, as the fallback
+  // error handler should terminate it with the exception code as the process
+  // exit code. The return value from this function is therefore academic in
+  // the normal case.
+  // However, for completeness, this function returns one of:
+  // - The error from CreateProcess if it fails to launch the fallback handler.
+  // - The error from waiting on the fallback crash handler process if it
+  //   fails to wait for that process to exit.
+  // - The exit code from the fallback crash handler process.
+  // - The error encountered in retrieving the crash handler process' exit code.
+  // Note that the return value is used in testing.
+  DWORD LaunchAndWaitForHandler(EXCEPTION_POINTERS* pointers);
+
+ private:
+  // A copy of the actual exception pointers made at time of exception.
+  EXCEPTION_POINTERS exception_pointers_;
+
+  // The precomputed startup info and command line for launching the fallback
+  // handler.
+  base::win::StartupInformation startup_info_;
+  // Stores the pre-cooked command line, with an allotment of zeros at the back
+  // sufficient for writing in the thread id, just before launch.
+  std::vector<wchar_t> cmd_line_;
+
+  // An inheritable handle to our own process, the raw handle is necessary
+  // for pre-computing the startup info.
+  base::win::ScopedHandle self_process_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(FallbackCrashHandlerLauncher);
+};
+
+}  // namespace crash_reporter
+
+#endif  // COMPONENTS_CRASH_CONTENT_APP_FALLBACK_CRASH_HANDLER_LAUNCHER_WIN_H_
diff --git a/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc b/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
new file mode 100644
index 0000000..94dd65b
--- /dev/null
+++ b/components/crash/content/app/fallback_crash_handler_launcher_win_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/crash/content/app/fallback_crash_handler_launcher_win.h"
+
+#include <dbghelp.h>
+
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/win_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace crash_reporter {
+
+namespace {
+
+const wchar_t kFileName[] = L"crash.dmp";
+
+MULTIPROCESS_TEST_MAIN(FallbackCrashHandlerLauncherMain) {
+  base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+
+  // Check for presence of the "process" argument.
+  CHECK(cmd_line->HasSwitch("process"));
+
+  // Retrieve and check the handle to verify that it was inherited in.
+  unsigned int uint_process = 0;
+  CHECK(base::StringToUint(cmd_line->GetSwitchValueASCII("process"),
+                           &uint_process));
+  base::Process process(base::win::Uint32ToHandle(uint_process));
+
+  // Verify that the process handle points to our parent.
+  CHECK_EQ(base::GetParentProcessId(base::GetCurrentProcessHandle()),
+           process.Pid());
+
+  // Check the "thread" argument.
+  CHECK(cmd_line->HasSwitch("thread"));
+
+  // Retrieve the thread id.
+  unsigned int thread_id = 0;
+  CHECK(
+      base::StringToUint(cmd_line->GetSwitchValueASCII("thread"), &thread_id));
+
+  // Check the "exception-pointers" argument.
+  CHECK(cmd_line->HasSwitch("exception-pointers"));
+  uint64_t uint_exc_ptrs = 0;
+  CHECK(base::StringToUint64(
+      cmd_line->GetSwitchValueASCII("exception-pointers"), &uint_exc_ptrs));
+
+  EXCEPTION_POINTERS* exc_ptrs = reinterpret_cast<EXCEPTION_POINTERS*>(
+      static_cast<uintptr_t>(uint_exc_ptrs));
+
+  // Check the "database" argument.
+  CHECK(cmd_line->HasSwitch("database"));
+  base::FilePath database_dir = cmd_line->GetSwitchValuePath("database");
+
+  base::FilePath dump_path = database_dir.Append(kFileName);
+
+  // Create a dump file in the directory.
+  base::File dump(dump_path, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+
+  CHECK(dump.IsValid());
+
+  const MINIDUMP_TYPE kMinidumpType = static_cast<MINIDUMP_TYPE>(
+      MiniDumpWithHandleData | MiniDumpWithUnloadedModules |
+      MiniDumpWithProcessThreadData | MiniDumpWithThreadInfo |
+      MiniDumpWithTokenInformation);
+
+  MINIDUMP_EXCEPTION_INFORMATION exc_info = {};
+  exc_info.ThreadId = thread_id;
+  exc_info.ExceptionPointers = exc_ptrs;
+  exc_info.ClientPointers = TRUE;  // ExceptionPointers in client.
+
+  // Write the minidump as a direct test of the validity and permissions on the
+  // parent handle.
+  if (!MiniDumpWriteDump(process.Handle(),        // Process handle.
+                         process.Pid(),           // Process Id.
+                         dump.GetPlatformFile(),  // File handle.
+                         kMinidumpType,           // Minidump type.
+                         &exc_info,               // Exception Param
+                         nullptr,                 // UserStreamParam,
+                         nullptr)) {              // CallbackParam
+    DWORD error = GetLastError();
+
+    dump.Close();
+    CHECK(base::DeleteFile(dump_path, false));
+    CHECK(false) << "Unable to write dump, error " << error;
+  }
+
+  return 0;
+}
+
+class FallbackCrashHandlerLauncherTest : public base::MultiProcessTest {
+ public:
+  void SetUp() override { ASSERT_TRUE(database_dir_.CreateUniqueTempDir()); }
+
+ protected:
+  base::ScopedTempDir database_dir_;
+};
+
+}  // namespace
+
+TEST_F(FallbackCrashHandlerLauncherTest, LaunchAndWaitForHandler) {
+  base::CommandLine base_cmdline(
+      MakeCmdLine("FallbackCrashHandlerLauncherMain"));
+
+  FallbackCrashHandlerLauncher launcher;
+  ASSERT_TRUE(launcher.Initialize(base_cmdline, database_dir_.GetPath()));
+
+  // Make like an access violation at the current place.
+  EXCEPTION_RECORD exc_record = {};
+  exc_record.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
+  CONTEXT ctx = {};
+  RtlCaptureContext(&ctx);
+
+  EXCEPTION_POINTERS exc_ptrs = {&exc_record, &ctx};
+
+  ASSERT_EQ(0UL, launcher.LaunchAndWaitForHandler(&exc_ptrs));
+
+  // Check that the dump was written, e.g. it's an existing file with non-zero
+  // size.
+  base::File dump(database_dir_.GetPath().Append(kFileName),
+                  base::File::FLAG_OPEN | base::File::FLAG_READ);
+  ASSERT_TRUE(dump.IsValid());
+  ASSERT_NE(0, dump.GetLength());
+}
+
+}  // namespace crash_reporter
diff --git a/components/pageinfo_strings.grdp b/components/pageinfo_strings.grdp
index 36e82573..25baa50 100644
--- a/components/pageinfo_strings.grdp
+++ b/components/pageinfo_strings.grdp
@@ -3,11 +3,8 @@
   <message name="IDS_PAGE_INFO_HELP_CENTER_LINK" desc="This is the text of the link pointing to the Help Center. This appears at the bottom of the SSL dialog and 'this' refers to the sections within the bubble.">
     What do these mean?
   </message>
-  <message name="IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MINOR" desc="The security summary phrase in the page information panel for a security problem where the site's certificate expires in 2016 and contains a SHA1 signature in the chain (as opposed to 2017 or later). Such certificates will not be supported in a future version of Chrome.">
-    The certificate for this site expires in 2016, and the certificate chain contains a certificate signed using SHA-1.
-  </message>
-  <message name="IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR" desc="The security summary phrase in the page information panel for a security problem where the site's certificate expires in 2017 or later and contains a SHA1 signature in the chain (as opposed to 2016). Such certificates will not be supported in a future version of Chrome.">
-    The certificate for this site expires in 2017 or later, and the certificate chain contains a certificate signed using SHA-1.
+  <message name="IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM" desc="The security summary phrase in the page information panel for a security problem where the site's certificate chain contains a SHA1 signature. Such certificates are treated as errors except when a policy override is present.">
+    The certificate chain for this site contains a certificate signed using SHA-1.
   </message>
   <message name="IDS_PAGE_INFO_SECURITY_TAB_ENCRYPTED_CONNECTION_TEXT" desc="The text of the connection section when the connection is encrypted.">
     Your connection to <ph name="DOMAIN">$1<ex>www.google.com</ex></ph> is encrypted using a modern cipher suite.
diff --git a/components/security_state/content/content_utils.cc b/components/security_state/content/content_utils.cc
index ec7b804..71b9d1c 100644
--- a/components/security_state/content/content_utils.cc
+++ b/components/security_state/content/content_utils.cc
@@ -230,19 +230,11 @@
     return security_style;
   }
 
-  if (security_info.sha1_deprecation_status ==
-      security_state::DEPRECATED_SHA1_MAJOR) {
-    security_style_explanations->broken_explanations.push_back(
-        content::SecurityStyleExplanation(
-            l10n_util::GetStringUTF8(IDS_MAJOR_SHA1),
-            l10n_util::GetStringUTF8(IDS_MAJOR_SHA1_DESCRIPTION),
-            !!security_info.certificate));
-  } else if (security_info.sha1_deprecation_status ==
-             security_state::DEPRECATED_SHA1_MINOR) {
+  if (security_info.sha1_in_chain) {
     security_style_explanations->unauthenticated_explanations.push_back(
         content::SecurityStyleExplanation(
-            l10n_util::GetStringUTF8(IDS_MINOR_SHA1),
-            l10n_util::GetStringUTF8(IDS_MINOR_SHA1_DESCRIPTION),
+            l10n_util::GetStringUTF8(IDS_SHA1),
+            l10n_util::GetStringUTF8(IDS_SHA1_DESCRIPTION),
             !!security_info.certificate));
   }
 
@@ -299,11 +291,9 @@
       security_style_explanations->broken_explanations.push_back(explanation);
     }
   } else {
-    // If the certificate does not have errors and is not using
-    // deprecated SHA1, then add an explanation that the certificate is
-    // valid.
-    if (security_info.sha1_deprecation_status ==
-        security_state::NO_DEPRECATED_SHA1) {
+    // If the certificate does not have errors and is not using SHA1, then add
+    // an explanation that the certificate is valid.
+    if (!security_info.sha1_in_chain) {
       security_style_explanations->secure_explanations.push_back(
           content::SecurityStyleExplanation(
               l10n_util::GetStringUTF8(IDS_VALID_SERVER_CERTIFICATE),
diff --git a/components/security_state/core/security_state.cc b/components/security_state/core/security_state.cc
index ef7e0a8..d5e867ed 100644
--- a/components/security_state/core/security_state.cc
+++ b/components/security_state/core/security_state.cc
@@ -84,27 +84,6 @@
   return level;
 }
 
-SHA1DeprecationStatus GetSHA1DeprecationStatus(
-    const VisibleSecurityState& visible_security_state) {
-  if (!visible_security_state.certificate ||
-      !(visible_security_state.cert_status &
-        net::CERT_STATUS_SHA1_SIGNATURE_PRESENT))
-    return NO_DEPRECATED_SHA1;
-
-  // The internal representation of the dates for UI treatment of SHA-1.
-  // See http://crbug.com/401365 for details.
-  static const int64_t kJanuary2017 = INT64_C(13127702400000000);
-  if (visible_security_state.certificate->valid_expiry() >=
-      base::Time::FromInternalValue(kJanuary2017))
-    return DEPRECATED_SHA1_MAJOR;
-  static const int64_t kJanuary2016 = INT64_C(13096080000000000);
-  if (visible_security_state.certificate->valid_expiry() >=
-      base::Time::FromInternalValue(kJanuary2016))
-    return DEPRECATED_SHA1_MINOR;
-
-  return NO_DEPRECATED_SHA1;
-}
-
 ContentStatus GetContentStatus(bool displayed, bool ran) {
   if (ran && displayed)
     return CONTENT_STATUS_DISPLAYED_AND_RAN;
@@ -119,7 +98,7 @@
     const VisibleSecurityState& visible_security_state,
     bool used_policy_installed_certificate,
     const IsOriginSecureCallback& is_origin_secure_callback,
-    SHA1DeprecationStatus sha1_status,
+    bool sha1_in_chain,
     ContentStatus mixed_content_status,
     ContentStatus content_with_cert_errors_status) {
   DCHECK(visible_security_state.connection_info_initialized ||
@@ -172,14 +151,10 @@
     return SECURE_WITH_POLICY_INSTALLED_CERT;
 
   // In most cases, SHA1 use is treated as a certificate error, in which case
-  // DANGEROUS will have been returned above. If SHA1 is permitted, we downgrade
-  // the security level to Neutral or Dangerous depending on policy.
-  if (sha1_status == DEPRECATED_SHA1_MAJOR ||
-      sha1_status == DEPRECATED_SHA1_MINOR) {
-    return (visible_security_state.display_sha1_from_local_anchors_as_neutral)
-               ? NONE
-               : DANGEROUS;
-  }
+  // DANGEROUS will have been returned above. If SHA1 was permitted by policy,
+  // downgrade the security level to Neutral.
+  if (sha1_in_chain)
+    return NONE;
 
   // Active mixed content is handled above.
   DCHECK_NE(CONTENT_STATUS_RAN, mixed_content_status);
@@ -216,14 +191,16 @@
         MALICIOUS_CONTENT_STATUS_NONE) {
       security_info->security_level = GetSecurityLevelForRequest(
           visible_security_state, used_policy_installed_certificate,
-          is_origin_secure_callback, UNKNOWN_SHA1, CONTENT_STATUS_UNKNOWN,
+          is_origin_secure_callback, false, CONTENT_STATUS_UNKNOWN,
           CONTENT_STATUS_UNKNOWN);
     }
     return;
   }
   security_info->certificate = visible_security_state.certificate;
-  security_info->sha1_deprecation_status =
-      GetSHA1DeprecationStatus(visible_security_state);
+
+  security_info->sha1_in_chain = visible_security_state.certificate &&
+                                 (visible_security_state.cert_status &
+                                  net::CERT_STATUS_SHA1_SIGNATURE_PRESENT);
   security_info->mixed_content_status =
       GetContentStatus(visible_security_state.displayed_mixed_content,
                        visible_security_state.ran_mixed_content);
@@ -252,7 +229,7 @@
 
   security_info->security_level = GetSecurityLevelForRequest(
       visible_security_state, used_policy_installed_certificate,
-      is_origin_secure_callback, security_info->sha1_deprecation_status,
+      is_origin_secure_callback, security_info->sha1_in_chain,
       security_info->mixed_content_status,
       security_info->content_with_cert_errors_status);
 }
@@ -265,7 +242,7 @@
 SecurityInfo::SecurityInfo()
     : security_level(NONE),
       malicious_content_status(MALICIOUS_CONTENT_STATUS_NONE),
-      sha1_deprecation_status(NO_DEPRECATED_SHA1),
+      sha1_in_chain(false),
       mixed_content_status(CONTENT_STATUS_NONE),
       content_with_cert_errors_status(CONTENT_STATUS_NONE),
       scheme_is_cryptographic(false),
@@ -307,8 +284,7 @@
       ran_content_with_cert_errors(false),
       pkp_bypassed(false),
       displayed_password_field_on_http(false),
-      displayed_credit_card_field_on_http(false),
-      display_sha1_from_local_anchors_as_neutral(false) {}
+      displayed_credit_card_field_on_http(false) {}
 
 VisibleSecurityState::~VisibleSecurityState() {}
 
@@ -330,9 +306,7 @@
           displayed_password_field_on_http ==
               other.displayed_password_field_on_http &&
           displayed_credit_card_field_on_http ==
-              other.displayed_credit_card_field_on_http &&
-          display_sha1_from_local_anchors_as_neutral ==
-              other.display_sha1_from_local_anchors_as_neutral);
+              other.displayed_credit_card_field_on_http);
 }
 
 }  // namespace security_state
diff --git a/components/security_state/core/security_state.h b/components/security_state/core/security_state.h
index 62b1806..7de0fa74 100644
--- a/components/security_state/core/security_state.h
+++ b/components/security_state/core/security_state.h
@@ -68,22 +68,6 @@
   DANGEROUS,
 };
 
-// Describes how the SHA1 deprecation policy applies to an HTTPS
-// connection.
-enum SHA1DeprecationStatus {
-  UNKNOWN_SHA1,
-  // No SHA1 deprecation policy applies.
-  NO_DEPRECATED_SHA1,
-  // The connection used a certificate with a SHA1 signature in the
-  // chain, and policy says that the connection should be treated with a
-  // warning.
-  DEPRECATED_SHA1_MINOR,
-  // The connection used a certificate with a SHA1 signature in the
-  // chain, and policy says that the connection should be treated as
-  // broken HTTPS.
-  DEPRECATED_SHA1_MAJOR,
-};
-
 // The ContentStatus enum is used to describe content on the page that
 // has significantly different security properties than the main page
 // load. Content can be passive content that is displayed (such as
@@ -117,7 +101,8 @@
   SecurityLevel security_level;
   // Describes the nature of the page's malicious content, if any.
   MaliciousContentStatus malicious_content_status;
-  SHA1DeprecationStatus sha1_deprecation_status;
+  // True if a SHA1 signature was observed anywhere in the certificate chain.
+  bool sha1_in_chain;
   // |mixed_content_status| describes the presence of content that was
   // loaded over a nonsecure (HTTP) connection.
   ContentStatus mixed_content_status;
@@ -198,10 +183,6 @@
   bool displayed_password_field_on_http;
   // True if the page was an HTTP page that displayed a credit card field.
   bool displayed_credit_card_field_on_http;
-  // True if Enterprise Policy configured to display as neutral all SHA-1 chains
-  // to a local trust anchor.
-  // TODO(elawrence): remove this in M57, https://crbug.com/676826
-  bool display_sha1_from_local_anchors_as_neutral;
 };
 
 // These security levels describe the treatment given to pages that
diff --git a/components/security_state/core/security_state_unittest.cc b/components/security_state/core/security_state_unittest.cc
index 4e4aa70..f6a899cf 100644
--- a/components/security_state/core/security_state_unittest.cc
+++ b/components/security_state/core/security_state_unittest.cc
@@ -115,44 +115,56 @@
 
 }  // namespace
 
-// Tests that SHA1-signed certificates expiring in 2016 downgrade the
-// security state of the page.
+// Tests that SHA1-signed certificates, when not allowed by policy, downgrade
+// the security state of the page to DANGEROUS.
+TEST(SecurityStateTest, SHA1Blocked) {
+  TestSecurityStateHelper helper;
+  helper.AddCertStatus(net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
+  helper.AddCertStatus(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT);
+  SecurityInfo security_info;
+  helper.GetSecurityInfo(&security_info);
+  EXPECT_TRUE(security_info.sha1_in_chain);
+  EXPECT_EQ(DANGEROUS, security_info.security_level);
+}
+
+// Tests that SHA1-signed certificates, when allowed by policy, downgrade the
+// security state of the page to NONE.
 TEST(SecurityStateTest, SHA1Warning) {
   TestSecurityStateHelper helper;
   SecurityInfo security_info;
   helper.GetSecurityInfo(&security_info);
-  EXPECT_EQ(DEPRECATED_SHA1_MINOR, security_info.sha1_deprecation_status);
-  EXPECT_EQ(DANGEROUS, security_info.security_level);
+  EXPECT_TRUE(security_info.sha1_in_chain);
+  EXPECT_EQ(NONE, security_info.security_level);
 }
 
-// Tests that SHA1 warnings don't interfere with the handling of mixed
-// content.
+// Tests that SHA1-signed certificates, when allowed by policy, don't interfere
+// with the handling of mixed content.
 TEST(SecurityStateTest, SHA1WarningMixedContent) {
   TestSecurityStateHelper helper;
   helper.SetDisplayedMixedContent(true);
   SecurityInfo security_info1;
   helper.GetSecurityInfo(&security_info1);
-  EXPECT_EQ(DEPRECATED_SHA1_MINOR, security_info1.sha1_deprecation_status);
+  EXPECT_TRUE(security_info1.sha1_in_chain);
   EXPECT_EQ(CONTENT_STATUS_DISPLAYED, security_info1.mixed_content_status);
-  EXPECT_EQ(DANGEROUS, security_info1.security_level);
+  EXPECT_EQ(NONE, security_info1.security_level);
 
   helper.SetDisplayedMixedContent(false);
   helper.SetRanMixedContent(true);
   SecurityInfo security_info2;
   helper.GetSecurityInfo(&security_info2);
-  EXPECT_EQ(DEPRECATED_SHA1_MINOR, security_info2.sha1_deprecation_status);
+  EXPECT_TRUE(security_info2.sha1_in_chain);
   EXPECT_EQ(CONTENT_STATUS_RAN, security_info2.mixed_content_status);
   EXPECT_EQ(DANGEROUS, security_info2.security_level);
 }
 
-// Tests that SHA1 warnings don't interfere with the handling of major
-// cert errors.
+// Tests that SHA1-signed certificates, when allowed by policy,
+// don't interfere with the handling of major cert errors.
 TEST(SecurityStateTest, SHA1WarningBrokenHTTPS) {
   TestSecurityStateHelper helper;
   helper.AddCertStatus(net::CERT_STATUS_DATE_INVALID);
   SecurityInfo security_info;
   helper.GetSecurityInfo(&security_info);
-  EXPECT_EQ(DEPRECATED_SHA1_MINOR, security_info.sha1_deprecation_status);
+  EXPECT_TRUE(security_info.sha1_in_chain);
   EXPECT_EQ(DANGEROUS, security_info.security_level);
 }
 
diff --git a/components/security_state_strings.grdp b/components/security_state_strings.grdp
index 99337fe..a193d68 100644
--- a/components/security_state_strings.grdp
+++ b/components/security_state_strings.grdp
@@ -7,17 +7,11 @@
   <message name="IDS_SAFEBROWSING_WARNING" desc="Summary phrase for a security problem where the site is deemed unsafe by the SafeBrowsing service." translateable="false">
     This page is dangerous (flagged by Google Safe Browsing).
   </message>
-  <message name="IDS_MAJOR_SHA1" desc="Summary phrase for a security problem where the site's certificate expires in 2017 or later and contains a SHA1 signature in the chain." translateable="false">
+  <message name="IDS_SHA1" desc="Summary phrase for a security problem where the site's certificate chain contains a SHA1 signature." translateable="false">
     SHA-1 Certificate
   </message>
-  <message name="IDS_MAJOR_SHA1_DESCRIPTION" desc="Description of a security problem where the site's certificate expires in 2017 or later and contains a SHA1 signature in the chain." translateable="false">
-    The certificate for this site expires in 2017 or later, and the certificate chain contains a certificate signed using SHA-1.
-  </message>
-  <message name="IDS_MINOR_SHA1" desc="Summary phrase for a security problem where the site's certificate expires in 2016 and contains a SHA1 signature in the chain." translateable="false">
-    SHA-1 Certificate
-  </message>
-  <message name="IDS_MINOR_SHA1_DESCRIPTION" desc="Description of a security problem where the site's certificate expires in 2016 and contains a SHA1 signature in the chain." translateable="false">
-    The certificate for this site expires in 2016, and the certificate chain contains a certificate signed using SHA-1.
+  <message name="IDS_SHA1_DESCRIPTION" desc="Description of a security problem where the site's certificate chain contains a SHA1 signature." translateable="false">
+    The certificate chain for this site contains a certificate signed using SHA-1.
   </message>
   <message name="IDS_CERTIFICATE_CHAIN_ERROR" desc="Summary phrase for a security problem with the site's certificate." translateable="false">
     Certificate Error
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index d57ddbe..916302e9 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1053,6 +1053,7 @@
         // redirecting the FILE thread on Windows. http://crbug.com/662122
         thread_to_start = &file_thread_;
         options = ui_message_loop_options;
+        options.timer_slack = base::TIMER_SLACK_MAXIMUM;
 #else
         if (redirect_nonUInonIO_browser_threads) {
           non_ui_non_io_task_runner_traits
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index 459fc3c..2b89f6d 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -356,7 +356,8 @@
   DCHECK_EQ(globals.states[identifier], BrowserThreadState::SHUTDOWN);
   globals.states[identifier] = BrowserThreadState::UNINITIALIZED;
   globals.task_runners[identifier] = nullptr;
-  SetIOThreadDelegate(nullptr);
+  if (identifier == BrowserThread::IO)
+    SetIOThreadDelegate(nullptr);
 }
 
 BrowserThreadImpl::~BrowserThreadImpl() {
diff --git a/content/browser/media/session/audio_focus_delegate_android.cc b/content/browser/media/session/audio_focus_delegate_android.cc
index dfaba7d..07f0a8e 100644
--- a/content/browser/media/session/audio_focus_delegate_android.cc
+++ b/content/browser/media/session/audio_focus_delegate_android.cc
@@ -53,19 +53,11 @@
 }
 
 void AudioFocusDelegateAndroid::OnSuspend(JNIEnv*,
-                                          const JavaParamRef<jobject>&,
-                                          jboolean temporary) {
-  // TODO(mlamouri): this check makes it so that if a MediaSession is paused and
-  // then loses audio focus, it will still stay in the Suspended state.
-  // See https://crbug.com/539998
+                                          const JavaParamRef<jobject>&) {
   if (!media_session_->IsActive())
     return;
 
-  if (temporary) {
-    media_session_->Suspend(MediaSession::SuspendType::SYSTEM);
-  } else {
-    media_session_->Stop(MediaSession::SuspendType::SYSTEM);
-  }
+  media_session_->Suspend(MediaSession::SuspendType::SYSTEM);
 }
 
 void AudioFocusDelegateAndroid::OnResume(JNIEnv*,
diff --git a/content/browser/media/session/audio_focus_delegate_android.h b/content/browser/media/session/audio_focus_delegate_android.h
index 31a48dd..b888b50 100644
--- a/content/browser/media/session/audio_focus_delegate_android.h
+++ b/content/browser/media/session/audio_focus_delegate_android.h
@@ -29,9 +29,7 @@
 
   // Called when the Android system requests the MediaSession to be suspended.
   // Called by Java through JNI.
-  void OnSuspend(JNIEnv* env,
-                 const base::android::JavaParamRef<jobject>& obj,
-                 jboolean temporary);
+  void OnSuspend(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
 
   // Called when the Android system requests the MediaSession to be resumed.
   // Called by Java through JNI.
diff --git a/content/browser/service_worker/service_worker_browsertest.cc b/content/browser/service_worker/service_worker_browsertest.cc
index 02af1cc..1c423d0 100644
--- a/content/browser/service_worker/service_worker_browsertest.cc
+++ b/content/browser/service_worker/service_worker_browsertest.cc
@@ -534,8 +534,6 @@
   void ActivateTestHelper(
       const std::string& worker_url,
       ServiceWorkerStatusCode expected_status) {
-    RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread,
-                             base::Unretained(this), worker_url));
     ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
     base::RunLoop run_loop;
     BrowserThread::PostTask(
@@ -775,9 +773,6 @@
   void ActivateOnIOThread(const base::Closure& done,
                           ServiceWorkerStatusCode* result) {
     ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
-    version_->set_fetch_handler_existence(
-        ServiceWorkerVersion::FetchHandlerExistence::EXISTS);
-    version_->SetMainScriptHttpResponseInfo(CreateHttpResponseInfo());
     version_->SetStatus(ServiceWorkerVersion::ACTIVATING);
     registration_->SetActiveVersion(version_.get());
     version_->RunAfterStartWorker(
@@ -935,17 +930,8 @@
                        ReadResourceFailure_WaitingWorker) {
   StartServerAndNavigateToSetup();
   // Create a registration and active version.
-  RunOnIOThread(base::Bind(&self::SetUpRegistrationOnIOThread,
-                           base::Unretained(this),
-                           "/service_worker/worker.js"));
-  base::RunLoop activate_run_loop;
-  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&self::ActivateOnIOThread, base::Unretained(this),
-                 activate_run_loop.QuitClosure(), &status));
-  activate_run_loop.Run();
-  EXPECT_EQ(SERVICE_WORKER_OK, status);
+  InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
+  ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
   ASSERT_TRUE(registration_->active_version());
 
   // Give the version a controllee.
@@ -953,15 +939,15 @@
       base::Bind(&self::AddControlleeOnIOThread, base::Unretained(this)));
 
   // Add a non-existent resource to the version.
-  std::vector<ServiceWorkerDatabase::ResourceRecord> records;
-  records.push_back(
-      ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100));
-  version_->script_cache_map()->SetResources(records);
+  version_->script_cache_map()->resource_map_[version_->script_url()] =
+      ServiceWorkerDatabase::ResourceRecord(30, version_->script_url(), 100);
 
   // Make a waiting version and store it.
   RunOnIOThread(base::Bind(&self::AddWaitingWorkerOnIOThread,
                            base::Unretained(this),
                            "/service_worker/worker.js"));
+  std::vector<ServiceWorkerDatabase::ResourceRecord> records = {
+      ServiceWorkerDatabase::ResourceRecord(31, version_->script_url(), 100)};
   registration_->waiting_version()->script_cache_map()->SetResources(records);
   StoreRegistration(registration_->waiting_version()->version_id(),
                     SERVICE_WORKER_OK);
@@ -1022,12 +1008,15 @@
 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest,
                        Activate_NoEventListener) {
   StartServerAndNavigateToSetup();
+  InstallTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
   ActivateTestHelper("/service_worker/worker.js", SERVICE_WORKER_OK);
   ASSERT_EQ(ServiceWorkerVersion::ACTIVATING, version_->status());
 }
 
 IN_PROC_BROWSER_TEST_F(ServiceWorkerVersionBrowserTest, Activate_Rejected) {
   StartServerAndNavigateToSetup();
+  InstallTestHelper("/service_worker/worker_activate_rejected.js",
+                    SERVICE_WORKER_OK);
   ActivateTestHelper("/service_worker/worker_activate_rejected.js",
                      SERVICE_WORKER_ERROR_EVENT_WAITUNTIL_REJECTED);
 }
@@ -1164,6 +1153,7 @@
   ServiceWorkerFetchEventResult result;
   ServiceWorkerResponse response;
   std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
+  InstallTestHelper("/service_worker/fetch_event.js", SERVICE_WORKER_OK);
   ActivateTestHelper("/service_worker/fetch_event.js", SERVICE_WORKER_OK);
 
   FetchOnRegisteredWorker(&result, &response, &blob_data_handle);
@@ -1190,6 +1180,8 @@
   ServiceWorkerResponse response2;
   std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
   const base::Time start_time(base::Time::Now());
+  InstallTestHelper("/service_worker/fetch_event_response_via_cache.js",
+                    SERVICE_WORKER_OK);
   ActivateTestHelper("/service_worker/fetch_event_response_via_cache.js",
                      SERVICE_WORKER_OK);
 
@@ -1216,6 +1208,8 @@
   ServiceWorkerFetchEventResult result;
   ServiceWorkerResponse response;
   std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
+  InstallTestHelper("/service_worker/fetch_event_rejected.js",
+                    SERVICE_WORKER_OK);
   ActivateTestHelper("/service_worker/fetch_event_rejected.js",
                      SERVICE_WORKER_OK);
 
@@ -2552,15 +2546,6 @@
   // OnCachedMetadataUpdated() is called.
   cached_metadata_run_loop.Run();
 
-  // Activate the worker.
-  ServiceWorkerStatusCode status = SERVICE_WORKER_ERROR_FAILED;
-  base::RunLoop activate_run_loop;
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&self::ActivateOnIOThread, base::Unretained(this),
-                 activate_run_loop.QuitClosure(), &status));
-  activate_run_loop.Run();
-  ASSERT_EQ(SERVICE_WORKER_OK, status);
   // Stop the worker.
   StopWorker(SERVICE_WORKER_OK);
   // Restart the worker.
@@ -2990,6 +2975,7 @@
 IN_PROC_BROWSER_TEST_F(MemoryCoordinatorWithServiceWorkerTest,
                        CannotSuspendRendererWithServiceWorker) {
   StartServerAndNavigateToSetup();
+  InstallTestHelper("/service_worker/fetch_event.js", SERVICE_WORKER_OK);
   ActivateTestHelper("/service_worker/fetch_event.js", SERVICE_WORKER_OK);
 
   MemoryCoordinatorImpl* memory_coordinator =
diff --git a/content/browser/service_worker/service_worker_context_request_handler.cc b/content/browser/service_worker/service_worker_context_request_handler.cc
index 39250cd..ed72f5f 100644
--- a/content/browser/service_worker/service_worker_context_request_handler.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler.cc
@@ -11,13 +11,36 @@
 #include "content/browser/service_worker/service_worker_storage.h"
 #include "content/browser/service_worker/service_worker_version.h"
 #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
-#include "content/public/browser/resource_context.h"
 #include "content/public/common/resource_response_info.h"
 #include "net/base/load_flags.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
 #include "net/url_request/url_request.h"
+#include "net/url_request/url_request_error_job.h"
 
 namespace content {
 
+namespace {
+
+bool IsInstalled(const ServiceWorkerVersion* version) {
+  switch (version->status()) {
+    case ServiceWorkerVersion::NEW:
+    case ServiceWorkerVersion::INSTALLING:
+      return false;
+    case ServiceWorkerVersion::INSTALLED:
+    case ServiceWorkerVersion::ACTIVATING:
+    case ServiceWorkerVersion::ACTIVATED:
+      return true;
+    case ServiceWorkerVersion::REDUNDANT:
+      return false;
+  }
+  NOTREACHED();
+  return false;
+}
+
+}  // namespace
+
 ServiceWorkerContextRequestHandler::ServiceWorkerContextRequestHandler(
     base::WeakPtr<ServiceWorkerContextCore> context,
     base::WeakPtr<ServiceWorkerProviderHost> provider_host,
@@ -36,129 +59,186 @@
 ServiceWorkerContextRequestHandler::~ServiceWorkerContextRequestHandler() {
 }
 
+// static
+std::string ServiceWorkerContextRequestHandler::CreateJobStatusToString(
+    CreateJobStatus status) {
+  switch (status) {
+    case CreateJobStatus::UNINITIALIZED:
+      return "UNINITIALIZED";
+    case CreateJobStatus::WRITE_JOB_FOR_REGISTER:
+      return "WRITE_JOB_FOR_REGISTER";
+    case CreateJobStatus::WRITE_JOB_FOR_UPDATE:
+      return "WRITE_JOB_FOR_UPDATE";
+    case CreateJobStatus::READ_JOB:
+      return "READ_JOB";
+    case CreateJobStatus::READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT:
+      return "READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT";
+    case CreateJobStatus::ERROR_NO_PROVIDER:
+      return "ERROR_NO_PROVIDER";
+    case CreateJobStatus::ERROR_NO_VERSION:
+      return "ERROR_NO_VERSION";
+    case CreateJobStatus::ERROR_REDUNDANT_VERSION:
+      return "ERROR_REDUNDANT_VERSION";
+    case CreateJobStatus::ERROR_NO_CONTEXT:
+      return "ERROR_NO_CONTEXT";
+    case CreateJobStatus::ERROR_REDIRECT:
+      return "ERROR_REDIRECT";
+    case CreateJobStatus::ERROR_UNINSTALLED_SCRIPT_IMPORT:
+      return "ERROR_UNINSTALLED_SCRIPT_IMPORT";
+    case CreateJobStatus::ERROR_OUT_OF_RESOURCE_IDS:
+      return "ERROR_OUT_OF_RESOURCE_IDS";
+    case CreateJobStatus::NUM_TYPES:
+      NOTREACHED();
+  }
+  NOTREACHED() << static_cast<int>(status);
+  return "UNKNOWN";
+}
+
 net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJob(
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate,
     ResourceContext* resource_context) {
-  CreateJobStatus status = CreateJobStatus::DID_NOT_SET_STATUS;
-  net::URLRequestJob* job =
-      MaybeCreateJobImpl(&status, request, network_delegate, resource_context);
-  if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER) {
-    version_->NotifyMainScriptJobCreated(status);
+  // We only use the script cache for main script loading and
+  // importScripts(), even if a cached script is xhr'd, we don't
+  // retrieve it from the script cache.
+  // TODO(falken): Get the desired behavior clarified in the spec,
+  // and make tweak the behavior here to match.
+  if (resource_type_ != RESOURCE_TYPE_SERVICE_WORKER &&
+      resource_type_ != RESOURCE_TYPE_SCRIPT) {
+    // Fall back to network.
+    return nullptr;
   }
-  return job;
+
+  CreateJobStatus status = CreateJobStatus::UNINITIALIZED;
+  net::URLRequestJob* job =
+      MaybeCreateJobImpl(request, network_delegate, &status);
+  const bool is_main_script = resource_type_ == RESOURCE_TYPE_SERVICE_WORKER;
+  // TODO(falken): Add UMA for CreateJobStatus.
+  if (is_main_script)
+    version_->NotifyMainScriptJobCreated(status);
+  if (job)
+    return job;
+
+  // If we got here, a job couldn't be created. Return an error job rather than
+  // falling back to network. Otherwise the renderer may receive the response
+  // from network and start a service worker whose browser-side
+  // ServiceWorkerVersion is not properly initialized.
+  //
+  // As an exception, allow installed service workers to use importScripts()
+  // to import non-installed scripts.
+  // TODO(falken): This is a spec violation that should be deprecated and
+  // removed. See https://github.com/w3c/ServiceWorker/issues/1021
+  if (status == CreateJobStatus::ERROR_UNINSTALLED_SCRIPT_IMPORT) {
+    // Fall back to network.
+    return nullptr;
+  }
+
+  std::string error_str(CreateJobStatusToString(status));
+  request->net_log().AddEvent(
+      net::NetLogEventType::SERVICE_WORKER_SCRIPT_LOAD_UNHANDLED_REQUEST_ERROR,
+      net::NetLog::StringCallback("error", &error_str));
+
+  return new net::URLRequestErrorJob(request, network_delegate,
+                                     net::Error::ERR_FAILED);
 }
 
 net::URLRequestJob* ServiceWorkerContextRequestHandler::MaybeCreateJobImpl(
-    CreateJobStatus* out_status,
     net::URLRequest* request,
     net::NetworkDelegate* network_delegate,
-    ResourceContext* resource_context) {
+    CreateJobStatus* out_status) {
   if (!provider_host_) {
-    *out_status = CreateJobStatus::NO_PROVIDER;
-    return nullptr;
-  }
-  if (!version_) {
-    *out_status = CreateJobStatus::NO_VERSION;
+    *out_status = CreateJobStatus::ERROR_NO_PROVIDER;
     return nullptr;
   }
   if (!context_) {
-    *out_status = CreateJobStatus::NO_CONTEXT;
+    *out_status = CreateJobStatus::ERROR_NO_CONTEXT;
+    return nullptr;
+  }
+  if (!version_) {
+    *out_status = CreateJobStatus::ERROR_NO_VERSION;
+    return nullptr;
+  }
+  // This could happen if browser-side has set the status to redundant but the
+  // worker has not yet stopped. The worker is already doomed so just reject the
+  // request. Handle it specially here because otherwise it'd be unclear whether
+  // "REDUNDANT" should count as installed or not installed when making
+  // decisions about how to handle the request and logging UMA.
+  if (version_->status() == ServiceWorkerVersion::REDUNDANT) {
+    *out_status = CreateJobStatus::ERROR_REDUNDANT_VERSION;
     return nullptr;
   }
 
   // We currently have no use case for hijacking a redirected request.
   if (request->url_chain().size() > 1) {
-    *out_status = CreateJobStatus::IGNORE_REDIRECT;
+    *out_status = CreateJobStatus::ERROR_REDIRECT;
     return nullptr;
   }
 
-  // We only use the script cache for main script loading and
-  // importScripts(), even if a cached script is xhr'd, we don't
-  // retrieve it from the script cache.
-  // TODO(michaeln): Get the desired behavior clarified in the spec,
-  // and make tweak the behavior here to match.
-  if (resource_type_ != RESOURCE_TYPE_SERVICE_WORKER &&
-      resource_type_ != RESOURCE_TYPE_SCRIPT) {
-    *out_status = CreateJobStatus::IGNORE_NON_SCRIPT;
-    return nullptr;
-  }
-
-  if (ShouldAddToScriptCache(request->url())) {
-    ServiceWorkerRegistration* registration =
-        context_->GetLiveRegistration(version_->registration_id());
-    DCHECK(registration);  // We're registering or updating so must be there.
-
-    int64_t resource_id = context_->storage()->NewResourceId();
-    if (resource_id == kInvalidServiceWorkerResourceId) {
-      *out_status = CreateJobStatus::OUT_OF_RESOURCE_IDS;
-      return nullptr;
+  const bool is_main_script = resource_type_ == RESOURCE_TYPE_SERVICE_WORKER;
+  int resource_id =
+      version_->script_cache_map()->LookupResourceId(request->url());
+  if (resource_id != kInvalidServiceWorkerResourceId) {
+    if (IsInstalled(version_.get())) {
+      // An installed worker is loading a stored script.
+      if (is_main_script)
+        version_->embedded_worker()->OnURLJobCreatedForMainScript();
+      *out_status = CreateJobStatus::READ_JOB;
+    } else {
+      // A new worker is loading a stored script. The script was already
+      // imported (or the main script is being recursively imported).
+      *out_status = CreateJobStatus::READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT;
     }
-
-    // Bypass the browser cache for initial installs and update
-    // checks after 24 hours have passed.
-    int extra_load_flags = 0;
-    base::TimeDelta time_since_last_check =
-        base::Time::Now() - registration->last_update_check();
-    if (time_since_last_check > base::TimeDelta::FromHours(
-                                    kServiceWorkerScriptMaxCacheAgeInHours) ||
-        version_->force_bypass_cache_for_scripts()) {
-      extra_load_flags = net::LOAD_BYPASS_CACHE;
-    }
-
-    ServiceWorkerVersion* stored_version = registration->waiting_version()
-                                               ? registration->waiting_version()
-                                               : registration->active_version();
-    int64_t incumbent_resource_id = kInvalidServiceWorkerResourceId;
-    if (stored_version && stored_version->script_url() == request->url()) {
-      incumbent_resource_id =
-          stored_version->script_cache_map()->LookupResourceId(request->url());
-    }
-    if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER)
-      version_->embedded_worker()->OnURLJobCreatedForMainScript();
-    *out_status = incumbent_resource_id == kInvalidServiceWorkerResourceId
-                      ? CreateJobStatus::CREATED_WRITE_JOB_FOR_REGISTER
-                      : CreateJobStatus::CREATED_WRITE_JOB_FOR_UPDATE;
-    return new ServiceWorkerWriteToCacheJob(
-        request, network_delegate, resource_type_, context_, version_.get(),
-        extra_load_flags, resource_id, incumbent_resource_id);
-  }
-
-  int64_t resource_id = kInvalidServiceWorkerResourceId;
-  if (ShouldReadFromScriptCache(request->url(), &resource_id)) {
-    if (resource_type_ == RESOURCE_TYPE_SERVICE_WORKER)
-      version_->embedded_worker()->OnURLJobCreatedForMainScript();
-    *out_status = CreateJobStatus::CREATED_READ_JOB;
     return new ServiceWorkerReadFromCacheJob(request, network_delegate,
                                              resource_type_, context_, version_,
                                              resource_id);
   }
 
-  // NULL means use the network.
-  *out_status = CreateJobStatus::IGNORE_UNKNOWN;
-  return nullptr;
-}
-
-bool ServiceWorkerContextRequestHandler::ShouldAddToScriptCache(
-    const GURL& url) {
-  // We only write imports that occur during the initial eval.
-  if (version_->status() != ServiceWorkerVersion::NEW &&
-      version_->status() != ServiceWorkerVersion::INSTALLING) {
-    return false;
+  // An installed worker is importing a non-stored script.
+  if (IsInstalled(version_.get())) {
+    DCHECK(!is_main_script);
+    *out_status = CreateJobStatus::ERROR_UNINSTALLED_SCRIPT_IMPORT;
+    return nullptr;
   }
-  return version_->script_cache_map()->LookupResourceId(url) ==
-         kInvalidServiceWorkerResourceId;
-}
 
-bool ServiceWorkerContextRequestHandler::ShouldReadFromScriptCache(
-    const GURL& url,
-    int64_t* resource_id_out) {
-  // We don't read from the script cache until the version is INSTALLED.
-  if (version_->status() == ServiceWorkerVersion::NEW ||
-      version_->status() == ServiceWorkerVersion::INSTALLING)
-    return false;
-  *resource_id_out = version_->script_cache_map()->LookupResourceId(url);
-  return *resource_id_out != kInvalidServiceWorkerResourceId;
+  // A new worker is loading a script for the first time. Create a write job to
+  // store the script.
+  ServiceWorkerRegistration* registration =
+      context_->GetLiveRegistration(version_->registration_id());
+  DCHECK(registration);  // We're registering or updating so must be there.
+
+  resource_id = context_->storage()->NewResourceId();
+  if (resource_id == kInvalidServiceWorkerResourceId) {
+    *out_status = CreateJobStatus::ERROR_OUT_OF_RESOURCE_IDS;
+    return nullptr;
+  }
+
+  // Bypass the browser cache for initial installs and update checks after 24
+  // hours have passed.
+  int extra_load_flags = 0;
+  base::TimeDelta time_since_last_check =
+      base::Time::Now() - registration->last_update_check();
+  if (time_since_last_check >
+          base::TimeDelta::FromHours(kServiceWorkerScriptMaxCacheAgeInHours) ||
+      version_->force_bypass_cache_for_scripts()) {
+    extra_load_flags = net::LOAD_BYPASS_CACHE;
+  }
+
+  ServiceWorkerVersion* stored_version = registration->waiting_version()
+                                             ? registration->waiting_version()
+                                             : registration->active_version();
+  int64_t incumbent_resource_id = kInvalidServiceWorkerResourceId;
+  if (stored_version && stored_version->script_url() == request->url()) {
+    incumbent_resource_id =
+        stored_version->script_cache_map()->LookupResourceId(request->url());
+  }
+  if (is_main_script)
+    version_->embedded_worker()->OnURLJobCreatedForMainScript();
+  *out_status = incumbent_resource_id == kInvalidServiceWorkerResourceId
+                    ? CreateJobStatus::WRITE_JOB_FOR_REGISTER
+                    : CreateJobStatus::WRITE_JOB_FOR_UPDATE;
+  return new ServiceWorkerWriteToCacheJob(
+      request, network_delegate, resource_type_, context_, version_.get(),
+      extra_load_flags, resource_id, incumbent_resource_id);
 }
 
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_context_request_handler.h b/content/browser/service_worker/service_worker_context_request_handler.h
index 2c1e2a6..1f00dabf 100644
--- a/content/browser/service_worker/service_worker_context_request_handler.h
+++ b/content/browser/service_worker/service_worker_context_request_handler.h
@@ -21,19 +21,21 @@
  public:
   enum class CreateJobStatus {
     UNINITIALIZED,
-    CREATED_WRITE_JOB_FOR_REGISTER,
-    CREATED_WRITE_JOB_FOR_UPDATE,
-    CREATED_READ_JOB,
-    NO_PROVIDER,
-    NO_VERSION,
-    NO_CONTEXT,
-    IGNORE_REDIRECT,
-    IGNORE_NON_SCRIPT,
-    OUT_OF_RESOURCE_IDS,
-    IGNORE_UNKNOWN,
-    // This is just to distinguish from UNINITIALIZED in case the function that
-    // is supposed to set status didn't do so.
-    DID_NOT_SET_STATUS
+    WRITE_JOB_FOR_REGISTER,
+    WRITE_JOB_FOR_UPDATE,
+    READ_JOB,
+    // When a new worker imports a script that was already imported.
+    READ_JOB_FOR_DUPLICATE_SCRIPT_IMPORT,
+    ERROR_NO_PROVIDER,
+    ERROR_NO_VERSION,
+    ERROR_REDUNDANT_VERSION,
+    ERROR_NO_CONTEXT,
+    ERROR_REDIRECT,
+    // When an installed worker imports a script that was not stored at
+    // installation time.
+    ERROR_UNINSTALLED_SCRIPT_IMPORT,
+    ERROR_OUT_OF_RESOURCE_IDS,
+    NUM_TYPES
   };
 
   ServiceWorkerContextRequestHandler(
@@ -49,13 +51,12 @@
       net::NetworkDelegate* network_delegate,
       ResourceContext* resource_context) override;
 
+  static std::string CreateJobStatusToString(CreateJobStatus status);
+
  private:
-  net::URLRequestJob* MaybeCreateJobImpl(CreateJobStatus* out_status,
-                                         net::URLRequest* request,
+  net::URLRequestJob* MaybeCreateJobImpl(net::URLRequest* request,
                                          net::NetworkDelegate* network_delegate,
-                                         ResourceContext* resource_context);
-  bool ShouldAddToScriptCache(const GURL& url);
-  bool ShouldReadFromScriptCache(const GURL& url, int64_t* resource_id_out);
+                                         CreateJobStatus* out_status);
 
   scoped_refptr<ServiceWorkerVersion> version_;
 
diff --git a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
index 93583b3..96486459f 100644
--- a/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
+++ b/content/browser/service_worker/service_worker_context_request_handler_unittest.cc
@@ -14,14 +14,17 @@
 #include "content/browser/service_worker/embedded_worker_test_helper.h"
 #include "content/browser/service_worker/service_worker_context_core.h"
 #include "content/browser/service_worker/service_worker_provider_host.h"
+#include "content/browser/service_worker/service_worker_read_from_cache_job.h"
 #include "content/browser/service_worker/service_worker_registration.h"
 #include "content/browser/service_worker/service_worker_test_utils.h"
 #include "content/browser/service_worker/service_worker_write_to_cache_job.h"
 #include "content/common/service_worker/service_worker_utils.h"
 #include "content/public/browser/resource_request_info.h"
+#include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_job_factory_impl.h"
 #include "storage/browser/blob/blob_storage_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -31,7 +34,26 @@
 
 void EmptyCallback() {}
 
-}
+}  // namespace
+
+class MockHttpProtocolHandler
+    : public net::URLRequestJobFactory::ProtocolHandler {
+ public:
+  MockHttpProtocolHandler(ResourceContext* resource_context)
+      : resource_context_(resource_context) {}
+
+  net::URLRequestJob* MaybeCreateJob(
+      net::URLRequest* request,
+      net::NetworkDelegate* network_delegate) const override {
+    ServiceWorkerRequestHandler* handler =
+        ServiceWorkerRequestHandler::GetHandler(request);
+    return handler->MaybeCreateJob(request, network_delegate,
+                                   resource_context_);
+  }
+
+ private:
+  ResourceContext* resource_context_;
+};
 
 class ServiceWorkerContextRequestHandlerTest : public testing::Test {
  public:
@@ -42,14 +64,14 @@
     helper_.reset(new EmbeddedWorkerTestHelper(base::FilePath()));
 
     // A new unstored registration/version.
-    scope_ = GURL("http://host/scope/");
-    script_url_ = GURL("http://host/script.js");
+    scope_ = GURL("https://host/scope/");
+    script_url_ = GURL("https://host/script.js");
     registration_ = new ServiceWorkerRegistration(
         scope_, 1L, context()->AsWeakPtr());
     version_ = new ServiceWorkerVersion(
         registration_.get(), script_url_, 1L, context()->AsWeakPtr());
 
-    // An empty host.
+    // A provider host for the version.
     std::unique_ptr<ServiceWorkerProviderHost> host(
         new ServiceWorkerProviderHost(
             helper_->mock_render_process_id(),
@@ -59,9 +81,16 @@
             context()->AsWeakPtr(), nullptr));
     provider_host_ = host->AsWeakPtr();
     context()->AddProviderHost(std::move(host));
+    provider_host_->running_hosted_version_ = version_;
 
     context()->storage()->LazyInitialize(base::Bind(&EmptyCallback));
     base::RunLoop().RunUntilIdle();
+
+    std::unique_ptr<MockHttpProtocolHandler> handler(
+        new MockHttpProtocolHandler(
+            helper_->browser_context()->GetResourceContext()));
+    url_request_job_factory_.SetProtocolHandler("https", std::move(handler));
+    url_request_context_.set_job_factory(&url_request_job_factory_);
   }
 
   void TearDown() override {
@@ -72,6 +101,13 @@
 
   ServiceWorkerContextCore* context() const { return helper_->context(); }
 
+  EmbeddedWorkerTestHelper* helper() { return helper_.get(); }
+  ServiceWorkerVersion* version() { return version_.get(); }
+  ServiceWorkerProviderHost* provider_host() { return provider_host_.get(); }
+  storage::BlobStorageContext* blob_storage_context() {
+    return &blob_storage_context_;
+  }
+
  protected:
   TestBrowserThreadBundle browser_thread_bundle_;
   std::unique_ptr<EmbeddedWorkerTestHelper> helper_;
@@ -80,6 +116,7 @@
   base::WeakPtr<ServiceWorkerProviderHost> provider_host_;
   net::URLRequestContext url_request_context_;
   MockURLRequestDelegate url_request_delegate_;
+  net::URLRequestJobFactoryImpl url_request_job_factory_;
   GURL scope_;
   GURL script_url_;
   storage::BlobStorageContext blob_storage_context_;
@@ -90,10 +127,9 @@
   // we're installing a new version.
   registration_->set_last_update_check(base::Time::Now());
   version_->SetStatus(ServiceWorkerVersion::NEW);
-  provider_host_->running_hosted_version_ = version_;
 
   // Conduct a resource fetch for the main script.
-  const GURL kScriptUrl("http://host/script.js");
+  const GURL kScriptUrl("https://host/script.js");
   std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
       kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
   std::unique_ptr<ServiceWorkerContextRequestHandler> handler(
@@ -117,10 +153,9 @@
   registration_->set_last_update_check(
       base::Time::Now() - base::TimeDelta::FromDays(7));
   version_->SetStatus(ServiceWorkerVersion::NEW);
-  provider_host_->running_hosted_version_ = version_;
 
   // Conduct a resource fetch for the main script.
-  const GURL kScriptUrl("http://host/script.js");
+  const GURL kScriptUrl("https://host/script.js");
   std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
       kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
   std::unique_ptr<ServiceWorkerContextRequestHandler> handler(
@@ -144,10 +179,9 @@
   registration_->set_last_update_check(base::Time::Now());
   version_->SetStatus(ServiceWorkerVersion::NEW);
   version_->set_force_bypass_cache_for_scripts(true);
-  provider_host_->running_hosted_version_ = version_;
 
   // Conduct a resource fetch for the main script.
-  const GURL kScriptUrl("http://host/script.js");
+  const GURL kScriptUrl("https://host/script.js");
   std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
       kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
   std::unique_ptr<ServiceWorkerContextRequestHandler> handler(
@@ -168,10 +202,9 @@
 TEST_F(ServiceWorkerContextRequestHandlerTest,
        ServiceWorkerDataRequestAnnotation) {
   version_->SetStatus(ServiceWorkerVersion::NEW);
-  provider_host_->running_hosted_version_ = version_;
 
   // Conduct a resource fetch for the main script.
-  const GURL kScriptUrl("http://host/script.js");
+  const GURL kScriptUrl("https://host/script.js");
   std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
       kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
   std::unique_ptr<ServiceWorkerContextRequestHandler> handler(
@@ -197,8 +230,7 @@
        SkipServiceWorkerForServiceWorkerRequest) {
   // Conduct a resource fetch for the main script.
   version_->SetStatus(ServiceWorkerVersion::NEW);
-  provider_host_->running_hosted_version_ = version_;
-  const GURL kScriptUrl("http://host/script.js");
+  const GURL kScriptUrl("https://host/script.js");
   std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
       kScriptUrl, net::DEFAULT_PRIORITY, &url_request_delegate_);
   ServiceWorkerRequestHandler::InitializeHandler(
@@ -214,4 +246,25 @@
   EXPECT_TRUE(handler);
 }
 
+TEST_F(ServiceWorkerContextRequestHandlerTest, RedundantVersion) {
+  // Create a redundant version.
+  version_->SetStatus(ServiceWorkerVersion::REDUNDANT);
+
+  // Conduct a resource fetch for the main script.
+  std::unique_ptr<net::URLRequest> request = url_request_context_.CreateRequest(
+      version_->script_url(), net::DEFAULT_PRIORITY, &url_request_delegate_);
+  ServiceWorkerRequestHandler::InitializeHandler(
+      request.get(), helper()->context_wrapper(), blob_storage_context(),
+      helper()->mock_render_process_id(), provider_host()->provider_id(),
+      true /* skip_service_worker */, FETCH_REQUEST_MODE_NO_CORS,
+      FETCH_CREDENTIALS_MODE_OMIT, FetchRedirectMode::FOLLOW_MODE,
+      RESOURCE_TYPE_SERVICE_WORKER, REQUEST_CONTEXT_TYPE_SERVICE_WORKER,
+      REQUEST_CONTEXT_FRAME_TYPE_NONE, nullptr);
+
+  // Verify that the request fails.
+  request->Start();
+  base::RunLoop().Run();
+  EXPECT_EQ(net::ERR_FAILED, url_request_delegate_.request_status());
+}
+
 }  // namespace content
diff --git a/content/browser/service_worker/service_worker_metrics.h b/content/browser/service_worker/service_worker_metrics.h
index 4d229d8..1225c386 100644
--- a/content/browser/service_worker/service_worker_metrics.h
+++ b/content/browser/service_worker/service_worker_metrics.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "content/browser/service_worker/service_worker_context_request_handler.h"
 #include "content/browser/service_worker/service_worker_database.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerResponseError.h"
diff --git a/content/browser/service_worker/service_worker_provider_host.h b/content/browser/service_worker/service_worker_provider_host.h
index 33df5b2..3ed67ba 100644
--- a/content/browser/service_worker/service_worker_provider_host.h
+++ b/content/browser/service_worker/service_worker_provider_host.h
@@ -299,6 +299,7 @@
   friend class LinkHeaderServiceWorkerTest;
   friend class ServiceWorkerProviderHostTest;
   friend class ServiceWorkerWriteToCacheJobTest;
+  friend class ServiceWorkerContextRequestHandlerTest;
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest, Update_SameScript);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerWriteToCacheJobTest,
                            Update_SameSizeScript);
@@ -312,16 +313,6 @@
                            DispatchExtendableMessageEvent);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerDispatcherHostTest,
                            DispatchExtendableMessageEvent_Fail);
-  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
-                           UpdateBefore24Hours);
-  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
-                           UpdateAfter24Hours);
-  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
-                           UpdateForceBypassCache);
-  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
-                           ServiceWorkerDataRequestAnnotation);
-  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTest,
-                           SkipServiceWorkerForServiceWorkerRequest);
   FRIEND_TEST_ALL_PREFIXES(ServiceWorkerProviderHostTest, ContextSecurity);
 
   struct OneShotGetReadyCallback {
diff --git a/content/browser/service_worker/service_worker_read_from_cache_job.h b/content/browser/service_worker/service_worker_read_from_cache_job.h
index 4373fad8..3acf53e0 100644
--- a/content/browser/service_worker/service_worker_read_from_cache_job.h
+++ b/content/browser/service_worker/service_worker_read_from_cache_job.h
@@ -41,6 +41,8 @@
 
  private:
   friend class ServiceWorkerReadFromCacheJobTest;
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerContextRequestHandlerTestP,
+                           DuplicateScriptImport);
 
   bool is_main_script() const {
     return resource_type_ == RESOURCE_TYPE_SERVICE_WORKER;
diff --git a/content/browser/service_worker/service_worker_script_cache_map.h b/content/browser/service_worker/service_worker_script_cache_map.h
index 6a167346..ac4436d 100644
--- a/content/browser/service_worker/service_worker_script_cache_map.h
+++ b/content/browser/service_worker/service_worker_script_cache_map.h
@@ -73,6 +73,9 @@
 
   // The version objects owns its script cache and provides a rawptr to it.
   friend class ServiceWorkerVersion;
+  FRIEND_TEST_ALL_PREFIXES(ServiceWorkerVersionBrowserTest,
+                           ReadResourceFailure_WaitingWorker);
+
   ServiceWorkerScriptCacheMap(
       ServiceWorkerVersion* owner,
       base::WeakPtr<ServiceWorkerContextCore> context);
diff --git a/content/child/browser_font_resource_trusted.cc b/content/child/browser_font_resource_trusted.cc
index 30bae9f..e6fbfc4 100644
--- a/content/child/browser_font_resource_trusted.cc
+++ b/content/child/browser_font_resource_trusted.cc
@@ -315,12 +315,12 @@
 
   PPB_ImageData_API* image = static_cast<PPB_ImageData_API*>(
       enter.object());
-  SkCanvas* canvas = image->GetPlatformCanvas();
+  SkCanvas* canvas = image->GetCanvas();
   bool needs_unmapping = false;
   if (!canvas) {
     needs_unmapping = true;
     image->Map();
-    canvas = image->GetPlatformCanvas();
+    canvas = image->GetCanvas();
     if (!canvas)
       return result;  // Failure mapping.
   }
diff --git a/content/public/android/java/src/org/chromium/content/browser/AudioFocusDelegate.java b/content/public/android/java/src/org/chromium/content/browser/AudioFocusDelegate.java
index ad03a3a..2642433 100644
--- a/content/public/android/java/src/org/chromium/content/browser/AudioFocusDelegate.java
+++ b/content/public/android/java/src/org/chromium/content/browser/AudioFocusDelegate.java
@@ -90,7 +90,7 @@
                 }
                 break;
             case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
-                nativeOnSuspend(mNativeAudioFocusDelegateAndroid, true);
+                nativeOnSuspend(mNativeAudioFocusDelegateAndroid);
                 break;
             case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                 mIsDucking = true;
@@ -99,7 +99,7 @@
                 break;
             case AudioManager.AUDIOFOCUS_LOSS:
                 abandonAudioFocus();
-                nativeOnSuspend(mNativeAudioFocusDelegateAndroid, false);
+                nativeOnSuspend(mNativeAudioFocusDelegateAndroid);
                 break;
             default:
                 Log.w(TAG, "onAudioFocusChange called with unexpected value %d", focusChange);
@@ -107,7 +107,7 @@
         }
     }
 
-    private native void nativeOnSuspend(long nativeAudioFocusDelegateAndroid, boolean temporary);
+    private native void nativeOnSuspend(long nativeAudioFocusDelegateAndroid);
     private native void nativeOnResume(long nativeAudioFocusDelegateAndroid);
     private native void nativeOnStartDucking(long nativeAudioFocusDelegateAndroid);
     private native void nativeOnStopDucking(long nativeAudioFocusDelegateAndroid);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
index 69aa07dc..a67cb50e 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
@@ -9,6 +9,8 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.DisabledTest;
 import org.chromium.base.test.util.Feature;
@@ -18,8 +20,11 @@
 import org.chromium.content.browser.test.util.CriteriaHelper;
 import org.chromium.content.browser.test.util.DOMUtils;
 import org.chromium.content.common.ContentSwitches;
+import org.chromium.content_public.browser.MediaSession;
+import org.chromium.content_public.browser.MediaSessionObserver;
 import org.chromium.content_shell_apk.ContentShellTestBase;
 
+import java.util.ArrayList;
 import java.util.concurrent.Callable;
 
 /**
@@ -84,6 +89,35 @@
 
     private MockAudioFocusChangeListener mAudioFocusChangeListener;
 
+    @SuppressFBWarnings("URF_UNREAD_FIELD")
+    private MediaSessionObserver mObserver;
+
+    private ArrayList<StateRecord> mStateRecords = new ArrayList<StateRecord>();
+
+    private static class StateRecord {
+        public boolean isControllable;
+        public boolean isSuspended;
+
+        public StateRecord(boolean isControllable, boolean isSuspended) {
+            this.isControllable = isControllable;
+            this.isSuspended = isSuspended;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) return true;
+            if (!(obj instanceof StateRecord)) return false;
+
+            StateRecord other = (StateRecord) obj;
+            return isControllable == other.isControllable && isSuspended == other.isSuspended;
+        }
+
+        @Override
+        public int hashCode() {
+            return (isControllable ? 2 : 0) + (isSuspended ? 1 : 0);
+        }
+    }
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
@@ -95,6 +129,19 @@
         }
 
         mAudioFocusChangeListener = new MockAudioFocusChangeListener();
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mObserver =
+                        new MediaSessionObserver(MediaSession.fromWebContents(getWebContents())) {
+                            @Override
+                            public void mediaSessionStateChanged(
+                                    boolean isControllable, boolean isSuspended) {
+                                mStateRecords.add(new StateRecord(isControllable, isSuspended));
+                            }
+                        };
+            }
+        });
     }
 
     @Override
@@ -382,4 +429,62 @@
         DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
         DOMUtils.waitForMediaPlay(getWebContents(), LONG_VIDEO);
     }
+
+    @MediumTest
+    @Feature({"MediaSession"})
+    @RetryOnFailure
+    public void testSessionSuspendedAfterFocusLossWhenPlaying() throws Exception {
+        ArrayList<StateRecord> expectedStates = new ArrayList<StateRecord>();
+        expectedStates.add(new StateRecord(true, false));
+        expectedStates.add(new StateRecord(true, true));
+
+        assertEquals(AudioManager.AUDIOFOCUS_LOSS, mAudioFocusChangeListener.getAudioFocusState());
+        mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
+        assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
+
+        DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
+
+        // Wait for the media to be really playing.
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
+
+        mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
+        assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
+
+        DOMUtils.waitForMediaPauseBeforeEnd(getWebContents(), LONG_AUDIO);
+
+        assertEquals(expectedStates, mStateRecords);
+    }
+
+    @MediumTest
+    @Feature({"MediaSession"})
+    @RetryOnFailure
+    public void testSessionSuspendedAfterFocusLossWhenPaused() throws Exception {
+        ArrayList<StateRecord> expectedStates = new ArrayList<StateRecord>();
+        expectedStates.add(new StateRecord(true, false));
+        expectedStates.add(new StateRecord(true, true));
+
+        assertEquals(AudioManager.AUDIOFOCUS_LOSS, mAudioFocusChangeListener.getAudioFocusState());
+        mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
+        assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
+
+        DOMUtils.playMedia(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPlay(getWebContents(), LONG_AUDIO);
+
+        // Wait for the media to be really playing.
+        mAudioFocusChangeListener.waitForFocusStateChange(AudioManager.AUDIOFOCUS_LOSS);
+
+        DOMUtils.pauseMedia(getWebContents(), LONG_AUDIO);
+        DOMUtils.waitForMediaPauseBeforeEnd(getWebContents(), LONG_AUDIO);
+
+        assertEquals(expectedStates, mStateRecords);
+
+        mAudioFocusChangeListener.requestAudioFocus(AudioManager.AUDIOFOCUS_GAIN);
+        assertEquals(AudioManager.AUDIOFOCUS_GAIN, mAudioFocusChangeListener.getAudioFocusState());
+
+        // Wait for 1 second before observing MediaSession state change.
+        Thread.sleep(AUDIO_FOCUS_CHANGE_TIMEOUT);
+
+        assertEquals(expectedStates, mStateRecords);
+    }
 }
diff --git a/content/renderer/pepper/pepper_plugin_instance_impl.cc b/content/renderer/pepper/pepper_plugin_instance_impl.cc
index fabc117..5a74226 100644
--- a/content/renderer/pepper/pepper_plugin_instance_impl.cc
+++ b/content/renderer/pepper/pepper_plugin_instance_impl.cc
@@ -3094,7 +3094,7 @@
   if (!mapper.is_valid())
     return 0;
 
-  SkCanvas* canvas = image_data->GetPlatformCanvas();
+  SkCanvas* canvas = image_data->GetCanvas();
   // Note: Do not SkBitmap::copyTo the canvas bitmap directly because it will
   // ignore the allocated pixels in shared memory and re-allocate a new buffer.
   canvas->writePixels(image_skia_rep.sk_bitmap(), 0, 0);
diff --git a/content/renderer/pepper/ppb_image_data_impl.cc b/content/renderer/pepper/ppb_image_data_impl.cc
index 5d52a1d..d612e4c 100644
--- a/content/renderer/pepper/ppb_image_data_impl.cc
+++ b/content/renderer/pepper/ppb_image_data_impl.cc
@@ -114,10 +114,6 @@
   return backend_->GetSharedMemory(shm, byte_count);
 }
 
-SkCanvas* PPB_ImageData_Impl::GetPlatformCanvas() {
-  return backend_->GetPlatformCanvas();
-}
-
 SkCanvas* PPB_ImageData_Impl::GetCanvas() { return backend_->GetCanvas(); }
 
 void PPB_ImageData_Impl::SetIsCandidateForReuse() {
@@ -199,10 +195,6 @@
   return PP_OK;
 }
 
-SkCanvas* ImageDataPlatformBackend::GetPlatformCanvas() {
-  return mapped_canvas_.get();
-}
-
 SkCanvas* ImageDataPlatformBackend::GetCanvas() { return mapped_canvas_.get(); }
 
 SkBitmap ImageDataPlatformBackend::GetMappedBitmap() const {
@@ -268,10 +260,6 @@
   return PP_OK;
 }
 
-SkCanvas* ImageDataSimpleBackend::GetPlatformCanvas() {
-  return NULL;
-}
-
 SkCanvas* ImageDataSimpleBackend::GetCanvas() {
   if (!IsMapped())
     return NULL;
diff --git a/content/renderer/pepper/ppb_image_data_impl.h b/content/renderer/pepper/ppb_image_data_impl.h
index 81c9a5a..7d6b19b 100644
--- a/content/renderer/pepper/ppb_image_data_impl.h
+++ b/content/renderer/pepper/ppb_image_data_impl.h
@@ -51,7 +51,6 @@
     virtual void Unmap() = 0;
     virtual int32_t GetSharedMemory(base::SharedMemory** shm,
                                     uint32_t* byte_count) = 0;
-    virtual SkCanvas* GetPlatformCanvas() = 0;
     virtual SkCanvas* GetCanvas() = 0;
     virtual SkBitmap GetMappedBitmap() const = 0;
   };
@@ -97,7 +96,6 @@
   void Unmap() override;
   int32_t GetSharedMemory(base::SharedMemory** shm,
                           uint32_t* byte_count) override;
-  SkCanvas* GetPlatformCanvas() override;
   SkCanvas* GetCanvas() override;
   void SetIsCandidateForReuse() override;
 
@@ -137,7 +135,6 @@
   void Unmap() override;
   int32_t GetSharedMemory(base::SharedMemory** shm,
                           uint32_t* byte_count) override;
-  SkCanvas* GetPlatformCanvas() override;
   SkCanvas* GetCanvas() override;
   SkBitmap GetMappedBitmap() const override;
 
@@ -171,7 +168,6 @@
   void Unmap() override;
   int32_t GetSharedMemory(base::SharedMemory** shm,
                           uint32_t* byte_count) override;
-  SkCanvas* GetPlatformCanvas() override;
   SkCanvas* GetCanvas() override;
   SkBitmap GetMappedBitmap() const override;
 
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index c8af5304..9399235 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1399,6 +1399,32 @@
   },
 }
 
+# These isolated tests don't use telemetry. They need to be placed in the
+# isolated_scripts section of the generated json.
+NON_TELEMETRY_ISOLATED_SCRIPT_TESTS = {
+  # We run angle_perftests on the ANGLE CQ to ensure the tests don't crash.
+  'angle_perftests': {
+    'tester_configs': [
+      {
+        'fyi_only': True,
+        'run_on_optional': True,
+        # Run on the Win/Linux Release NVIDIA bots.
+        'build_configs': ['Release'],
+        'swarming_dimension_sets': [
+          {
+            'gpu': '10de:104a',
+            'os': 'Windows-2008ServerR2-SP1'
+          },
+          {
+            'gpu': '10de:104a',
+            'os': 'Linux'
+          }
+        ],
+      },
+    ],
+  },
+}
+
 def substitute_args(tester_config, args):
   """Substitutes the ${os_type} variable in |args| from the
      tester_config's "os_type" property.
@@ -1551,62 +1577,6 @@
   result['use_xvfb'] = False
   return result
 
-def generate_telemetry_test(tester_name, tester_config,
-                            test, test_config, is_fyi):
-  if not should_run_on_tester(tester_name, tester_config, test_config, is_fyi):
-    return None
-  test_args = ['-v']
-  # --expose-gc allows the WebGL conformance tests to more reliably
-  # reproduce GC-related bugs in the V8 bindings.
-  extra_browser_args_string = (
-      '--enable-logging=stderr --js-flags=--expose-gc')
-  if 'extra_browser_args' in test_config:
-    extra_browser_args_string += ' ' + ' '.join(
-        test_config['extra_browser_args'])
-  test_args.append('--extra-browser-args=' + extra_browser_args_string)
-  if 'args' in test_config:
-    test_args.extend(substitute_args(tester_config, test_config['args']))
-  if 'desktop_args' in test_config and not is_android(tester_config):
-    test_args.extend(substitute_args(tester_config,
-                                     test_config['desktop_args']))
-  if 'android_args' in test_config and is_android(tester_config):
-    test_args.extend(substitute_args(tester_config,
-                                     test_config['android_args']))
-  # The step name must end in 'test' or 'tests' in order for the
-  # results to automatically show up on the flakiness dashboard.
-  # (At least, this was true some time ago.) Continue to use this
-  # naming convention for the time being to minimize changes.
-  step_name = test
-  if not (step_name.endswith('test') or step_name.endswith('tests')):
-    step_name = '%s_tests' % step_name
-  # Prepend Telemetry GPU-specific flags.
-  benchmark_name = test_config.get('target_name') or test
-  prefix_args = [
-    benchmark_name,
-    '--show-stdout',
-    '--browser=%s' % tester_config['build_config'].lower()
-  ]
-  swarming = {
-    # Always say this is true regardless of whether the tester
-    # supports swarming. It doesn't hurt.
-    'can_use_on_swarming_builders': True,
-    'dimension_sets': tester_config['swarming_dimensions']
-  }
-  if 'swarming' in test_config:
-    swarming.update(test_config['swarming'])
-  result = {
-    'args': prefix_args + test_args,
-    'isolate_name': 'telemetry_gpu_integration_test',
-    'name': step_name,
-    'override_compile_targets': ['telemetry_gpu_integration_test_run'],
-    'swarming': swarming,
-  }
-  if 'non_precommit_args' in test_config:
-    result['non_precommit_args'] = test_config['non_precommit_args']
-  if 'precommit_args' in test_config:
-    result['precommit_args'] = test_config['precommit_args']
-  return result
-
 def generate_gtests(tester_name, tester_config, test_dictionary, is_fyi):
   # The relative ordering of some of the tests is important to
   # minimize differences compared to the handwritten JSON files, since
@@ -1622,6 +1592,73 @@
       gtests.append(test)
   return gtests
 
+def generate_isolated_test(tester_name, tester_config, test, test_config,
+                           is_fyi, extra_browser_args, isolate_name,
+                           override_compile_targets, prefix_args):
+  if not should_run_on_tester(tester_name, tester_config, test_config, is_fyi):
+    return None
+  test_args = ['-v']
+  extra_browser_args_string = ""
+  if extra_browser_args != None:
+    extra_browser_args_string += ' '.join(extra_browser_args)
+  if 'extra_browser_args' in test_config:
+    extra_browser_args_string += ' ' + ' '.join(
+        test_config['extra_browser_args'])
+  if extra_browser_args_string != "":
+    test_args.append('--extra-browser-args=' + extra_browser_args_string)
+  if 'args' in test_config:
+    test_args.extend(substitute_args(tester_config, test_config['args']))
+  if 'desktop_args' in test_config and not is_android(tester_config):
+    test_args.extend(substitute_args(tester_config,
+                                     test_config['desktop_args']))
+  if 'android_args' in test_config and is_android(tester_config):
+    test_args.extend(substitute_args(tester_config,
+                                     test_config['android_args']))
+  # The step name must end in 'test' or 'tests' in order for the
+  # results to automatically show up on the flakiness dashboard.
+  # (At least, this was true some time ago.) Continue to use this
+  # naming convention for the time being to minimize changes.
+  step_name = test
+  if not (step_name.endswith('test') or step_name.endswith('tests')):
+    step_name = '%s_tests' % step_name
+  # Prepend GPU-specific flags.
+  swarming = {
+    # Always say this is true regardless of whether the tester
+    # supports swarming. It doesn't hurt.
+    'can_use_on_swarming_builders': True,
+    'dimension_sets': tester_config['swarming_dimensions']
+  }
+  if 'swarming' in test_config:
+    swarming.update(test_config['swarming'])
+  result = {
+    'args': prefix_args + test_args,
+    'isolate_name': isolate_name,
+    'name': step_name,
+    'swarming': swarming,
+  }
+  if override_compile_targets != None:
+    result['override_compile_targets'] = override_compile_targets
+  if 'non_precommit_args' in test_config:
+    result['non_precommit_args'] = test_config['non_precommit_args']
+  if 'precommit_args' in test_config:
+    result['precommit_args'] = test_config['precommit_args']
+  return result
+
+def generate_telemetry_test(tester_name, tester_config,
+                            test, test_config, is_fyi):
+  extra_browser_args = ['--enable-logging=stderr', '--js-flags=--expose-gc']
+  benchmark_name = test_config.get('target_name') or test
+  prefix_args = [
+    benchmark_name,
+    '--show-stdout',
+    '--browser=%s' % tester_config['build_config'].lower()
+  ]
+  return generate_isolated_test(tester_name, tester_config, test,
+                                test_config, is_fyi, extra_browser_args,
+                                'telemetry_gpu_integration_test',
+                                ['telemetry_gpu_integration_test_run'],
+                                prefix_args)
+
 def generate_telemetry_tests(tester_name, tester_config,
                              test_dictionary, is_fyi):
   isolated_scripts = []
@@ -1632,6 +1669,21 @@
       isolated_scripts.append(test)
   return isolated_scripts
 
+def generate_non_telemetry_isolated_test(tester_name, tester_config,
+                                         test, test_config, is_fyi):
+  return generate_isolated_test(tester_name, tester_config, test,
+                                test_config, is_fyi, None, test, None, [])
+
+def generate_non_telemetry_isolated_tests(tester_name, tester_config,
+                                          test_dictionary, is_fyi):
+  isolated_scripts = []
+  for test_name, test_config in sorted(test_dictionary.iteritems()):
+    test = generate_non_telemetry_isolated_test(
+      tester_name, tester_config, test_name, test_config, is_fyi)
+    if test:
+      isolated_scripts.append(test)
+  return isolated_scripts
+
 def generate_all_tests(waterfall, is_fyi):
   tests = {}
   for builder, config in waterfall['builders'].iteritems():
@@ -1640,7 +1692,9 @@
     gtests = generate_gtests(name, config, COMMON_GTESTS, is_fyi)
     isolated_scripts = \
       generate_telemetry_tests(
-        name, config, TELEMETRY_GPU_INTEGRATION_TESTS, is_fyi)
+        name, config, TELEMETRY_GPU_INTEGRATION_TESTS, is_fyi) + \
+      generate_non_telemetry_isolated_tests(name, config,
+          NON_TELEMETRY_ISOLATED_SCRIPT_TESTS, is_fyi)
     tests[name] = {
       'gtest_tests': sorted(gtests, key=lambda x: x['test']),
       'isolated_scripts': sorted(isolated_scripts, key=lambda x: x['name'])
diff --git a/headless/app/headless_shell.cc b/headless/app/headless_shell.cc
index 530a7c5..42a331fb 100644
--- a/headless/app/headless_shell.cc
+++ b/headless/app/headless_shell.cc
@@ -45,7 +45,7 @@
 
 bool ParseWindowSize(std::string window_size, gfx::Size* parsed_window_size) {
   int width, height = 0;
-  if (sscanf(window_size.c_str(), "%dx%d", &width, &height) >= 2 &&
+  if (sscanf(window_size.c_str(), "%d%*[x,]%d", &width, &height) >= 2 &&
       width >= 0 && height >= 0) {
     parsed_window_size->set_width(width);
     parsed_window_size->set_height(height);
diff --git a/headless/app/headless_shell_switches.cc b/headless/app/headless_shell_switches.cc
index 392c5f7e..0675059 100644
--- a/headless/app/headless_shell_switches.cc
+++ b/headless/app/headless_shell_switches.cc
@@ -54,7 +54,7 @@
 // specified virtual time budget is exhausted.
 const char kVirtualTimeBudget[] = "virtual-time-budget";
 
-// Sets the initial window size. Provided as string in the format "800x600".
+// Sets the initial window size. Provided as string in the format "800,600".
 const char kWindowSize[] = "window-size";
 
 }  // namespace switches
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 352e988..5b0bda09 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -710,7 +710,8 @@
   // Ensure the main tab model is created.
   ignore_result([_browserViewWrangler mainTabModel]);
 
-  [self createSpotlightManager];
+  _spotlightManager.reset([[SpotlightManager
+      spotlightManagerWithBrowserState:_mainBrowserState] retain]);
 
   if (reading_list::switches::IsReadingListEnabled()) {
     ShareExtensionService* service =
@@ -1236,13 +1237,6 @@
                   }];
 }
 
-- (void)createSpotlightManager {
-  if (spotlight::IsSpotlightAvailable()) {
-    _spotlightManager.reset([[SpotlightManager
-        spotlightManagerWithBrowserState:_mainBrowserState] retain]);
-  }
-}
-
 - (void)scheduleSpotlightResync {
   if (!_spotlightManager) {
     return;
diff --git a/ios/chrome/app/safe_mode/BUILD.gn b/ios/chrome/app/safe_mode/BUILD.gn
index 180fb25..bd5b7ea3 100644
--- a/ios/chrome/app/safe_mode/BUILD.gn
+++ b/ios/chrome/app/safe_mode/BUILD.gn
@@ -37,6 +37,7 @@
 }
 
 source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
     "safe_mode_egtest.mm",
diff --git a/ios/chrome/app/safe_mode/safe_mode_egtest.mm b/ios/chrome/app/safe_mode/safe_mode_egtest.mm
index 5962693..fcefead 100644
--- a/ios/chrome/app/safe_mode/safe_mode_egtest.mm
+++ b/ios/chrome/app/safe_mode/safe_mode_egtest.mm
@@ -7,7 +7,6 @@
 
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
 #import "ios/chrome/app/chrome_overlay_window.h"
 #import "ios/chrome/app/safe_mode/safe_mode_view_controller.h"
 #import "ios/chrome/browser/ui/main/main_view_controller.h"
@@ -15,6 +14,10 @@
 #import "ios/chrome/test/base/scoped_block_swizzler.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace {
 
 // Returns the top view controller for rendering the Safe Mode Controller.
@@ -80,8 +83,8 @@
                                 });
 
   // Instantiates a Safe Mode controller and displays it.
-  base::scoped_nsobject<SafeModeViewController> safeModeController(
-      [[SafeModeViewController alloc] initWithDelegate:nil]);
+  SafeModeViewController* safeModeController =
+      [[SafeModeViewController alloc] initWithDelegate:nil];
   [GetActiveViewController() presentViewController:safeModeController
                                           animated:NO
                                         completion:nil];
@@ -110,8 +113,8 @@
                                  });
 
   // Instantiates a Safe Mode controller and displays it.
-  base::scoped_nsobject<SafeModeViewController> safeModeController(
-      [[SafeModeViewController alloc] initWithDelegate:nil]);
+  SafeModeViewController* safeModeController =
+      [[SafeModeViewController alloc] initWithDelegate:nil];
   [GetActiveViewController() presentViewController:safeModeController
                                           animated:NO
                                         completion:nil];
@@ -146,8 +149,8 @@
                                   return YES;
                                 });
   // Instantiates a Safe Mode controller and displays it.
-  base::scoped_nsobject<SafeModeViewController> safeModeController(
-      [[SafeModeViewController alloc] initWithDelegate:nil]);
+  SafeModeViewController* safeModeController =
+      [[SafeModeViewController alloc] initWithDelegate:nil];
   [GetActiveViewController() presentViewController:safeModeController
                                           animated:NO
                                         completion:nil];
diff --git a/ios/chrome/app/spotlight/spotlight_manager.mm b/ios/chrome/app/spotlight/spotlight_manager.mm
index 22c83bd..b4d05739 100644
--- a/ios/chrome/app/spotlight/spotlight_manager.mm
+++ b/ios/chrome/app/spotlight/spotlight_manager.mm
@@ -28,12 +28,15 @@
 
 + (SpotlightManager*)spotlightManagerWithBrowserState:
     (ios::ChromeBrowserState*)browserState {
-  DCHECK(spotlight::IsSpotlightAvailable());
-  return [[[SpotlightManager alloc] initWithBrowserState:browserState]
-      autorelease];
+  if (spotlight::IsSpotlightAvailable()) {
+    return [[[SpotlightManager alloc] initWithBrowserState:browserState]
+        autorelease];
+  }
+  return nil;
 }
 
 - (instancetype)initWithBrowserState:(ios::ChromeBrowserState*)browserState {
+  DCHECK(spotlight::IsSpotlightAvailable());
   self = [super init];
   if (self) {
     _topSitesManager.reset([[TopSitesSpotlightManager
diff --git a/ios/chrome/browser/metrics/first_user_action_recorder.cc b/ios/chrome/browser/metrics/first_user_action_recorder.cc
index c0790876..ab1d6bf 100644
--- a/ios/chrome/browser/metrics/first_user_action_recorder.cc
+++ b/ios/chrome/browser/metrics/first_user_action_recorder.cc
@@ -62,16 +62,26 @@
 
 // A list of actions that indicate a new task has been started.
 const char* kNewTaskActions[] = {
-    "MobileMenuAllBookmarks",     "MobileMenuHistory",
-    "MobileMenuNewIncognitoTab",  "MobileMenuNewTab",
-    "MobileMenuRecentTabs",       "MobileMenuVoiceSearch",
-    "MobileNTPBookmark",          "MobileNTPForeignSession",
-    "MobileNTPMostVisited",       "MobileNTPShowBookmarks",
-    "MobileNTPShowMostVisited",   "MobileNTPShowOpenTabs",
-    "MobileNTPSwitchToBookmarks", "MobileNTPSwitchToMostVisited",
-    "MobileNTPSwitchToOpenTabs",  "MobileTabStripNewTab",
-    "MobileToolbarNewTab",        "MobileToolbarStackViewNewTab",
-    "MobileToolbarVoiceSearch",   "OmniboxInputInProgress",
+    "MobileMenuAllBookmarks",
+    "MobileMenuHistory",
+    "MobileMenuNewIncognitoTab",
+    "MobileMenuNewTab",
+    "MobileMenuRecentTabs",
+    "MobileMenuVoiceSearch",
+    "MobileBookmarkManagerEntryOpened",
+    "MobileRecentTabManagerTabFromOtherDeviceOpened",
+    "MobileNTPMostVisited",
+    "MobileNTPShowBookmarks",
+    "MobileNTPShowMostVisited",
+    "MobileNTPShowOpenTabs",
+    "MobileNTPSwitchToBookmarks",
+    "MobileNTPSwitchToMostVisited",
+    "MobileNTPSwitchToOpenTabs",
+    "MobileTabStripNewTab",
+    "MobileToolbarNewTab",
+    "MobileToolbarStackViewNewTab",
+    "MobileToolbarVoiceSearch",
+    "OmniboxInputInProgress",
 };
 
 // Min and max values (in minutes) for the buckets in the duration histograms.
diff --git a/ios/chrome/browser/reading_list/url_downloader.cc b/ios/chrome/browser/reading_list/url_downloader.cc
index 096e5c97..f3213843 100644
--- a/ios/chrome/browser/reading_list/url_downloader.cc
+++ b/ios/chrome/browser/reading_list/url_downloader.cc
@@ -19,6 +19,20 @@
 #include "net/base/escape.h"
 #include "url/gurl.h"
 
+namespace {
+// This script disables context menu on img elements.
+// The pages are stored locally and long pressing on them will trigger a context
+// menu on the file:// URL which cannot be opened. Disable the context menu.
+const char kDisableImageContextMenuScript[] =
+    "<script>"
+    "document.addEventListener('DOMContentLoaded', function (event) {"
+    "    var imgMenuDisabler = document.createElement('style');"
+    "    imgMenuDisabler.innerHTML = 'img { -webkit-touch-callout: none; }';"
+    "    document.head.appendChild(imgMenuDisabler);"
+    "}, false);"
+    "</script>";
+}  // namespace
+
 // URLDownloader
 
 URLDownloader::URLDownloader(
@@ -214,6 +228,7 @@
     const std::vector<dom_distiller::DistillerViewerInterface::ImageInfo>&
         images) {
   std::string mutable_html = html;
+  bool local_images_found = false;
   for (size_t i = 0; i < images.size(); i++) {
     if (images[i].url.SchemeIs(url::kDataScheme)) {
       // Data URI, the data part of the image is empty, no need to store it.
@@ -228,10 +243,15 @@
     size_t image_url_size = image_url.size();
     size_t pos = mutable_html.find(image_url, 0);
     while (pos != std::string::npos) {
+      local_images_found = true;
       mutable_html.replace(pos, image_url_size, local_image_name);
       pos = mutable_html.find(image_url, pos + local_image_name.size());
     }
   }
+  if (local_images_found) {
+    mutable_html += kDisableImageContextMenuScript;
+  }
+
   return mutable_html;
 }
 
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index a9557a4..e2278140 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -143,6 +143,7 @@
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/ui/crw_generic_content_view.h"
 #include "ios/web/public/web_state/web_state.h"
+#import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #import "ios/web/web_state/web_state_impl.h"
@@ -201,6 +202,7 @@
 }  // namespace
 
 @interface Tab ()<BlockedPopupHandlerDelegate,
+                  CRWWebStateObserver,
                   CRWWebUserInterfaceDelegate,
                   FindInPageControllerDelegate,
                   ReaderModeControllerDelegate> {
@@ -306,6 +308,9 @@
   // WebStateImpl for this tab.
   std::unique_ptr<web::WebStateImpl> webStateImpl_;
 
+  // Allows Tab to conform CRWWebStateDelegate protocol.
+  std::unique_ptr<web::WebStateObserverBridge> webStateObserver_;
+
   // Context used by history to scope the lifetime of navigation entry
   // references to Tab.
   std::unique_ptr<TabHistoryContext> tabHistoryContext_;
@@ -549,6 +554,9 @@
         ios::ChromeBrowserState::FromBrowserState(webState->GetBrowserState());
 
     webStateImpl_.reset(static_cast<web::WebStateImpl*>(webState.release()));
+    webStateObserver_.reset(
+        new web::WebStateObserverBridge(webStateImpl_.get(), self));
+
     [self.webController setDelegate:self];
     [self.webController setUIDelegate:self];
 
@@ -1665,7 +1673,7 @@
   return [self tabId];
 }
 
-#pragma mark - WebDelegate protocol methods.
+#pragma mark - CRWWebDelegate and CRWWebStateObserver protocol methods.
 
 - (CRWWebController*)webPageOrderedOpen:(const GURL&)URL
                                referrer:(const web::Referrer&)referrer
@@ -1851,9 +1859,8 @@
   }
 }
 
-// Called when the page finishes loading, with the URL and a boolean indicating
-// if the page was successfully loaded.
-- (void)webDidFinishWithURL:(const GURL&)url loadSuccess:(BOOL)loadSuccess {
+- (void)webStateDidLoadPage:(web::WebState*)webState
+                withSuccess:(BOOL)loadSuccess {
   DCHECK(self.webController.loadPhase == web::PAGE_LOADED);
 
   // Cancel prerendering if response is "application/octet-stream". It can be a
@@ -1866,10 +1873,11 @@
   bool wasPost = false;
   if (self.currentSessionEntry)
     wasPost = self.currentSessionEntry.navigationItem->HasPostData();
+  GURL lastCommittedURL = self.webState->GetLastCommittedURL();
   if (loadSuccess)
-    [autoReloadBridge_ loadFinishedForURL:url wasPost:wasPost];
+    [autoReloadBridge_ loadFinishedForURL:lastCommittedURL wasPost:wasPost];
   else
-    [autoReloadBridge_ loadFailedForURL:url wasPost:wasPost];
+    [autoReloadBridge_ loadFailedForURL:lastCommittedURL wasPost:wasPost];
   [webControllerSnapshotHelper_ setSnapshotCoalescingEnabled:YES];
   if (!loadSuccess) {
     [fullScreenController_ disableFullScreen];
@@ -1877,9 +1885,10 @@
   [self recordInterfaceOrientation];
   navigation_metrics::OriginsSeenService* originsSeenService =
       IOSChromeOriginsSeenServiceFactory::GetForBrowserState(self.browserState);
-  bool already_seen = originsSeenService->Insert(url::Origin::Origin(url));
+  bool alreadySeen =
+      originsSeenService->Insert(url::Origin::Origin(lastCommittedURL));
   navigation_metrics::RecordMainFrameNavigation(
-      url, true, self.browserState->IsOffTheRecord(), already_seen);
+      lastCommittedURL, true, self.browserState->IsOffTheRecord(), alreadySeen);
 
   if (loadSuccess) {
     scoped_refptr<net::HttpResponseHeaders> headers =
@@ -1910,8 +1919,9 @@
   // If the tab switcher is not enabled, don't take snapshot of chrome scheme
   // pages.
   BOOL takeSnapshotOnIpad =
-      IsIPadIdiom() && (experimental_flags::IsTabSwitcherEnabled() ||
-                        !web::GetWebClient()->IsAppSpecificURL(url));
+      IsIPadIdiom() &&
+      (experimental_flags::IsTabSwitcherEnabled() ||
+       !web::GetWebClient()->IsAppSpecificURL(lastCommittedURL));
   // Always take snapshot on iPhone.
   BOOL takeSnapshot = !IsIPadIdiom() || takeSnapshotOnIpad;
   if (loadSuccess && takeSnapshot) {
@@ -2364,6 +2374,8 @@
   // Set the new web state.
   webStateImpl_.reset(webState.release());
   [self.webController setDelegate:self];
+  webStateObserver_.reset(
+      new web::WebStateObserverBridge(webStateImpl_.get(), self));
   // SessionTabHelper comes first because it sets up the tab ID, and other
   // helpers may rely on that.
   IOSChromeSessionTabHelper::CreateForWebState(webStateImpl_.get());
diff --git a/ios/chrome/browser/tabs/tab_model.h b/ios/chrome/browser/tabs/tab_model.h
index 1a008a2e..e2e0a8fe 100644
--- a/ios/chrome/browser/tabs/tab_model.h
+++ b/ios/chrome/browser/tabs/tab_model.h
@@ -115,10 +115,6 @@
 // Determines the number of tabs in the model.
 @property(nonatomic, readonly) NSUInteger count;
 
-// Returns the TabModel associated with |browserState|. May be null during
-// shutdown.
-+ (instancetype)tabModelForBrowserState:(ios::ChromeBrowserState*)browserState;
-
 // Initializes tabs from a restored session. |-setCurrentTab| needs to be called
 // in order to display the views associated with the tabs. Waits until the views
 // are ready. |browserState| cannot be nil. |service| cannot be nil; this class
@@ -126,7 +122,6 @@
 // session service before they are deallocated. |window| can be nil to create
 // an empty TabModel. In that case no notification will be sent during object
 // creation.
-// |browserState| will have the initialized TabModel stored as user data.
 - (instancetype)initWithSessionWindow:(SessionWindowIOS*)window
                        sessionService:(SessionServiceIOS*)service
                          browserState:(ios::ChromeBrowserState*)browserState
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm
index cab6b545..8bfb11f 100644
--- a/ios/chrome/browser/tabs/tab_model.mm
+++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -16,7 +16,6 @@
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/supports_user_data.h"
 #include "components/sessions/core/serialized_navigation_entry.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sessions/core/tab_restore_service.h"
@@ -99,23 +98,6 @@
       base::Bind(&RestoreCertificatePolicyCacheFromTabs, tabs));
 }
 
-// Wrapper class to attach a TabModel to a base::SupportsUserData object, such
-// as an ios::ChromeBrowserState. This wrapper retains the TabModel it wraps, so
-// any base::SupportsUserData object storing such a wrapper has ownership of the
-// TabModel.
-class TabModelHandle : public base::SupportsUserData::Data {
- public:
-  explicit TabModelHandle(TabModel* model) : tab_model_([model retain]) {}
-  ~TabModelHandle() override {}
-  TabModel* tab_model() { return tab_model_; }
-
- private:
-  base::scoped_nsobject<TabModel> tab_model_;
-};
-
-// Key for storing a TabModelHandle in a ChromeBrowserState.
-const char kTabModelKeyName[] = "tab_model";
-
 }  // anonymous namespace
 
 @interface TabModelObservers : CRBProtocolObservers<TabModelObserver>
@@ -245,14 +227,6 @@
   return [_tabs count];
 }
 
-+ (instancetype)tabModelForBrowserState:(ios::ChromeBrowserState*)browserState {
-  if (!browserState)
-    return nil;
-  TabModelHandle* handle =
-      static_cast<TabModelHandle*>(browserState->GetUserData(kTabModelKeyName));
-  return handle ? handle->tab_model() : nil;
-}
-
 - (instancetype)initWithSessionWindow:(SessionWindowIOS*)window
                        sessionService:(SessionServiceIOS*)service
                          browserState:(ios::ChromeBrowserState*)browserState {
@@ -325,9 +299,6 @@
                       selector:@selector(applicationWillEnterForeground:)
                           name:UIApplicationWillEnterForegroundNotification
                         object:nil];
-
-    // Store pointer to |self| in |_browserState|.
-    _browserState->SetUserData(kTabModelKeyName, new TabModelHandle(self));
   }
   return self;
 }
@@ -761,9 +732,6 @@
 // NOTE: This can be called multiple times, so must be robust against that.
 - (void)browserStateDestroyed {
   [[NSNotificationCenter defaultCenter] removeObserver:self];
-  if (_browserState) {
-    _browserState->RemoveUserData(kTabModelKeyName);
-  }
   _browserState = nullptr;
 }
 
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 367fbb9b..d99a886 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -219,16 +219,6 @@
   base::mac::ScopedNSAutoreleasePool pool_;
 };
 
-TEST_F(TabModelTest, IsStoredAsUserData) {
-  EXPECT_EQ(tabModel_,
-            [TabModel tabModelForBrowserState:chrome_browser_state_.get()]);
-  [tabModel_ browserStateDestroyed];
-  EXPECT_EQ(nil,
-            [TabModel tabModelForBrowserState:chrome_browser_state_.get()]);
-  // Verify that a null browser state doesn't break +tabModelForBrowserState.
-  EXPECT_EQ(nil, [TabModel tabModelForBrowserState:nullptr]);
-}
-
 TEST_F(TabModelTest, IsEmpty) {
   EXPECT_EQ([tabModel_ count], 0U);
   EXPECT_TRUE([tabModel_ isEmpty]);
diff --git a/ios/chrome/browser/tabs/tab_unittest.mm b/ios/chrome/browser/tabs/tab_unittest.mm
index b870481..2b49589 100644
--- a/ios/chrome/browser/tabs/tab_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_unittest.mm
@@ -243,8 +243,7 @@
     [tab_ webController:mock_web_controller_ titleDidChange:title];
     [[[(id)mock_web_controller_ expect]
         andReturnValue:OCMOCK_VALUE(kPageLoaded)] loadPhase];
-    [[tab_ webController] webStateImpl]->OnPageLoaded(redirectUrl, true);
-    [tab_ webDidFinishWithURL:redirectUrl loadSuccess:YES];
+    [tab_ webStateImpl]->OnPageLoaded(redirectUrl, true);
   }
 
   void BrowseToNewTab() {
@@ -259,7 +258,7 @@
     [tab_ webDidStartLoadingURL:url shouldUpdateHistory:YES];
     [[[(id)mock_web_controller_ expect]
         andReturnValue:OCMOCK_VALUE(kPageLoaded)] loadPhase];
-    [tab_ webDidFinishWithURL:url loadSuccess:YES];
+    [tab_ webStateImpl]->OnPageLoaded(url, true);
     [tab_ webController:mock_web_controller_ titleDidChange:kNewTabTitle];
   }
 
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm
index 6c0e9ce..e4e521b 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_tablet_ntp_controller.mm
@@ -436,7 +436,8 @@
 
   new_tab_page_uma::RecordAction(self.browserState,
                                  new_tab_page_uma::ACTION_OPENED_BOOKMARK);
-  base::RecordAction(base::UserMetricsAction("MobileNTPBookmark"));
+  base::RecordAction(
+      base::UserMetricsAction("MobileBookmarkManagerEntryOpened"));
   [_loader loadURL:url
                referrer:web::Referrer()
              transition:ui::PAGE_TRANSITION_AUTO_BOOKMARK
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
index 95c9cbf..44060eee 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_interaction_controller.mm
@@ -295,7 +295,8 @@
   if (url != GURL()) {
     new_tab_page_uma::RecordAction(_browserState,
                                    new_tab_page_uma::ACTION_OPENED_BOOKMARK);
-    base::RecordAction(base::UserMetricsAction("MobileNTPBookmark"));
+    base::RecordAction(
+        base::UserMetricsAction("MobileBookmarkManagerEntryOpened"));
 
     if (url.SchemeIs(url::kJavaScriptScheme)) {  // bookmarklet
       NSString* jsToEval = [base::SysUTF8ToNSString(url.GetContent())
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
index 10a9b92..d77d3d62 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller.mm
@@ -342,7 +342,8 @@
   [self dismissRecentTabsModal];
   if (openTabs->GetForeignTab(distantTab->session_tag, distantTab->tab_id,
                               &toLoad)) {
-    base::RecordAction(base::UserMetricsAction("MobileNTPForeignSession"));
+    base::RecordAction(base::UserMetricsAction(
+        "MobileRecentTabManagerTabFromOtherDeviceOpened"));
     new_tab_page_uma::RecordAction(
         _browserState, new_tab_page_uma::ACTION_OPENED_FOREIGN_SESSION);
     [_loader loadSessionTab:toLoad];
@@ -361,7 +362,8 @@
       TabRestoreServiceDelegateImplIOSFactory::GetForBrowserState(
           _browserState);
   [self dismissRecentTabsModal];
-  base::RecordAction(base::UserMetricsAction("MobileNTPRecentlyClosed"));
+  base::RecordAction(
+      base::UserMetricsAction("MobileRecentTabManagerRecentTabOpened"));
   new_tab_page_uma::RecordAction(
       _browserState, new_tab_page_uma::ACTION_OPENED_RECENTLY_CLOSED_ENTRY);
   _tabRestoreService->RestoreEntryById(delegate, entry->id,
diff --git a/ios/chrome/browser/ui/omnibox/page_info_model.cc b/ios/chrome/browser/ui/omnibox/page_info_model.cc
index 5967c3c..a524461 100644
--- a/ios/chrome/browser/ui/omnibox/page_info_model.cc
+++ b/ios/chrome/browser/ui/omnibox/page_info_model.cc
@@ -119,28 +119,12 @@
       description.assign(l10n_util::GetStringFUTF16(
           IDS_IOS_PAGE_INFO_SECURITY_TAB_SECURE_IDENTITY, issuer_name));
     }
-    // The date after which no new SHA-1 certificates may be issued.
-    // 2016-01-01 00:00:00 UTC
-    // WARNING: This value must be kept in sync with WebsiteSettings::Init() in
-    // chrome/browser/ui/website_settings/website_settings.cc.
-    static const int64_t kJanuary2016 = INT64_C(13096080000000000);
-    static const int64_t kJanuary2017 = INT64_C(13127702400000000);
-    if ((ssl.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT) &&
-        ssl.certificate->valid_expiry() >=
-            base::Time::FromInternalValue(kJanuary2016)) {
+    if (ssl.cert_status & net::CERT_STATUS_SHA1_SIGNATURE_PRESENT) {
       icon_id = ICON_STATE_INFO;
-      if (ssl.certificate->valid_expiry() >=
-          base::Time::FromInternalValue(kJanuary2017)) {
-        description +=
-            base::UTF8ToUTF16("\n\n") +
-            l10n_util::GetStringUTF16(
-                IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MAJOR);
-      } else {
-        description +=
-            base::UTF8ToUTF16("\n\n") +
-            l10n_util::GetStringUTF16(
-                IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM_MINOR);
-      }
+      description +=
+          base::UTF8ToUTF16("\n\n") +
+          l10n_util::GetStringUTF16(
+              IDS_PAGE_INFO_SECURITY_TAB_DEPRECATED_SIGNATURE_ALGORITHM);
     }
   } else {
     // HTTP or HTTPS with errors (not warnings).
diff --git a/ios/net/cookies/cookie_store_ios.h b/ios/net/cookies/cookie_store_ios.h
index 6108ee1..b58d14aa 100644
--- a/ios/net/cookies/cookie_store_ios.h
+++ b/ios/net/cookies/cookie_store_ios.h
@@ -80,11 +80,6 @@
   // Only one cookie store may enable metrics.
   void SetMetricsEnabled();
 
-  // Sets the delay between flushes. Only used in tests.
-  void set_flush_delay_for_testing(base::TimeDelta delay) {
-    flush_delay_ = delay;
-  }
-
   // Inherited CookieStore methods.
   void SetCookieWithOptionsAsync(const GURL& url,
                                  const std::string& cookie_line,
@@ -146,7 +141,6 @@
 
   enum SynchronizationState {
     NOT_SYNCHRONIZED,  // Uses CookieMonster as backend.
-    SYNCHRONIZING,     // Moves from NSHTTPCookieStorage to CookieMonster.
     SYNCHRONIZED       // Uses NSHTTPCookieStorage as backend.
   };
 
@@ -174,12 +168,9 @@
   base::scoped_nsobject<NSHTTPCookieStorage> system_store_;
   std::unique_ptr<CookieCreationTimeManager> creation_time_manager_;
   bool metrics_enabled_;
-  base::TimeDelta flush_delay_;
   base::CancelableClosure flush_closure_;
 
   SynchronizationState synchronization_state_;
-  // Tasks received when SYNCHRONIZING are queued and run when SYNCHRONIZED.
-  std::vector<base::Closure> tasks_pending_synchronization_;
 
   base::ThreadChecker thread_checker_;
 
@@ -252,15 +243,14 @@
   // OnSystemCookiesChanged is responsible for updating the cookie cache (and
   // hence running callbacks).
   //
-  // When this CookieStoreIOS object is not synchronized (or is synchronizing),
-  // the various mutator methods (SetCookieWithOptionsAsync &c) instead store
-  // their state in a CookieMonster object to be written back when the system
-  // store synchronizes. To deliver notifications in a timely manner, the
-  // mutators have to ensure that hooks get run, but only after the changes have
-  // been written back to CookieMonster. To do this, the mutators wrap the
-  // user-supplied callback in a callback which schedules an asynchronous task
-  // to synchronize the cache and run callbacks, then calls through to the
-  // user-specified callback.
+  // When this CookieStoreIOS object is not synchronized, the various mutator
+  // methods (SetCookieWithOptionsAsync &c) instead store their state in a
+  // CookieMonster object to be written back when the system store synchronizes.
+  // To deliver notifications in a timely manner, the mutators have to ensure
+  // that hooks get run, but only after the changes have been written back to
+  // CookieMonster. To do this, the mutators wrap the user-supplied callback in
+  // a callback which schedules an asynchronous task to synchronize the cache
+  // and run callbacks, then calls through to the user-specified callback.
   //
   // These three UpdateCachesAfter functions are responsible for scheduling an
   // asynchronous cache update (using UpdateCachesFromCookieMonster()) and
diff --git a/ios/net/cookies/cookie_store_ios.mm b/ios/net/cookies/cookie_store_ios.mm
index 149d22b..6853244 100644
--- a/ios/net/cookies/cookie_store_ios.mm
+++ b/ios/net/cookies/cookie_store_ios.mm
@@ -328,12 +328,6 @@
       cookie_monster_->SetCookieWithOptionsAsync(url, cookie_line, options,
                                                  WrapSetCallback(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::SetCookieWithOptionsAsync,
-                     weak_factory_.GetWeakPtr(), url, cookie_line, options,
-                     WrapSetCallback(callback)));
-      break;
     case SYNCHRONIZED:
       // The exclude_httponly() option would only be used by a javascript
       // engine.
@@ -406,14 +400,6 @@
           last_access_time, secure, http_only, same_site, enforce_strict_secure,
           priority, WrapSetCallback(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::SetCookieWithDetailsAsync,
-                     weak_factory_.GetWeakPtr(), url, name, value, domain, path,
-                     creation_time, expiration_time, last_access_time, secure,
-                     http_only, same_site, enforce_strict_secure, priority,
-                     WrapSetCallback(callback)));
-      break;
     case SYNCHRONIZED:
       // If cookies are not allowed, they are stashed in the CookieMonster, and
       // should be written there instead.
@@ -460,11 +446,6 @@
     case NOT_SYNCHRONIZED:
       cookie_monster_->GetCookiesWithOptionsAsync(url, options, callback);
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::GetCookiesWithOptionsAsync,
-                     weak_factory_.GetWeakPtr(), url, options, callback));
-      break;
     case SYNCHRONIZED:
       // If cookies are not allowed, they are stashed in the CookieMonster, and
       // should be read from there instead.
@@ -493,11 +474,6 @@
     case NOT_SYNCHRONIZED:
       cookie_monster_->GetCookieListWithOptionsAsync(url, options, callback);
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::GetCookieListWithOptionsAsync,
-                     weak_factory_.GetWeakPtr(), url, options, callback));
-      break;
     case SYNCHRONIZED:
       if (!SystemCookiesAllowed()) {
         // If cookies are not allowed, the cookies are stashed in the
@@ -525,11 +501,6 @@
     case NOT_SYNCHRONIZED:
       cookie_monster_->GetAllCookiesAsync(callback);
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::GetAllCookiesAsync,
-                     weak_factory_.GetWeakPtr(), callback));
-      break;
     case SYNCHRONIZED:
       if (!SystemCookiesAllowed()) {
         // If cookies are not allowed, the cookies are stashed in the
@@ -559,11 +530,6 @@
       cookie_monster_->DeleteCookieAsync(url, cookie_name,
                                          WrapClosure(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(base::Bind(
-          &CookieStoreIOS::DeleteCookieAsync, weak_factory_.GetWeakPtr(), url,
-          cookie_name, WrapClosure(callback)));
-      break;
     case SYNCHRONIZED:
       NSArray* cookies = GetCookiesForURL(system_store_,
                                           url, creation_time_manager_.get());
@@ -590,11 +556,6 @@
       cookie_monster_->DeleteCanonicalCookieAsync(cookie,
                                                   WrapDeleteCallback(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(base::Bind(
-          &CookieStoreIOS::DeleteCanonicalCookieAsync,
-          weak_factory_.GetWeakPtr(), cookie, WrapDeleteCallback(callback)));
-      break;
     case SYNCHRONIZED:
       // This relies on the fact cookies are given unique creation dates.
       CookieFilterFunction filter = base::Bind(
@@ -617,12 +578,6 @@
       cookie_monster_->DeleteAllCreatedBetweenAsync(
           delete_begin, delete_end, WrapDeleteCallback(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::DeleteAllCreatedBetweenAsync,
-                     weak_factory_.GetWeakPtr(), delete_begin, delete_end,
-                     WrapDeleteCallback(callback)));
-      break;
     case SYNCHRONIZED:
       CookieFilterFunction filter =
           base::Bind(&IsCookieCreatedBetween, delete_begin, delete_end);
@@ -646,12 +601,6 @@
       cookie_monster_->DeleteAllCreatedBetweenWithPredicateAsync(
           delete_begin, delete_end, predicate, WrapDeleteCallback(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::DeleteAllCreatedBetweenWithPredicateAsync,
-                     weak_factory_.GetWeakPtr(), delete_begin, delete_end,
-                     predicate, WrapDeleteCallback(callback)));
-      break;
     case SYNCHRONIZED:
       CookieFilterFunction filter =
           base::Bind(IsCookieCreatedBetweenWithPredicate, delete_begin,
@@ -671,11 +620,6 @@
     case NOT_SYNCHRONIZED:
       cookie_monster_->DeleteSessionCookiesAsync(WrapDeleteCallback(callback));
       break;
-    case SYNCHRONIZING:
-      tasks_pending_synchronization_.push_back(
-          base::Bind(&CookieStoreIOS::DeleteSessionCookiesAsync,
-                     weak_factory_.GetWeakPtr(), WrapDeleteCallback(callback)));
-      break;
     case SYNCHRONIZED:
       CookieFilterFunction filter = base::Bind(&IsCookieSessionCookie);
       DeleteCookiesWithFilter(filter, callback);
@@ -705,7 +649,6 @@
       system_store_(system_store),
       creation_time_manager_(new CookieCreationTimeManager),
       metrics_enabled_(false),
-      flush_delay_(base::TimeDelta::FromSeconds(10)),
       synchronization_state_(NOT_SYNCHRONIZED),
       cookie_cache_(new CookieCache()),
       weak_factory_(this) {
@@ -809,7 +752,7 @@
   flush_closure_.Reset(base::Bind(&CookieStoreIOS::FlushStore,
                                   weak_factory_.GetWeakPtr(), base::Closure()));
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, flush_closure_.callback(), flush_delay_);
+      FROM_HERE, flush_closure_.callback(), base::TimeDelta::FromSeconds(10));
 }
 
 std::unique_ptr<net::CookieStore::CookieChangedSubscription>
diff --git a/ios/web/public/web_state/ui/crw_web_delegate.h b/ios/web/public/web_state/ui/crw_web_delegate.h
index 2dc7fed..d299e3d 100644
--- a/ios/web/public/web_state/ui/crw_web_delegate.h
+++ b/ios/web/public/web_state/ui/crw_web_delegate.h
@@ -78,12 +78,6 @@
 // isn't a web concept, so this shoud be expressed differently.
 - (void)webDidStartLoadingURL:(const GURL&)url
           shouldUpdateHistory:(BOOL)updateHistory;
-// Called when the page finishes loading, with the URL, page title and load
-// success status. Phase will be PAGE_LOADED.
-// On the next navigation event, this will be followed by a call to
-// webWillStartLoadingURL.
-- (void)webDidFinishWithURL:(const GURL&)url
-                loadSuccess:(BOOL)loadSuccess;
 // Called when the page load was cancelled by page activity (before a success /
 // failure state is known). Phase will be PAGE_LOADED.
 - (void)webLoadCancelled:(const GURL&)url;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 038c51f..cad77de 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2405,10 +2405,8 @@
   }
 
   [self restoreStateFromHistory];
-  _webStateImpl->OnPageLoaded(currentURL, loadSuccess);
   _webStateImpl->SetIsLoading(false);
-  // Inform the embedder the load completed.
-  [_delegate webDidFinishWithURL:currentURL loadSuccess:loadSuccess];
+  _webStateImpl->OnPageLoaded(currentURL, loadSuccess);
 }
 
 - (void)goDelta:(int)delta {
diff --git a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
index d33321c..725cc1c 100644
--- a/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
+++ b/net/android/java/src/org/chromium/net/AndroidNetworkLibrary.java
@@ -10,6 +10,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
+import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
@@ -24,6 +25,7 @@
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.CalledByNativeUnchecked;
 
+import java.net.InetAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
 import java.net.URLConnection;
@@ -31,6 +33,7 @@
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
 import java.util.Enumeration;
+import java.util.List;
 
 /**
  * This class implements net utilities required by the net component.
@@ -261,4 +264,28 @@
         }
         return true;
     }
+
+    @TargetApi(Build.VERSION_CODES.M)
+    @CalledByNative
+    private static byte[][] getDnsServers(Context context) {
+        ConnectivityManager connectivityManager =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (connectivityManager == null) {
+            return new byte[0][0];
+        }
+        Network network = connectivityManager.getActiveNetwork();
+        if (network == null) {
+            return new byte[0][0];
+        }
+        LinkProperties linkProperties = connectivityManager.getLinkProperties(network);
+        if (linkProperties == null) {
+            return new byte[0][0];
+        }
+        List<InetAddress> dnsServersList = linkProperties.getDnsServers();
+        byte[][] dnsServers = new byte[dnsServersList.size()][];
+        for (int i = 0; i < dnsServersList.size(); i++) {
+            dnsServers[i] = dnsServersList.get(i).getAddress();
+        }
+        return dnsServers;
+    }
 }
diff --git a/net/android/network_library.cc b/net/android/network_library.cc
index 34a9194..7535952 100644
--- a/net/android/network_library.cc
+++ b/net/android/network_library.cc
@@ -11,6 +11,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/logging.h"
 #include "jni/AndroidNetworkLibrary_jni.h"
+#include "net/dns/dns_protocol.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
@@ -146,5 +147,22 @@
           base::android::GetApplicationContext()));
 }
 
+void GetDnsServers(std::vector<IPEndPoint>* dns_servers) {
+  JNIEnv* env = AttachCurrentThread();
+  std::vector<std::string> dns_servers_strings;
+  base::android::JavaArrayOfByteArrayToStringVector(
+      env, Java_AndroidNetworkLibrary_getDnsServers(
+               env, base::android::GetApplicationContext())
+               .obj(),
+      &dns_servers_strings);
+  for (const std::string& dns_address_string : dns_servers_strings) {
+    IPAddress dns_address(
+        reinterpret_cast<const uint8_t*>(dns_address_string.c_str()),
+        dns_address_string.size());
+    IPEndPoint dns_server(dns_address, dns_protocol::kDefaultPort);
+    dns_servers->push_back(dns_server);
+  }
+}
+
 }  // namespace android
 }  // namespace net
diff --git a/net/android/network_library.h b/net/android/network_library.h
index 2045346..b72cb259 100644
--- a/net/android/network_library.h
+++ b/net/android/network_library.h
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "net/android/cert_verify_result_android.h"
+#include "net/base/ip_endpoint.h"
 #include "net/base/mime_util.h"
 #include "net/base/net_export.h"
 
@@ -78,6 +79,10 @@
 // Otherwise, returns empty string.
 NET_EXPORT_PRIVATE std::string GetWifiSSID();
 
+// Gets the DNS servers and puts them in |dns_servers|.
+// Only callable on Marshmallow and newer releases.
+NET_EXPORT_PRIVATE void GetDnsServers(std::vector<IPEndPoint>* dns_servers);
+
 }  // namespace android
 }  // namespace net
 
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc
index ba8a369..c9c9d92 100644
--- a/net/dns/dns_config_service_posix.cc
+++ b/net/dns/dns_config_service_posix.cc
@@ -31,6 +31,8 @@
 
 #if defined(OS_ANDROID)
 #include <sys/system_properties.h>
+#include "base/android/build_info.h"
+#include "net/android/network_library.h"
 #include "net/base/network_change_notifier.h"
 #endif
 
@@ -170,6 +172,14 @@
 // TODO(juliatuttle): Depend on libcutils, then switch this (and other uses of
 //                    __system_property_get) to property_get.
 ConfigParsePosixResult ReadDnsConfig(DnsConfig* dns_config) {
+  if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+      base::android::SDK_VERSION_MARSHMALLOW) {
+    dns_config->nameservers.clear();
+    net::android::GetDnsServers(&dns_config->nameservers);
+    if (dns_config->nameservers.empty())
+      return CONFIG_PARSE_POSIX_NO_NAMESERVERS;
+    return CONFIG_PARSE_POSIX_OK;
+  }
   char property_value[PROP_VALUE_MAX];
   __system_property_get("net.dns1", property_value);
   std::string dns1_string = property_value;
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index e7b4227f..80ec0ec8 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -2089,6 +2089,13 @@
 // }
 EVENT_TYPE(SERVICE_WORKER_FETCH_EVENT)
 
+// This event is emitted when a request for a service worker script or its
+// imported scripts could not be handled.
+// {
+//   "error": The error reason as a string.
+// }
+EVENT_TYPE(SERVICE_WORKER_SCRIPT_LOAD_UNHANDLED_REQUEST_ERROR)
+
 // ------------------------------------------------------------------------
 // Global events
 // ------------------------------------------------------------------------
diff --git a/ppapi/proxy/ppb_image_data_proxy.cc b/ppapi/proxy/ppb_image_data_proxy.cc
index 6c04fc42..c04f2aa 100644
--- a/ppapi/proxy/ppb_image_data_proxy.cc
+++ b/ppapi/proxy/ppb_image_data_proxy.cc
@@ -404,10 +404,6 @@
   // We need to add a method to TransportDIB to release the handles.
 }
 
-SkCanvas* PlatformImageData::GetPlatformCanvas() {
-  return mapped_canvas_.get();
-}
-
 SkCanvas* PlatformImageData::GetCanvas() {
   return mapped_canvas_.get();
 }
@@ -443,10 +439,6 @@
     shm_.Unmap();
 }
 
-SkCanvas* SimpleImageData::GetPlatformCanvas() {
-  return NULL;  // No canvas available.
-}
-
 SkCanvas* SimpleImageData::GetCanvas() {
   return NULL;  // No canvas available.
 }
diff --git a/ppapi/proxy/ppb_image_data_proxy.h b/ppapi/proxy/ppb_image_data_proxy.h
index 2b39aa0..8201b44 100644
--- a/ppapi/proxy/ppb_image_data_proxy.h
+++ b/ppapi/proxy/ppb_image_data_proxy.h
@@ -95,7 +95,6 @@
   // PPB_ImageData API.
   void* Map() override;
   void Unmap() override;
-  SkCanvas* GetPlatformCanvas() override;
   SkCanvas* GetCanvas() override;
 
   static ImageHandle NullHandle();
@@ -123,7 +122,6 @@
   // PPB_ImageData API.
   void* Map() override;
   void Unmap() override;
-  SkCanvas* GetPlatformCanvas() override;
   SkCanvas* GetCanvas() override;
 
  private:
diff --git a/ppapi/thunk/ppb_image_data_api.h b/ppapi/thunk/ppb_image_data_api.h
index ec2a716..af1eaef 100644
--- a/ppapi/thunk/ppb_image_data_api.h
+++ b/ppapi/thunk/ppb_image_data_api.h
@@ -31,19 +31,6 @@
   virtual int32_t GetSharedMemory(base::SharedMemory** shm,
                                   uint32_t* byte_count) = 0;
 
-  // Get the platform-specific canvas that backs this ImageData, if there is
-  // one.
-  // The canvas will be NULL:
-  //   * If the image is not mapped.
-  //   * Within untrusted code (which does not have skia).
-  //   * If the ImageData is not backed by a platform-specific image buffer.
-  //     This will be the case for ImageDatas created for use in NaCl.
-  // For this last reason, you should prefer GetCanvas any time you don't need
-  // a platform-specific canvas (e.g., for use with platform-specific APIs).
-  // Anything that relies on having a PlatformCanvas will not work for ImageDat
-  // objects created from NaCl.
-  virtual SkCanvas* GetPlatformCanvas() = 0;
-
   // Get the canvas that backs this ImageData, if there is one.
   // The canvas will be NULL:
   //   * If the image is not mapped.
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index db9b5423..1306231c 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -367,8 +367,6 @@
   # Select the right BitmapPlatformDevice.
   if (is_win) {
     sources += [ "ext/bitmap_platform_device_win.cc" ]
-  } else if (!is_ios) {
-    sources += [ "ext/bitmap_platform_device_skia.cc" ]
   }
 
   if (is_clang && !is_nacl) {
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 476dc577..f46b942 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -234,6 +234,10 @@
 #   define SK_SUPPORT_LEGACY_CLIPOP_EXOTIC_NAMES
 #endif
 
+#ifndef    SK_SUPPORT_LEGACY_QUAD_SHIFT
+#   define SK_SUPPORT_LEGACY_QUAD_SHIFT
+#endif
+
 ///////////////////////// Imported from BUILD.gn and skia_common.gypi
 
 /* In some places Skia can use static initializers for global initialization,
diff --git a/skia/ext/bitmap_platform_device_skia.cc b/skia/ext/bitmap_platform_device_skia.cc
deleted file mode 100644
index 5904d6f2..0000000
--- a/skia/ext/bitmap_platform_device_skia.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "skia/ext/bitmap_platform_device_skia.h"
-#include "skia/ext/platform_canvas.h"
-
-namespace skia {
-
-BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
-                                                   bool is_opaque) {
-  return Create(width, height, is_opaque, nullptr);
-}
-
-BitmapPlatformDevice* BitmapPlatformDevice::Create(int width, int height,
-                                                   bool is_opaque,
-                                                   uint8_t* data) {
-  SkBitmap bitmap;
-  bitmap.setInfo(SkImageInfo::MakeN32(width, height,
-      is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType));
-
-  if (data) {
-    bitmap.setPixels(data);
-  } else {
-      if (!bitmap.tryAllocPixels())
-        return nullptr;
-      // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if
-      // it is not opaque.
-      if (!is_opaque)
-        bitmap.eraseARGB(0, 0, 0, 0);
-  }
-
-  return new BitmapPlatformDevice(bitmap);
-}
-
-BitmapPlatformDevice::BitmapPlatformDevice(const SkBitmap& bitmap)
-    : SkBitmapDevice(bitmap) {
-  SetPlatformDevice(this, this);
-}
-
-BitmapPlatformDevice::~BitmapPlatformDevice() {
-}
-
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const CreateInfo& info,
-                                                   const SkPaint*) {
-  SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
-  return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(),
-                                      info.fInfo.isOpaque());
-}
-
-// PlatformCanvas impl
-
-std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels(
-    int width,
-    int height,
-    bool is_opaque,
-    uint8_t* data,
-    OnFailureType failureType) {
-  sk_sp<SkBaseDevice> dev(
-      BitmapPlatformDevice::Create(width, height, is_opaque, data));
-  return CreateCanvas(dev, failureType);
-}
-
-}  // namespace skia
diff --git a/skia/ext/bitmap_platform_device_skia.h b/skia/ext/bitmap_platform_device_skia.h
deleted file mode 100644
index 42a3be1..0000000
--- a/skia/ext/bitmap_platform_device_skia.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SKIA_EXT_BITMAP_PLATFORM_DEVICE_SKIA_H_
-#define SKIA_EXT_BITMAP_PLATFORM_DEVICE_SKIA_H_
-
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "skia/ext/platform_device.h"
-
-namespace skia {
-
-// -----------------------------------------------------------------------------
-// For now we just use SkBitmap for SkBitmapDevice
-//
-// This is all quite ok for test_shell. In the future we will want to use
-// shared memory between the renderer and the main process at least. In this
-// case we'll probably create the buffer from a precreated region of memory.
-// -----------------------------------------------------------------------------
-class BitmapPlatformDevice final : public SkBitmapDevice,
-                                   public PlatformDevice {
- public:
-  // Construct a BitmapPlatformDevice. |is_opaque| should be set if the caller
-  // knows the bitmap will be completely opaque and allows some optimizations
-  // (the bitmap is not initialized to 0 when is_opaque == true).
-  static BitmapPlatformDevice* Create(int width, int height, bool is_opaque);
-
-  // This doesn't take ownership of |data|. If |data| is null and |is_opaque|
-  // is false, the bitmap is initialized to 0.
-  //
-  // Note: historicaly, BitmapPlatformDevice impls have had diverging
-  // initialization behavior for null |data| (Cairo used to initialize, while
-  // the others did not).  For now we stick to the more conservative Cairo
-  // behavior.
-  static BitmapPlatformDevice* Create(int width, int height, bool is_opaque,
-                                      uint8_t* data);
-
-  // Create a BitmapPlatformDevice from an already constructed bitmap;
-  // you should probably be using Create(). This may become private later if
-  // we ever have to share state between some native drawing UI and Skia, like
-  // the Windows and Mac versions of this class do.
-  explicit BitmapPlatformDevice(const SkBitmap& other);
-  ~BitmapPlatformDevice() override;
-
- protected:
-  SkBaseDevice* onCreateDevice(const CreateInfo&, const SkPaint*) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice);
-};
-
-}  // namespace skia
-
-#endif  // SKIA_EXT_BITMAP_PLATFORM_DEVICE_SKIA_H_
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc
index 34b7e2f..41c121c 100644
--- a/skia/ext/bitmap_platform_device_win.cc
+++ b/skia/ext/bitmap_platform_device_win.cc
@@ -8,6 +8,7 @@
 
 #include "base/debug/gdi_debug_util_win.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/win/win_util.h"
 #include "skia/ext/bitmap_platform_device_win.h"
 #include "skia/ext/platform_canvas.h"
@@ -210,9 +211,15 @@
     bool is_opaque,
     HANDLE shared_section,
     OnFailureType failureType) {
-  sk_sp<SkBaseDevice> dev(
+  sk_sp<SkBaseDevice> device(
       BitmapPlatformDevice::Create(width, height, is_opaque, shared_section));
-  return CreateCanvas(dev, failureType);
+  if (!device) {
+    if (CRASH_ON_FAILURE == failureType)
+      SK_CRASH();
+    return nullptr;
+  }
+
+  return base::MakeUnique<SkCanvas>(device.get());
 }
 
 }  // namespace skia
diff --git a/skia/ext/platform_canvas.cc b/skia/ext/platform_canvas.cc
index 81f8ff58..cf67ac5d 100644
--- a/skia/ext/platform_canvas.cc
+++ b/skia/ext/platform_canvas.cc
@@ -62,16 +62,6 @@
   return 4 * width;
 }
 
-std::unique_ptr<SkCanvas> CreateCanvas(const sk_sp<SkBaseDevice>& device,
-                                       OnFailureType failureType) {
-  if (!device) {
-    if (CRASH_ON_FAILURE == failureType)
-      SK_CRASH();
-    return nullptr;
-  }
-  return base::MakeUnique<SkCanvas>(device.get());
-}
-
 SkMetaData& GetMetaData(const SkCanvas& canvas) {
   return const_cast<SkCanvas&>(canvas).getMetaData();
 }
@@ -86,4 +76,37 @@
 }
 #endif
 
+#if !defined(WIN32)
+
+std::unique_ptr<SkCanvas> CreatePlatformCanvasWithPixels(
+    int width,
+    int height,
+    bool is_opaque,
+    uint8_t* data,
+    OnFailureType failureType) {
+
+  SkBitmap bitmap;
+  bitmap.setInfo(SkImageInfo::MakeN32(width, height,
+      is_opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType));
+
+  if (data) {
+    bitmap.setPixels(data);
+  } else {
+      if (!bitmap.tryAllocPixels()) {
+        if (CRASH_ON_FAILURE == failureType)
+          SK_CRASH();
+        return nullptr;
+      }
+
+      // Follow the logic in SkCanvas::createDevice(), initialize the bitmap if
+      // it is not opaque.
+      if (!is_opaque)
+        bitmap.eraseARGB(0, 0, 0, 0);
+  }
+
+  return base::MakeUnique<SkCanvas>(bitmap);
+}
+
+#endif
+
 }  // namespace skia
diff --git a/skia/ext/platform_canvas.h b/skia/ext/platform_canvas.h
index dea8ae82..11bc398 100644
--- a/skia/ext/platform_canvas.h
+++ b/skia/ext/platform_canvas.h
@@ -14,10 +14,9 @@
 #include "skia/ext/native_drawing_context.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-#include "third_party/skia/include/core/SkPixmap.h"
 
-class SkBaseDevice;
+class SkCanvas;
+class SkPixmap;
 
 // A PlatformCanvas is a software-rasterized SkCanvas which is *also*
 // addressable by the platform-specific drawing API (GDI, Core Graphics,
@@ -74,14 +73,11 @@
   return CreatePlatformCanvasWithSharedSection(width, height, is_opaque, 0,
                                                CRASH_ON_FAILURE);
 #else
-  return CreatePlatformCanvasWithPixels(width, height, is_opaque, 0,
+  return CreatePlatformCanvasWithPixels(width, height, is_opaque, nullptr,
                                         CRASH_ON_FAILURE);
 #endif
 }
 
-SK_API std::unique_ptr<SkCanvas> CreateCanvas(const sk_sp<SkBaseDevice>& device,
-                                              OnFailureType failure_type);
-
 static inline std::unique_ptr<SkCanvas> TryCreateBitmapCanvas(int width,
                                                               int height,
                                                               bool is_opaque) {
@@ -89,7 +85,7 @@
   return CreatePlatformCanvasWithSharedSection(width, height, is_opaque, 0,
                                                RETURN_NULL_ON_FAILURE);
 #else
-  return CreatePlatformCanvasWithPixels(width, height, is_opaque, 0,
+  return CreatePlatformCanvasWithPixels(width, height, is_opaque, nullptr,
                                         RETURN_NULL_ON_FAILURE);
 #endif
 }
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index d355317a..59411c9 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -5290,6 +5290,22 @@
     "isolated_scripts": [
       {
         "args": [
+          "-v"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Linux"
+            }
+          ]
+        }
+      },
+      {
+        "args": [
           "context_lost",
           "--show-stdout",
           "--browser=release",
@@ -9790,6 +9806,22 @@
     "isolated_scripts": [
       {
         "args": [
+          "-v"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Linux"
+            }
+          ]
+        }
+      },
+      {
+        "args": [
           "webgl_conformance",
           "--show-stdout",
           "--browser=release",
@@ -10318,6 +10350,22 @@
     "isolated_scripts": [
       {
         "args": [
+          "-v"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        }
+      },
+      {
+        "args": [
           "webgl_conformance",
           "--show-stdout",
           "--browser=release",
@@ -16322,6 +16370,22 @@
     "isolated_scripts": [
       {
         "args": [
+          "-v"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "10de:104a",
+              "os": "Windows-2008ServerR2-SP1"
+            }
+          ]
+        }
+      },
+      {
+        "args": [
           "context_lost",
           "--show-stdout",
           "--browser=release",
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index b6d2d06..ed0a886 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -21,30 +21,34 @@
 crbug.com/575210 virtual/mojo-loading/http/tests/navigation/history-back-across-form-submission-to-fragment.html [ Timeout ]
 
 # https://crbug.com/551000: PlzNavigate: DevTools support
-crbug.com/551000 http/tests/inspector-protocol/reload-memory-cache.html [ Failure ]
-crbug.com/551000 http/tests/inspector/console-resource-errors.html [ Failure ]
 crbug.com/551000 http/tests/inspector/extensions-ignore-cache.html [ Failure ]
 crbug.com/551000 http/tests/inspector/extensions-network-redirect.html [ Timeout ]
-crbug.com/551000 http/tests/inspector/network/network-datareceived.html [ Failure ]
-crbug.com/551000 http/tests/inspector/network/network-document-initiator.html [ Failure ]
-crbug.com/551000 http/tests/inspector/network/network-initiator.html [ Failure ]
 crbug.com/551000 http/tests/inspector/network/x-frame-options-deny.html [ Failure ]
-crbug.com/551000 http/tests/inspector/resource-har-conversion.html [ Failure ]
-crbug.com/551000 http/tests/inspector/resource-parameters-ipv6.html [ Failure Timeout ]
-crbug.com/551000 http/tests/inspector/resource-parameters.html [ Failure ]
-crbug.com/551000 http/tests/inspector/service-workers/service-workers-redundant.html [ Timeout ]
-crbug.com/551000 http/tests/inspector/service-workers/user-agent-override.html [ Failure ]
-crbug.com/551000 inspector-protocol/page/frameAttachedDetached.html [ Failure ]
-crbug.com/551000 inspector-protocol/page/frameStartedLoading.html [ Failure ]
-crbug.com/551000 virtual/mojo-loading/http/tests/inspector-protocol/reload-memory-cache.html [ Failure ]
-crbug.com/551000 virtual/mojo-loading/http/tests/inspector/console-resource-errors.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/extensions-ignore-cache.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/extensions-network-redirect.html [ Timeout ]
+crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/x-frame-options-deny.html [ Failure ]
+#  Encoded bytes received & encoded data length mismatch.
+crbug.com/551000 http/tests/inspector/network/network-datareceived.html [ Failure ]
+crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/network-datareceived.html [ Failure ]
+#  We don't set the right caching policy in the renderer when DevTools overrides the caching policy in reloads.
+crbug.com/551000 http/tests/inspector-protocol/reload-memory-cache.html [ Failure ]
+crbug.com/551000 virtual/mojo-loading/http/tests/inspector-protocol/reload-memory-cache.html [ Failure ]
+#  Console error messages are wrongly ordered.
+crbug.com/551000 http/tests/inspector/console-resource-errors.html [ Failure ]
+crbug.com/551000 virtual/mojo-loading/http/tests/inspector/console-resource-errors.html [ Failure ]
+#  We don't report the right initiator type or line number.
+crbug.com/551000 http/tests/inspector/network/network-document-initiator.html [ Failure ]
+crbug.com/551000 http/tests/inspector/network/network-initiator.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/network-document-initiator.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/network/network-initiator.html [ Failure ]
+#  We are missing several parameters in network har reports.
+crbug.com/551000 http/tests/inspector/resource-har-conversion.html [ Failure ]
+crbug.com/551000 http/tests/inspector/resource-parameters.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/resource-har-conversion.html [ Failure ]
 crbug.com/551000 virtual/mojo-loading/http/tests/inspector/resource-parameters.html [ Failure ]
-crbug.com/625765 virtual/mojo-loading/http/tests/inspector/network/x-frame-options-deny.html [ Failure ]
+#  Duplicate started loading output.
+crbug.com/551000 inspector-protocol/page/frameAttachedDetached.html [ Failure ]
+crbug.com/551000 inspector-protocol/page/frameStartedLoading.html [ Failure ]
 
 # https://crbug.com/625765: Need to solve duplicate output from
 # WebFrameTestClient::willSendRequest() that causes text failures.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 84bc1eea..b9c9381 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1711,25 +1711,25 @@
 crbug.com/490015 virtual/stable/http/tests/navigation/same-and-different-back.html [ Skip ]
 
 # ====== New tests from w3c-test-autoroller added here ======
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html [ Timeout ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/animation-model/animation-types/addition-per-property.html [ Timeout ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/syntax/parsing/html5lib_innerHTML_webkit02.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/interfaces/KeyframeEffect/composite.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/animation-model/combining-effects/effect-composition.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/syntax/parsing/html5lib_innerHTML_foreign-fragment.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/syntax/parsing/html5lib_innerHTML_adoption01.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/interfaces/KeyframeEffect/copy-contructor.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/browsers/history/the-location-interface/location-pathname-setter-question-mark.html [ Failure ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html [ Timeout ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/dynamic-append.html [ Timeout ]
-crbug.com/626703 [ Trusty Mac10.11 Mac10.10 Retina Win7 Win10 Mac10.9 ] imported/wpt/html/semantics/interfaces.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-transform.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/animation-model/animation-types/interpolation-per-property.html [ Timeout ]
+crbug.com/626703 imported/wpt/web-animations/interfaces/KeyframeEffectReadOnly/copy-contructor.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-shapes.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/animation-model/animation-types/addition-per-property.html [ Timeout ]
+crbug.com/626703 imported/wpt/user-timing/test_user_timing_mark_and_measure_exception_when_invoke_with_timing_attributes.html [ Failure ]
+crbug.com/626703 imported/wpt/html/syntax/parsing/html5lib_innerHTML_webkit02.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/interfaces/KeyframeEffect/composite.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/animation-model/combining-effects/effect-composition.html [ Failure ]
+crbug.com/626703 imported/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure ]
+crbug.com/626703 imported/wpt/html/syntax/parsing/html5lib_innerHTML_foreign-fragment.html [ Failure ]
+crbug.com/626703 imported/wpt/html/syntax/parsing/html5lib_innerHTML_adoption01.html [ Failure ]
+crbug.com/626703 imported/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/interfaces/KeyframeEffect/copy-contructor.html [ Failure ]
+crbug.com/626703 imported/wpt/web-animations/animation-model/animation-types/spacing-keyframes-filters.html [ Failure ]
+crbug.com/626703 imported/wpt/html/browsers/history/the-location-interface/location-pathname-setter-question-mark.html [ Failure ]
+crbug.com/626703 imported/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/moving-documents.html [ Timeout ]
+crbug.com/626703 imported/wpt/html/semantics/document-metadata/the-meta-element/pragma-directives/attr-meta-http-equiv-refresh/dynamic-append.html [ Timeout ]
+crbug.com/626703 imported/wpt/html/semantics/interfaces.html [ Failure ]
 crbug.com/626703 imported/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_drag-manual.html [ Timeout ]
 crbug.com/626703 imported/wpt/pointerevents/pointerevent_sequence_at_implicit_release_on_click-manual.html [ Timeout ]
 crbug.com/626703 imported/wpt/clear-site-data/navigation.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/importScripts.html b/third_party/WebKit/LayoutTests/http/tests/serviceworker/importScripts.html
new file mode 100644
index 0000000..3c5cf25
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/importScripts.html
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests for importScripts</title>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.js"></script>
+<body>
+<script>
+function post_and_wait_for_reply(worker, message) {
+  return new Promise(resolve => {
+      navigator.serviceWorker.onmessage = e => { resolve(e.data); };
+      worker.postMessage(message);
+    });
+}
+
+// This test registers a worker that imports a script multiple times. The
+// script should be stored on the first import and thereafter that stored
+// script should be loaded. The worker asserts that the stored script was
+// loaded; if the assert fails then registration fails.
+promise_test(t => {
+    const scope = 'resources/duplicate-import';
+    return service_worker_unregister(t, scope)
+      .then(() => {
+          return navigator.serviceWorker.register(
+              'resources/duplicate-import-worker.js', {scope: scope});
+        })
+      .then(r => { add_completion_callback(() => r.unregister()); });
+  }, 'import the same script URL multiple times');
+
+// This test registers a worker that calls importScripts at various stages of
+// service worker lifetime. The worker asserts that the scripts are imported
+// successfully and responds to a message with OK if so.
+promise_test(t => {
+    const scope = 'resources/import-scripts';
+    let registration;
+    return service_worker_unregister_and_register(
+        t, 'resources/import-scripts-worker.js', scope)
+      .then(r => {
+          registration = r;
+          add_completion_callback(() => { registration.unregister(); });
+          return wait_for_state(t, registration.installing, 'activated');
+        })
+      .then(() => {
+          return post_and_wait_for_reply(registration.active, 'ping');
+        })
+      .then(data => {
+          assert_equals(data, "OK");
+          return registration.unregister();
+        });
+  }, 'call importScript at various stages of service worker lifetime');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/duplicate-import-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/duplicate-import-worker.js
new file mode 100644
index 0000000..6393e3d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/duplicate-import-worker.js
@@ -0,0 +1,14 @@
+importScripts('../../resources/testharness.js');
+
+let version = null;
+importScripts('get-version.php');
+// Once imported, the stored script should be loaded for subsequent importScripts.
+const expected_version = version;
+
+version = null;
+importScripts('get-version.php');
+assert_equals(expected_version, version, 'second import');
+
+version = null;
+importScripts('get-version.php', 'get-version.php', 'get-version.php');
+assert_equals(expected_version, version, 'multiple imports');
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/echo.php b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/echo.php
new file mode 100644
index 0000000..ce35d85
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/echo.php
@@ -0,0 +1,7 @@
+<?php
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+header('Content-Type: application/javascript');
+
+echo "echo_output = '" . $_SERVER['QUERY_STRING'] . "';\n";
+?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/get-version.php b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/get-version.php
new file mode 100644
index 0000000..a68cada
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/get-version.php
@@ -0,0 +1,7 @@
+<?php
+header("Cache-Control: no-cache, must-revalidate");
+header("Pragma: no-cache");
+header('Content-Type:application/javascript');
+
+echo "version = '" . microtime() . "';\n";
+?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/import-scripts-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/import-scripts-worker.js
new file mode 100644
index 0000000..c3c5fac
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/resources/import-scripts-worker.js
@@ -0,0 +1,26 @@
+importScripts('../../resources/testharness.js');
+
+let echo_output = null;
+
+// Tests importing a script that sets |echo_output| to the query string.
+function test_import(str) {
+  importScripts('echo.php?' + str);
+  assert_equals(echo_output, str);
+}
+
+test_import('root');
+test_import('root-and-message');
+
+self.addEventListener('install', () => {
+    test_import('install');
+    test_import('install-and-message');
+  });
+
+self.addEventListener('message', e => {
+    test_import('root-and-message');
+    test_import('install-and-message');
+    // TODO(falken): This should fail. The spec disallows importing a non-cached
+    // script like this but currently Chrome and Firefox allow it.
+    test_import('message');
+    e.source.postMessage('OK');
+  });
diff --git a/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/aborting.js b/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/aborting.js
index 87b25e72c..ee4eaea 100644
--- a/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/aborting.js
+++ b/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/aborting.js
@@ -250,15 +250,14 @@
 }, 'Aborting a WritableStream after it is closed is a no-op');
 
 promise_test(t => {
+  // Testing that per https://github.com/whatwg/streams/issues/620#issuecomment-263483953 the fallback to close was
+  // removed.
+
   // Cannot use recordingWritableStream since it always has an abort
-  let controller;
-  let closeArgs;
+  let closeCalled = false;
   const ws = new WritableStream({
-    start(c) {
-      controller = c;
-    },
-    close(...args) {
-      closeArgs = args;
+    close() {
+      closeCalled = true;
     }
   });
 
@@ -267,9 +266,9 @@
   writer.abort();
 
   return promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError').then(() => {
-    assert_array_equals(closeArgs, [controller], 'close must have been called, with the controller as its argument');
+    assert_false(closeCalled, 'close must not have been called');
   });
-}, 'WritableStream should call underlying sink\'s close if no abort is supplied');
+}, 'WritableStream should NOT call underlying sink\'s close if no abort is supplied (historical)');
 
 promise_test(() => {
   let thenCalled = false;
diff --git a/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/general.js b/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/general.js
index 891b252..c284338 100644
--- a/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/general.js
+++ b/third_party/WebKit/LayoutTests/http/tests/streams/writable-streams/general.js
@@ -173,7 +173,9 @@
   const writer2 = ws2.getWriter();
   writer2.abort();
 
-  // Test PromiseInvokeOrFallbackOrNoop.
+  // Test abort() with a close underlying sink method present. (Historical; see
+  // https://github.com/whatwg/streams/issues/620#issuecomment-263483953 for what used to be
+  // tested here. But more coverage can't hurt.)
   const ws3 = new WritableStream({
     start: functionWithOverloads,
     write: functionWithOverloads,
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 2199e569..47df5cc4 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -980,7 +980,6 @@
   bool isDNSPrefetchEnabled() const { return m_isDNSPrefetchEnabled; }
   void parseDNSPrefetchControlHeader(const String&);
 
-  using ExecutionContext::postTask;
   void postTask(TaskType,
                 const WebTraceLocation&,
                 std::unique_ptr<ExecutionContextTask>,
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
index 8d7a370..ef843ee04 100644
--- a/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
+++ b/third_party/WebKit/Source/core/dom/ExecutionContext.cpp
@@ -167,13 +167,6 @@
   return virtualCompleteURL(url);
 }
 
-void ExecutionContext::postTask(const WebTraceLocation& location,
-                                std::unique_ptr<ExecutionContextTask> task,
-                                const String& taskNameForInstrumentation) {
-  postTask(TaskType::Unspecified, location, std::move(task),
-           taskNameForInstrumentation);
-}
-
 void ExecutionContext::allowWindowInteraction() {
   ++m_windowInteractionTokens;
 }
diff --git a/third_party/WebKit/Source/core/dom/ExecutionContext.h b/third_party/WebKit/Source/core/dom/ExecutionContext.h
index 470734e..a1e1162 100644
--- a/third_party/WebKit/Source/core/dom/ExecutionContext.h
+++ b/third_party/WebKit/Source/core/dom/ExecutionContext.h
@@ -100,9 +100,6 @@
       const WebTraceLocation&,
       std::unique_ptr<ExecutionContextTask>,
       const String& taskNameForInstrumentation = emptyString()) = 0;
-  void postTask(const WebTraceLocation&,
-                std::unique_ptr<ExecutionContextTask>,
-                const String& taskNameForInstrumentation = emptyString());
 
   // Gets the DOMTimerCoordinator which maintains the "active timer
   // list" of tasks created by setTimeout and setInterval. The
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
index 2ae662c..2d0ba638 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.cpp
@@ -33,7 +33,7 @@
     case TaskType::Sensor:
     case TaskType::Timer:
     case TaskType::UnspecedTimer:
-    case TaskType::Unspecified:
+    case TaskType::MiscPlatformAPI:
       return frame ? frame->frameScheduler()->timerTaskRunner()
                    : Platform::current()->currentThread()->getWebTaskRunner();
     case TaskType::UnspecedLoading:
diff --git a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
index 1c217c8..af9cda1 100644
--- a/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
+++ b/third_party/WebKit/Source/core/dom/TaskRunnerHelper.h
@@ -38,6 +38,13 @@
   Presentation,
   Sensor,
 
+  // Use MiscPlatformAPI for a task that is defined in the spec but is not yet
+  // associated with any specific task runner in the spec. MiscPlatformAPI is
+  // not encouraged for stable and matured APIs. The spec should define the task
+  // runner explicitly.
+  // The task runner may be throttled.
+  MiscPlatformAPI,
+
   // Other internal tasks that cannot fit any of the above task runners
   // can be posted here, but the usage is not encouraged. The task runner
   // may be throttled.
@@ -50,10 +57,6 @@
   // Tasks that must not be throttled should be posted here, but the usage
   // should be very limited.
   Unthrottled,
-
-  // Tasks that any other TaskType is not assigned to. This should be
-  // transitional and should be removed.
-  Unspecified,
 };
 
 // HashTraits for TaskType.
@@ -68,6 +71,9 @@
   }
 };
 
+// A set of helper functions to get a WebTaskRunner for TaskType and a context
+// object. The posted tasks are guaranteed to run in a sequence if they have the
+// same TaskType and the context objects belong to the same frame.
 class CORE_EXPORT TaskRunnerHelper final {
   STATIC_ONLY(TaskRunnerHelper);
 
diff --git a/third_party/WebKit/Source/core/streams/WritableStream.js b/third_party/WebKit/Source/core/streams/WritableStream.js
index e2f88482..5780fa8 100644
--- a/third_party/WebKit/Source/core/streams/WritableStream.js
+++ b/third_party/WebKit/Source/core/streams/WritableStream.js
@@ -615,8 +615,7 @@
     controller[_queue] = v8.InternalPackedArray();
     controller[_queueSize] = 0;
     const sinkAbortPromise =
-        PromiseInvokeOrFallbackOrNoop(controller[_underlyingSink],
-                                      'abort', [reason], 'close', [controller]);
+        PromiseInvokeOrNoop(controller[_underlyingSink], 'abort', [reason]);
     return thenPromise(sinkAbortPromise, () => undefined);
   }
 
@@ -895,25 +894,6 @@
     return Number_isFinite(v) && v >= 0;
   }
 
-  function PromiseInvokeOrFallbackOrNoop(O, P1, args1, P2, args2) {
-    TEMP_ASSERT(IsPropertyKey(P1),
-                'P1 is a valid property key.');
-    TEMP_ASSERT(IsPropertyKey(P2),
-                'P2 is a valid property key.');
-    try {
-      const method = O[P1];
-      if (method === undefined) {
-        return PromiseInvokeOrNoop(O, P2, args2);
-      }
-      if (typeof method !== 'function') {
-        return Promise_reject(new TypeError(templateErrorIsNotAFunction(P1)));
-      }
-      return Promise_resolve(Function_apply(method, O, args1));
-    } catch (e) {
-      return Promise_reject(e);
-    }
-  }
-
   function PromiseInvokeOrNoop(O, P, args) {
     try {
       return Promise_resolve(InvokeOrNoop(O, P, args));
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
index 24101502..09c5127 100644
--- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
+++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -126,8 +126,6 @@
   void disableEval(const String& errorMessage) final;
   String userAgent() const final { return m_userAgent; }
 
-  // This is necessary to make parent's postTask visible.
-  using ExecutionContext::postTask;
   void postTask(TaskType,
                 const WebTraceLocation&,
                 std::unique_ptr<ExecutionContextTask>,
diff --git a/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp b/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp
index 60b3a17..23367b3 100644
--- a/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp
+++ b/third_party/WebKit/Source/modules/quota/DeprecatedStorageInfo.cpp
@@ -32,6 +32,7 @@
 
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/dom/TaskRunnerHelper.h"
 #include "modules/quota/DeprecatedStorageQuota.h"
 #include "modules/quota/StorageErrorCallback.h"
 #include "modules/quota/StorageQuotaCallback.h"
@@ -52,7 +53,7 @@
   DeprecatedStorageQuota* storageQuota = getStorageQuota(storageType);
   if (!storageQuota) {
     // Unknown storage type is requested.
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
     return;
@@ -71,7 +72,7 @@
   DeprecatedStorageQuota* storageQuota = getStorageQuota(storageType);
   if (!storageQuota) {
     // Unknown storage type is requested.
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
     return;
diff --git a/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp b/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
index dd328ca..8406473f 100644
--- a/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
+++ b/third_party/WebKit/Source/modules/quota/DeprecatedStorageQuota.cpp
@@ -32,6 +32,7 @@
 
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/dom/TaskRunnerHelper.h"
 #include "modules/quota/DeprecatedStorageQuotaCallbacksImpl.h"
 #include "modules/quota/StorageErrorCallback.h"
 #include "modules/quota/StorageQuotaClient.h"
@@ -58,7 +59,7 @@
   if (storageType != WebStorageQuotaTypeTemporary &&
       storageType != WebStorageQuotaTypePersistent) {
     // Unknown storage type is requested.
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
     return;
@@ -66,7 +67,7 @@
 
   SecurityOrigin* securityOrigin = executionContext->getSecurityOrigin();
   if (securityOrigin->isUnique()) {
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
     return;
@@ -90,7 +91,7 @@
   if (storageType != WebStorageQuotaTypeTemporary &&
       storageType != WebStorageQuotaTypePersistent) {
     // Unknown storage type is requested.
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
     return;
@@ -98,7 +99,7 @@
 
   StorageQuotaClient* client = StorageQuotaClient::from(executionContext);
   if (!client) {
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
     return;
diff --git a/third_party/WebKit/Source/platform/exported/Platform.cpp b/third_party/WebKit/Source/platform/exported/Platform.cpp
index 422350a..9cc246e9 100644
--- a/third_party/WebKit/Source/platform/exported/Platform.cpp
+++ b/third_party/WebKit/Source/platform/exported/Platform.cpp
@@ -128,7 +128,6 @@
   ProcessHeap::shutdown();
 
   WTF::shutdown();
-  WTF::Partitions::shutdown();
 
   s_platform->m_mainThread = nullptr;
   s_platform = nullptr;
diff --git a/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp b/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
index 9e5356e..0ced62c 100644
--- a/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
+++ b/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
@@ -36,6 +36,7 @@
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/dom/ExecutionContext.h"
+#include "core/dom/TaskRunnerHelper.h"
 #include "modules/quota/DOMError.h"
 #include "modules/quota/DeprecatedStorageQuotaCallbacksImpl.h"
 #include "modules/quota/StorageErrorCallback.h"
@@ -71,7 +72,7 @@
                                             callbacks);
   } else {
     // Requesting quota in Worker is not supported.
-    executionContext->postTask(BLINK_FROM_HERE,
+    executionContext->postTask(TaskType::MiscPlatformAPI, BLINK_FROM_HERE,
                                StorageErrorCallback::createSameThreadTask(
                                    errorCallback, NotSupportedError));
   }
diff --git a/third_party/WebKit/Source/wtf/allocator/Partitions.cpp b/third_party/WebKit/Source/wtf/allocator/Partitions.cpp
index 743b900..04602cf8 100644
--- a/third_party/WebKit/Source/wtf/allocator/Partitions.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/Partitions.cpp
@@ -62,19 +62,6 @@
   }
 }
 
-void Partitions::shutdown() {
-  base::subtle::SpinLock::Guard guard(s_initializationLock);
-
-  // We could ASSERT here for a memory leak within the partition, but it leads
-  // to very hard to diagnose ASSERTs, so it's best to leave leak checking for
-  // the valgrind and heapcheck bots, which run without partitions.
-  if (s_initialized) {
-    (void)m_layoutAllocator.shutdown();
-    (void)m_bufferAllocator.shutdown();
-    (void)m_fastMallocAllocator.shutdown();
-  }
-}
-
 void Partitions::decommitFreeableMemory() {
   RELEASE_ASSERT(isMainThread());
   if (!s_initialized)
diff --git a/third_party/WebKit/Source/wtf/allocator/Partitions.h b/third_party/WebKit/Source/wtf/allocator/Partitions.h
index 3f246be..159e011 100644
--- a/third_party/WebKit/Source/wtf/allocator/Partitions.h
+++ b/third_party/WebKit/Source/wtf/allocator/Partitions.h
@@ -49,7 +49,6 @@
   static const char* const kAllocatedObjectPoolName;
 
   static void initialize(ReportPartitionAllocSizeFunction);
-  static void shutdown();
   ALWAYS_INLINE static base::PartitionRootGeneric* bufferPartition() {
     DCHECK(s_initialized);
     return m_bufferAllocator.root();
diff --git a/tools/battor_agent/battor_agent_unittest.cc b/tools/battor_agent/battor_agent_unittest.cc
index 291c109..cfd5e7a 100644
--- a/tools/battor_agent/battor_agent_unittest.cc
+++ b/tools/battor_agent/battor_agent_unittest.cc
@@ -862,7 +862,7 @@
 
   // Remove the last byte from the frame to make it invalid.
   std::unique_ptr<vector<char>> frame_bytes =
-      CreateFrame(frame_header, frame, 2);
+      CreateFrame(frame_header, frame, 1);
   frame_bytes->pop_back();
 
   OnMessageRead(true, BATTOR_MESSAGE_TYPE_SAMPLES, std::move(frame_bytes));
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 1c2afd9..a3e5ddb 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -9308,6 +9308,15 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="MobileBookmarkManagerEntryOpened">
+  <owner>ianwen@chromium.org</owner>
+  <description>
+    A bookmark was opened from the bookmark manager. Bookmarks opened directly
+    from the NTP will not be counted. Instead those will be counted in the
+    NewTabPage.ContentSuggestions.* histograms.
+  </description>
+</action>
+
 <action name="MobileBookmarkManagerOpen">
   <owner>ianwen@chromium.org</owner>
   <description>
@@ -9823,11 +9832,18 @@
   <description>
     Action indicating the user has opened a bookmark from the bookmark manager.
   </description>
+  <obsolete>
+    Deprecated as of 01/2017. Replaced with MobileBookmarkManagerEntryOpened.
+  </obsolete>
 </action>
 
 <action name="MobileNTPForeignSession">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
+  <obsolete>
+    Deprecated as of 01/2017. Replaced with
+    MobileRecentTabManagerTabFromOtherDeviceOpened.
+  </obsolete>
 </action>
 
 <action name="MobileNTPMostVisited">
@@ -9838,6 +9854,10 @@
 <action name="MobileNTPRecentlyClosed">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
+  <obsolete>
+    Deprecated as of 01/2017. Replaced with
+    MobileRecentTabManagerRecentTabOpened.
+  </obsolete>
 </action>
 
 <action name="MobileNTPShown">
@@ -10077,6 +10097,24 @@
   </description>
 </action>
 
+<action name="MobileRecentTabManagerRecentTabOpened">
+  <owner>finkm@chromium.org</owner>
+  <description>
+    A recently closed tab was opened from the recent tabs manager. Recently
+    closed tabs opened directly from the NTP will not be counted. Instead those
+    will be counted in the NewTabPage.ContentSuggestions.* histograms.
+  </description>
+</action>
+
+<action name="MobileRecentTabManagerTabFromOtherDeviceOpened">
+  <owner>finkm@chromium.org</owner>
+  <description>
+    A tab from another device was opened from the recent tabs manager. Tabs from
+    another device opened directly from the NTP will not be counted. Instead
+    those will be counted in the NewTabPage.ContentSuggestions.* histograms.
+  </description>
+</action>
+
 <action name="MobileRendererCrashed">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8a133ee..94ac7b1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -38689,6 +38689,9 @@
 </histogram>
 
 <histogram name="NewTabPage.ActionAndroid" enum="NewTabPageActionAndroid">
+  <obsolete>
+    Deprecated as of 01/2017. Replaced by NewTabPage.ActionAndroid2.
+  </obsolete>
   <owner>newt@chromium.org</owner>
   <summary>
     Actions taken by users from the new tab page on Android. These actions may
@@ -38698,6 +38701,16 @@
   </summary>
 </histogram>
 
+<histogram name="NewTabPage.ActionAndroid2" enum="NewTabPageActionAndroid2">
+  <owner>finkm@chromium.org</owner>
+  <summary>
+    Actions taken from the new tab page on Android. These actions may navigate
+    away from the NTP (e.g. searching in the omnibox or opening a bookmark), but
+    can also happen without navigating away from the NTP (e.g. opening a content
+    suggestion in a new tab).
+  </summary>
+</histogram>
+
 <histogram name="NewTabPage.AnimatedLogoDownloadTime" units="ms">
   <owner>ianwen@chromium.org</owner>
   <summary>
@@ -97549,6 +97562,9 @@
 </enum>
 
 <enum name="NewTabPageActionAndroid" type="int">
+  <obsolete>
+    Deprecated as of 01/2017. Replaced by NewTabPageActionAndroid2.
+  </obsolete>
   <int value="0" label="Searched using the omnibox"/>
   <int value="1" label="Navigated to Google search homepage using the omnibox"/>
   <int value="2" label="Navigated to any other page using the omnibox"/>
@@ -97563,6 +97579,21 @@
       label="Clicked on the Refresh button in the all dismissed state"/>
 </enum>
 
+<enum name="NewTabPageActionAndroid2" type="int">
+  <int value="0" label="Searched using the omnibox"/>
+  <int value="1" label="Navigated to Google search homepage using the omnibox"/>
+  <int value="2" label="Navigated to any other page using the omnibox"/>
+  <int value="3" label="Opened a most visited tile"/>
+  <int value="4" label="Opened the recent tabs manager"/>
+  <int value="5" label="Opened the history manager"/>
+  <int value="6" label="Opened the bookmarks manager"/>
+  <int value="7" label="Opened the downloads manager"/>
+  <int value="8" label="Navigated to the webpage for a snippet"/>
+  <int value="9" label="Clicked on Learn More"/>
+  <int value="10"
+      label="Clicked on the Refresh button in the all dismissed state"/>
+</enum>
+
 <enum name="NewTabPageBookmarkActionAndroid" type="int">
   <summary>
     These values are defined in PartnerBookmarkAction enum in
diff --git a/ui/gfx/vector_icons/BUILD.gn b/ui/gfx/vector_icons/BUILD.gn
index 9751ed4..d2ce06e 100644
--- a/ui/gfx/vector_icons/BUILD.gn
+++ b/ui/gfx/vector_icons/BUILD.gn
@@ -122,6 +122,20 @@
     "warning.icon",
     "warning_badge.icon",
     "web.icon",
+    "window_control_back.1x.icon",
+    "window_control_back.icon",
+    "window_control_close.1x.icon",
+    "window_control_close.icon",
+    "window_control_left_snapped.1x.icon",
+    "window_control_left_snapped.icon",
+    "window_control_maximize.1x.icon",
+    "window_control_maximize.icon",
+    "window_control_minimize.1x.icon",
+    "window_control_minimize.icon",
+    "window_control_restore.1x.icon",
+    "window_control_restore.icon",
+    "window_control_right_snapped.1x.icon",
+    "window_control_right_snapped.icon",
     "zoom_minus.icon",
     "zoom_plus.icon",
     "${branding_path_component}/product.icon",
diff --git a/ash/resources/vector_icons/window_control_back.1x.icon b/ui/gfx/vector_icons/window_control_back.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_back.1x.icon
rename to ui/gfx/vector_icons/window_control_back.1x.icon
diff --git a/ash/resources/vector_icons/window_control_back.icon b/ui/gfx/vector_icons/window_control_back.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_back.icon
rename to ui/gfx/vector_icons/window_control_back.icon
diff --git a/ash/resources/vector_icons/window_control_close.1x.icon b/ui/gfx/vector_icons/window_control_close.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_close.1x.icon
rename to ui/gfx/vector_icons/window_control_close.1x.icon
diff --git a/ash/resources/vector_icons/window_control_close.icon b/ui/gfx/vector_icons/window_control_close.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_close.icon
rename to ui/gfx/vector_icons/window_control_close.icon
diff --git a/ash/resources/vector_icons/window_control_left_snapped.1x.icon b/ui/gfx/vector_icons/window_control_left_snapped.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_left_snapped.1x.icon
rename to ui/gfx/vector_icons/window_control_left_snapped.1x.icon
diff --git a/ash/resources/vector_icons/window_control_left_snapped.icon b/ui/gfx/vector_icons/window_control_left_snapped.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_left_snapped.icon
rename to ui/gfx/vector_icons/window_control_left_snapped.icon
diff --git a/ash/resources/vector_icons/window_control_maximize.1x.icon b/ui/gfx/vector_icons/window_control_maximize.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_maximize.1x.icon
rename to ui/gfx/vector_icons/window_control_maximize.1x.icon
diff --git a/ash/resources/vector_icons/window_control_maximize.icon b/ui/gfx/vector_icons/window_control_maximize.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_maximize.icon
rename to ui/gfx/vector_icons/window_control_maximize.icon
diff --git a/ash/resources/vector_icons/window_control_minimize.1x.icon b/ui/gfx/vector_icons/window_control_minimize.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_minimize.1x.icon
rename to ui/gfx/vector_icons/window_control_minimize.1x.icon
diff --git a/ash/resources/vector_icons/window_control_minimize.icon b/ui/gfx/vector_icons/window_control_minimize.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_minimize.icon
rename to ui/gfx/vector_icons/window_control_minimize.icon
diff --git a/ash/resources/vector_icons/window_control_restore.1x.icon b/ui/gfx/vector_icons/window_control_restore.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_restore.1x.icon
rename to ui/gfx/vector_icons/window_control_restore.1x.icon
diff --git a/ash/resources/vector_icons/window_control_restore.icon b/ui/gfx/vector_icons/window_control_restore.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_restore.icon
rename to ui/gfx/vector_icons/window_control_restore.icon
diff --git a/ash/resources/vector_icons/window_control_right_snapped.1x.icon b/ui/gfx/vector_icons/window_control_right_snapped.1x.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_right_snapped.1x.icon
rename to ui/gfx/vector_icons/window_control_right_snapped.1x.icon
diff --git a/ash/resources/vector_icons/window_control_right_snapped.icon b/ui/gfx/vector_icons/window_control_right_snapped.icon
similarity index 100%
rename from ash/resources/vector_icons/window_control_right_snapped.icon
rename to ui/gfx/vector_icons/window_control_right_snapped.icon
diff --git a/ui/message_center/views/message_center_button_bar.cc b/ui/message_center/views/message_center_button_bar.cc
index 5f89a6a..fb86d93 100644
--- a/ui/message_center/views/message_center_button_bar.cc
+++ b/ui/message_center/views/message_center_button_bar.cc
@@ -68,9 +68,9 @@
     int text_id)
     : views::ToggleImageButton(listener), size_(kButtonSize, kButtonSize) {
   ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
-  SetImage(STATE_NORMAL, *resource_bundle.GetImageSkiaNamed(normal_id));
-  SetImage(STATE_HOVERED, *resource_bundle.GetImageSkiaNamed(hover_id));
-  SetImage(STATE_PRESSED, *resource_bundle.GetImageSkiaNamed(pressed_id));
+  SetImage(STATE_NORMAL, resource_bundle.GetImageSkiaNamed(normal_id));
+  SetImage(STATE_HOVERED, resource_bundle.GetImageSkiaNamed(hover_id));
+  SetImage(STATE_PRESSED, resource_bundle.GetImageSkiaNamed(pressed_id));
   SetImageAlignment(views::ImageButton::ALIGN_CENTER,
                     views::ImageButton::ALIGN_MIDDLE);
   if (text_id)
@@ -159,7 +159,7 @@
                                    IDS_MESSAGE_CENTER_CLEAR_ALL);
   close_all_button_->SetImage(
       views::Button::STATE_DISABLED,
-      *resource_bundle.GetImageSkiaNamed(IDR_NOTIFICATION_CLEAR_ALL_DISABLED));
+      resource_bundle.GetImageSkiaNamed(IDR_NOTIFICATION_CLEAR_ALL_DISABLED));
   button_container_->AddChildView(close_all_button_);
 
   settings_button_ =
diff --git a/ui/snapshot/snapshot_aura_unittest.cc b/ui/snapshot/snapshot_aura_unittest.cc
index 7be0d70..984a231b 100644
--- a/ui/snapshot/snapshot_aura_unittest.cc
+++ b/ui/snapshot/snapshot_aura_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/test/test_simple_task_runner.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkPixelRef.h"
 #include "ui/aura/test/aura_test_helper.h"
 #include "ui/aura/test/test_screen.h"
 #include "ui/aura/test/test_window_delegate.h"
diff --git a/ui/views/controls/button/image_button.cc b/ui/views/controls/button/image_button.cc
index fd2151e2a..e875612c 100644
--- a/ui/views/controls/button/image_button.cc
+++ b/ui/views/controls/button/image_button.cc
@@ -48,14 +48,10 @@
 }
 
 void ImageButton::SetImage(ButtonState for_state, const gfx::ImageSkia* image) {
-  SetImage(for_state, image ? *image : gfx::ImageSkia());
-}
-
-void ImageButton::SetImage(ButtonState for_state, const gfx::ImageSkia& image) {
   if (for_state == STATE_HOVERED)
-    set_animate_on_state_change(!image.isNull());
+    set_animate_on_state_change(image != nullptr);
   const gfx::Size old_preferred_size = GetPreferredSize();
-  images_[for_state] = image;
+  images_[for_state] = image ? *image : gfx::ImageSkia();
 
   if (old_preferred_size != GetPreferredSize())
     PreferredSizeChanged();
@@ -254,11 +250,11 @@
 }
 
 void ToggleImageButton::SetImage(ButtonState image_state,
-                                 const gfx::ImageSkia& image) {
+                                 const gfx::ImageSkia* image) {
   if (toggled_) {
-    alternate_images_[image_state] = image;
+    alternate_images_[image_state] = image ? *image : gfx::ImageSkia();
   } else {
-    images_[image_state] = image;
+    images_[image_state] = image ? *image : gfx::ImageSkia();
     if (state() == image_state)
       SchedulePaint();
   }
diff --git a/ui/views/controls/button/image_button.h b/ui/views/controls/button/image_button.h
index eba2a835..94f70ba8 100644
--- a/ui/views/controls/button/image_button.h
+++ b/ui/views/controls/button/image_button.h
@@ -44,12 +44,7 @@
   virtual const gfx::ImageSkia& GetImage(ButtonState state) const;
 
   // Set the image the button should use for the provided state.
-  void SetImage(ButtonState state, const gfx::ImageSkia* image);
-
-  // As above, but takes a const ref. TODO(estade): all callers should be
-  // updated to use this version, and then the implementations can be
-  // consolidated.
-  virtual void SetImage(ButtonState state, const gfx::ImageSkia& image);
+  virtual void SetImage(ButtonState state, const gfx::ImageSkia* image);
 
   // Set the background details.
   void SetBackground(SkColor color,
@@ -147,7 +142,7 @@
 
   // Overridden from ImageButton:
   const gfx::ImageSkia& GetImage(ButtonState state) const override;
-  void SetImage(ButtonState state, const gfx::ImageSkia& image) override;
+  void SetImage(ButtonState state, const gfx::ImageSkia* image) override;
 
   // Overridden from View:
   bool GetTooltipText(const gfx::Point& p,