diff --git a/DEPS b/DEPS
index 8da860e..9f81754 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': 'b2cd1d7b442b689ff74409029defbf505c044b2c',
+  'skia_revision': '98829b979119297bd9dbbe9313ba98ea0b3289af',
   # 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': 'b6bf2cf7592692af6f230e9fe6d4438bb26b6d55',
+  'v8_revision': '1e96ba3f4ede6cceee6146f78d558c4b34f6b2ee',
   # 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': '03de88464cc818ac4353de3e7ec49b98166bcdc5',
+  'pdfium_revision': '5c1673db6deae2e1858c4ffc3b3a0b79901dd827',
   # 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.
@@ -354,7 +354,7 @@
   },
   'ios': {
     'src/ios/third_party/earl_grey/src':
-      Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + '625b2b7cdaf9371ae2b001d6cdc23b1790d41cd8',
+      Var('chromium_git') + '/external/github.com/google/EarlGrey.git' + '@' + 'c5c89d810a8e76547ed0506e85c1a80f3a10bc48',
 
     'src/ios/third_party/fishhook/src':
       Var('chromium_git') + '/external/github.com/facebook/fishhook.git' + '@' + 'd172d5247aa590c25d0b1885448bae76036ea22c',
diff --git a/ash/common/BUILD.gn b/ash/common/BUILD.gn
index 94b8211..e5c535f1 100644
--- a/ash/common/BUILD.gn
+++ b/ash/common/BUILD.gn
@@ -8,6 +8,7 @@
   testonly = true
   sources = [
     "accelerators/accelerator_table_unittest.cc",
+    "drag_drop/drag_image_view_unittest.cc",
     "system/chromeos/audio/tray_audio_unittest.cc",
     "system/chromeos/brightness/tray_brightness_unittest.cc",
     "system/chromeos/network/vpn_list_unittest.cc",
diff --git a/ash/common/drag_drop/drag_image_view.cc b/ash/common/drag_drop/drag_image_view.cc
index 5c763c3..2f9a9ff 100644
--- a/ash/common/drag_drop/drag_image_view.cc
+++ b/ash/common/drag_drop/drag_image_view.cc
@@ -58,12 +58,13 @@
 }
 
 void DragImageView::SetBoundsInScreen(const gfx::Rect& bounds) {
+  drag_image_size_ = bounds.size();
   widget_->SetBounds(bounds);
-  widget_size_ = bounds.size();
 }
 
 void DragImageView::SetScreenPosition(const gfx::Point& position) {
-  widget_->SetBounds(gfx::Rect(position, widget_size_));
+  widget_->SetBounds(
+      gfx::Rect(position, widget_->GetWindowBoundsInScreen().size()));
 }
 
 gfx::Rect DragImageView::GetBoundsInScreen() const {
@@ -82,6 +83,12 @@
 void DragImageView::SetTouchDragOperationHintOff() {
   // Simply set the drag type to non-touch so that no hint is drawn.
   drag_event_source_ = ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE;
+
+  // This disables the drag hint image. This should reduce the widget size if
+  // the drag image is smaller than the drag hint image, so we set new bounds.
+  gfx::Rect new_bounds = GetBoundsInScreen();
+  new_bounds.set_size(drag_image_size_);
+  SetBoundsInScreen(new_bounds);
   SchedulePaint();
 }
 
@@ -110,32 +117,30 @@
   if (GetImage().isNull())
     return;
 
-  // |widget_size_| is in DIP. ImageSkia::size() also returns the size in DIP.
-  if (GetImage().size() == widget_size_) {
+  // |drag_image_size_| is in DIP.
+  // ImageSkia::size() also returns the size in DIP.
+  if (GetImage().size() == drag_image_size_) {
     canvas->DrawImageInt(GetImage(), 0, 0);
   } else {
     WmWindow* window = WmLookup::Get()->GetWindowForWidget(widget_.get());
     const float device_scale =
         window->GetDisplayNearestWindow().device_scale_factor();
     // The drag image already has device scale factor applied. But
-    // |widget_size_| is in DIP units.
-    gfx::Size scaled_widget_size =
-        gfx::ScaleToRoundedSize(widget_size_, device_scale);
+    // |drag_image_size_| is in DIP units.
+    gfx::Size drag_image_size_pixels =
+        gfx::ScaleToRoundedSize(drag_image_size_, device_scale);
     gfx::ImageSkiaRep image_rep = GetImage().GetRepresentation(device_scale);
     if (image_rep.is_null())
       return;
     SkBitmap scaled = skia::ImageOperations::Resize(
         image_rep.sk_bitmap(), skia::ImageOperations::RESIZE_LANCZOS3,
-        scaled_widget_size.width(), scaled_widget_size.height());
+        drag_image_size_pixels.width(), drag_image_size_pixels.height());
     gfx::ImageSkia image_skia(gfx::ImageSkiaRep(scaled, device_scale));
     canvas->DrawImageInt(image_skia, 0, 0);
   }
 
-  if (drag_event_source_ != ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH)
-    return;
-
   gfx::Image* drag_hint = DragHint();
-  if (drag_hint->IsEmpty())
+  if (!ShouldDrawDragHint() || drag_hint->IsEmpty())
     return;
 
   // Make sure drag hint image is positioned within the widget.
@@ -143,7 +148,9 @@
   gfx::Point drag_hint_position = touch_drag_operation_indicator_position_;
   drag_hint_position.Offset(-drag_hint_size.width() / 2, 0);
   gfx::Rect drag_hint_bounds(drag_hint_position, drag_hint_size);
-  drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size_));
+
+  gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size();
+  drag_hint_bounds.AdjustToFit(gfx::Rect(widget_size));
 
   // Draw image.
   canvas->DrawImageInt(*(drag_hint->ToImageSkia()), drag_hint_bounds.x(),
@@ -168,21 +175,34 @@
   return drag_hint;
 }
 
+bool DragImageView::ShouldDrawDragHint() const {
+  return drag_event_source_ == ui::DragDropTypes::DRAG_EVENT_SOURCE_TOUCH;
+}
+
+gfx::Size DragImageView::GetMinimumSize() const {
+  gfx::Size minimum_size = drag_image_size_;
+  if (ShouldDrawDragHint())
+    minimum_size.SetToMax(DragHint()->Size());
+  return minimum_size;
+}
+
 void DragImageView::Layout() {
   View::Layout();
 
+  // Only consider resizing the widget for the drag hint image if we are in a
+  // touch initiated drag.
   gfx::Image* drag_hint = DragHint();
-  if (drag_hint->IsEmpty())
+  if (!ShouldDrawDragHint() || drag_hint->IsEmpty())
     return;
 
   gfx::Size drag_hint_size = drag_hint->Size();
 
   // Enlarge widget if required to fit the drag hint image.
-  if (drag_hint_size.width() > widget_size_.width() ||
-      drag_hint_size.height() > widget_size_.height()) {
-    gfx::Size new_widget_size = widget_size_;
-    new_widget_size.SetToMax(drag_hint_size);
-    widget_->SetSize(new_widget_size);
+  gfx::Size widget_size = widget_->GetWindowBoundsInScreen().size();
+  if (drag_hint_size.width() > widget_size.width() ||
+      drag_hint_size.height() > widget_size.height()) {
+    widget_size.SetToMax(drag_hint_size);
+    widget_->SetSize(widget_size);
   }
 }
 
diff --git a/ash/common/drag_drop/drag_image_view.h b/ash/common/drag_drop/drag_image_view.h
index 63b972e..de6e4d5 100644
--- a/ash/common/drag_drop/drag_image_view.h
+++ b/ash/common/drag_drop/drag_image_view.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "ash/ash_export.h"
 #include "base/macros.h"
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/gfx/geometry/point.h"
@@ -29,7 +30,7 @@
 // does this by creating a widget and setting the content as the given view. The
 // caller can then use this object to freely move / drag it around on the
 // desktop in screen coordinates.
-class DragImageView : public views::ImageView {
+class ASH_EXPORT DragImageView : public views::ImageView {
  public:
   // |root_window| is the root window on which to create the drag image widget.
   // |source| is the event source that started this drag drop operation (touch
@@ -67,8 +68,12 @@
   // Sets the |opacity| of the image view between 0.0 and 1.0.
   void SetOpacity(float opacity);
 
+  gfx::Size GetMinimumSize() const override;
+
  private:
   gfx::Image* DragHint() const;
+  // Drag hint images are only drawn when the input source is touch.
+  bool ShouldDrawDragHint() const;
 
   // Overridden from views::ImageView.
   void OnPaint(gfx::Canvas* canvas) override;
@@ -77,7 +82,12 @@
   void Layout() override;
 
   std::unique_ptr<views::Widget> widget_;
-  gfx::Size widget_size_;
+
+  // Save the requested drag image size. We may need to display a drag hint
+  // image, which potentially expands |widget_|'s size. That drag hint image
+  // may be disabled (e.g. during the drag cancel animation). In that case,
+  // we need to know the originally requested size to render the drag image.
+  gfx::Size drag_image_size_;
 
   ui::DragDropTypes::DragEventSource drag_event_source_;
 
diff --git a/ash/common/drag_drop/drag_image_view_unittest.cc b/ash/common/drag_drop/drag_image_view_unittest.cc
new file mode 100644
index 0000000..e74d1bc
--- /dev/null
+++ b/ash/common/drag_drop/drag_image_view_unittest.cc
@@ -0,0 +1,77 @@
+// 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 "ash/common/drag_drop/drag_image_view.h"
+
+#include "ash/common/test/ash_test.h"
+#include "ui/base/dragdrop/drag_drop_types.h"
+
+namespace ash {
+namespace test {
+
+using DragDropImageTest = AshTest;
+
+TEST_F(DragDropImageTest, SetBoundsConsidersDragHintForTouch) {
+  std::unique_ptr<WindowOwner> window_owner(CreateTestWindow());
+  DragImageView drag_image_view(
+      window_owner->window(),
+      ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_TOUCH);
+
+  gfx::Size minimum_size = drag_image_view.GetMinimumSize();
+  gfx::Point new_pos(5, 5);
+
+  if (!minimum_size.IsEmpty()) {
+    // Expect that the view is at least the size of the drag hint image.
+    gfx::Rect small_bounds(0, 0, 1, 1);
+    drag_image_view.SetBoundsInScreen(small_bounds);
+    EXPECT_EQ(gfx::Rect(minimum_size), drag_image_view.GetBoundsInScreen());
+
+    // Expect that we can change the position without affecting the bounds.
+    drag_image_view.SetScreenPosition(new_pos);
+    EXPECT_EQ(gfx::Rect(new_pos, minimum_size),
+              drag_image_view.GetBoundsInScreen());
+  }
+
+  // Expect that we can resize the view normally.
+  gfx::Rect large_bounds(0, 0, minimum_size.width() + 1,
+                         minimum_size.height() + 1);
+  drag_image_view.SetBoundsInScreen(large_bounds);
+  EXPECT_EQ(large_bounds, drag_image_view.GetBoundsInScreen());
+  // Expect that we can change the position without affecting the bounds.
+  drag_image_view.SetScreenPosition(new_pos);
+  EXPECT_EQ(gfx::Rect(new_pos, large_bounds.size()),
+            drag_image_view.GetBoundsInScreen());
+}
+
+TEST_F(DragDropImageTest, SetBoundsIgnoresDragHintForMouse) {
+  std::unique_ptr<WindowOwner> window_owner(CreateTestWindow());
+  DragImageView drag_image_view(
+      window_owner->window(),
+      ui::DragDropTypes::DragEventSource::DRAG_EVENT_SOURCE_MOUSE);
+
+  // Expect no drag hint image.
+  gfx::Rect small_bounds(0, 0, 1, 1);
+  drag_image_view.SetBoundsInScreen(small_bounds);
+  EXPECT_EQ(small_bounds, drag_image_view.GetBoundsInScreen());
+  EXPECT_EQ(drag_image_view.GetMinimumSize(),
+            drag_image_view.GetBoundsInScreen().size());
+
+  gfx::Point new_pos(5, 5);
+  // Expect that we can change the position without affecting the bounds.
+  drag_image_view.SetScreenPosition(new_pos);
+  EXPECT_EQ(gfx::Rect(new_pos, small_bounds.size()),
+            drag_image_view.GetBoundsInScreen());
+
+  // Expect that we can resize the view.
+  gfx::Rect large_bounds(0, 0, 100, 100);
+  drag_image_view.SetBoundsInScreen(large_bounds);
+  EXPECT_EQ(large_bounds, drag_image_view.GetBoundsInScreen());
+  // Expect that we can change the position without affecting the bounds.
+  drag_image_view.SetScreenPosition(new_pos);
+  EXPECT_EQ(gfx::Rect(new_pos, large_bounds.size()),
+            drag_image_view.GetBoundsInScreen());
+}
+
+}  // namespace test
+}  // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn
index fa5e369d..7f46e71 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -149,6 +149,8 @@
     "allocator/allocator_check.h",
     "allocator/allocator_extension.cc",
     "allocator/allocator_extension.h",
+    "allocator/allocator_interception_mac.h",
+    "allocator/allocator_interception_mac.mm",
     "allocator/allocator_shim.h",
     "allocator/oom.h",
     "android/animation_frame_time_histogram.cc",
diff --git a/base/allocator/allocator_interception_mac.h b/base/allocator/allocator_interception_mac.h
new file mode 100644
index 0000000..87cbf489
--- /dev/null
+++ b/base/allocator/allocator_interception_mac.h
@@ -0,0 +1,55 @@
+// 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 BASE_ALLOCATOR_ALLOCATOR_INTERCEPTION_MAC_H_
+#define BASE_ALLOCATOR_ALLOCATOR_INTERCEPTION_MAC_H_
+
+#include <malloc/malloc.h>
+#include <stddef.h>
+
+#include "third_party/apple_apsl/malloc.h"
+
+namespace base {
+namespace allocator {
+
+typedef void* (*malloc_type)(struct _malloc_zone_t* zone, size_t size);
+typedef void* (*calloc_type)(struct _malloc_zone_t* zone,
+                             size_t num_items,
+                             size_t size);
+typedef void* (*valloc_type)(struct _malloc_zone_t* zone, size_t size);
+typedef void (*free_type)(struct _malloc_zone_t* zone, void* ptr);
+typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
+                              void* ptr,
+                              size_t size);
+typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
+                               size_t alignment,
+                               size_t size);
+
+struct MallocZoneFunctions {
+  malloc_type malloc = nullptr;
+  calloc_type calloc = nullptr;
+  valloc_type valloc = nullptr;
+  free_type free = nullptr;
+  realloc_type realloc = nullptr;
+  memalign_type memalign = nullptr;
+};
+
+// Saves the function pointers currently used by |zone| into |functions|.
+void StoreZoneFunctions(ChromeMallocZone* zone, MallocZoneFunctions* functions);
+
+// Updates the malloc zone to use the functions specified by |functions|.
+void ReplaceZoneFunctions(ChromeMallocZone* zone,
+                          const MallocZoneFunctions* functions);
+
+// Calls the original implementation of malloc/calloc prior to interception.
+bool UncheckedMallocMac(size_t size, void** result);
+bool UncheckedCallocMac(size_t num_items, size_t size, void** result);
+
+// Intercepts calls to default and purgeable malloc zones. Intercepts Core
+// Foundation and Objective-C allocations.
+void InterceptAllocationsMac();
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_INTERCEPTION_MAC_H_
diff --git a/base/allocator/allocator_interception_mac.mm b/base/allocator/allocator_interception_mac.mm
new file mode 100644
index 0000000..941c5b4a
--- /dev/null
+++ b/base/allocator/allocator_interception_mac.mm
@@ -0,0 +1,471 @@
+// 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.
+
+// This file contains all the logic necessary to intercept allocations on
+// macOS. "malloc zones" are an abstraction that allows the process to intercept
+// all malloc-related functions.  There is no good mechanism [short of
+// interposition] to determine new malloc zones are added, so there's no clean
+// mechanism to intercept all malloc zones. This file contains logic to
+// intercept the default and purgeable zones, which always exist. A cursory
+// review of Chrome seems to imply that non-default zones are almost never used.
+//
+// This file also contains logic to intercept Core Foundation and Objective-C
+// allocations. The implementations forward to the default malloc zone, so the
+// only reason to intercept these calls is to re-label OOM crashes with slightly
+// more details.
+
+#include "base/allocator/allocator_interception_mac.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#import <Foundation/Foundation.h>
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#import <objc/runtime.h>
+#include <stddef.h>
+
+#include <new>
+
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/process/memory.h"
+#include "base/scoped_clear_errno.h"
+#include "build/build_config.h"
+#include "third_party/apple_apsl/CFBase.h"
+
+namespace base {
+namespace allocator {
+
+namespace {
+
+bool g_oom_killer_enabled;
+
+#if !defined(ADDRESS_SANITIZER)
+
+// Starting with Mac OS X 10.7, the zone allocators set up by the system are
+// read-only, to prevent them from being overwritten in an attack. However,
+// blindly unprotecting and reprotecting the zone allocators fails with
+// GuardMalloc because GuardMalloc sets up its zone allocator using a block of
+// memory in its bss. Explicit saving/restoring of the protection is required.
+//
+// This function takes a pointer to a malloc zone, de-protects it if necessary,
+// and returns (in the out parameters) a region of memory (if any) to be
+// re-protected when modifications are complete. This approach assumes that
+// there is no contention for the protection of this memory.
+void DeprotectMallocZone(ChromeMallocZone* default_zone,
+                         mach_vm_address_t* reprotection_start,
+                         mach_vm_size_t* reprotection_length,
+                         vm_prot_t* reprotection_value) {
+  mach_port_t unused;
+  *reprotection_start = reinterpret_cast<mach_vm_address_t>(default_zone);
+  struct vm_region_basic_info_64 info;
+  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+  kern_return_t result = mach_vm_region(
+      mach_task_self(), reprotection_start, reprotection_length,
+      VM_REGION_BASIC_INFO_64, reinterpret_cast<vm_region_info_t>(&info),
+      &count, &unused);
+  MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_region";
+
+  // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
+  // balance it with a deallocate in case this ever changes. See 10.9.2
+  // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
+  mach_port_deallocate(mach_task_self(), unused);
+
+  // Does the region fully enclose the zone pointers? Possibly unwarranted
+  // simplification used: using the size of a full version 8 malloc zone rather
+  // than the actual smaller size if the passed-in zone is not version 8.
+  CHECK(*reprotection_start <=
+        reinterpret_cast<mach_vm_address_t>(default_zone));
+  mach_vm_size_t zone_offset =
+      reinterpret_cast<mach_vm_size_t>(default_zone) -
+      reinterpret_cast<mach_vm_size_t>(*reprotection_start);
+  CHECK(zone_offset + sizeof(ChromeMallocZone) <= *reprotection_length);
+
+  if (info.protection & VM_PROT_WRITE) {
+    // No change needed; the zone is already writable.
+    *reprotection_start = 0;
+    *reprotection_length = 0;
+    *reprotection_value = VM_PROT_NONE;
+  } else {
+    *reprotection_value = info.protection;
+    result = mach_vm_protect(mach_task_self(), *reprotection_start,
+                             *reprotection_length, false,
+                             info.protection | VM_PROT_WRITE);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+}
+
+MallocZoneFunctions g_old_zone;
+MallocZoneFunctions g_old_purgeable_zone;
+
+void* oom_killer_malloc(struct _malloc_zone_t* zone, size_t size) {
+  void* result = g_old_zone.malloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_calloc(struct _malloc_zone_t* zone,
+                        size_t num_items,
+                        size_t size) {
+  void* result = g_old_zone.calloc(zone, num_items, size);
+  if (!result && num_items && size)
+    TerminateBecauseOutOfMemory(num_items * size);
+  return result;
+}
+
+void* oom_killer_valloc(struct _malloc_zone_t* zone, size_t size) {
+  void* result = g_old_zone.valloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void oom_killer_free(struct _malloc_zone_t* zone, void* ptr) {
+  g_old_zone.free(zone, ptr);
+}
+
+void* oom_killer_realloc(struct _malloc_zone_t* zone, void* ptr, size_t size) {
+  void* result = g_old_zone.realloc(zone, ptr, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_memalign(struct _malloc_zone_t* zone,
+                          size_t alignment,
+                          size_t size) {
+  void* result = g_old_zone.memalign(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*) &&
+      (alignment & (alignment - 1)) == 0) {
+    TerminateBecauseOutOfMemory(size);
+  }
+  return result;
+}
+
+void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone, size_t size) {
+  void* result = g_old_purgeable_zone.malloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t num_items,
+                                  size_t size) {
+  void* result = g_old_purgeable_zone.calloc(zone, num_items, size);
+  if (!result && num_items && size)
+    TerminateBecauseOutOfMemory(num_items * size);
+  return result;
+}
+
+void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone, size_t size) {
+  void* result = g_old_purgeable_zone.valloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void oom_killer_free_purgeable(struct _malloc_zone_t* zone, void* ptr) {
+  g_old_purgeable_zone.free(zone, ptr);
+}
+
+void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
+                                   void* ptr,
+                                   size_t size) {
+  void* result = g_old_purgeable_zone.realloc(zone, ptr, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
+                                    size_t alignment,
+                                    size_t size) {
+  void* result = g_old_purgeable_zone.memalign(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*) &&
+      (alignment & (alignment - 1)) == 0) {
+    TerminateBecauseOutOfMemory(size);
+  }
+  return result;
+}
+
+#endif  // !defined(ADDRESS_SANITIZER)
+
+// === C++ operator new ===
+
+void oom_killer_new() {
+  TerminateBecauseOutOfMemory(0);
+}
+
+#if !defined(ADDRESS_SANITIZER)
+
+// === Core Foundation CFAllocators ===
+
+bool CanGetContextForCFAllocator() {
+  return !base::mac::IsOSLaterThan10_12_DontCallThis();
+}
+
+CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
+  ChromeCFAllocatorLions* our_allocator = const_cast<ChromeCFAllocatorLions*>(
+      reinterpret_cast<const ChromeCFAllocatorLions*>(allocator));
+  return &our_allocator->_context;
+}
+
+CFAllocatorAllocateCallBack g_old_cfallocator_system_default;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone;
+
+void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
+                                            CFOptionFlags hint,
+                                            void* info) {
+  void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
+                                    CFOptionFlags hint,
+                                    void* info) {
+  void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
+                                         CFOptionFlags hint,
+                                         void* info) {
+  void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+#endif  // !defined(ADDRESS_SANITIZER)
+
+// === Cocoa NSObject allocation ===
+
+typedef id (*allocWithZone_t)(id, SEL, NSZone*);
+allocWithZone_t g_old_allocWithZone;
+
+id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone) {
+  id result = g_old_allocWithZone(self, _cmd, zone);
+  if (!result)
+    TerminateBecauseOutOfMemory(0);
+  return result;
+}
+
+}  // namespace
+
+bool UncheckedMallocMac(size_t size, void** result) {
+#if defined(ADDRESS_SANITIZER)
+  *result = malloc(size);
+#else
+  if (g_old_zone.malloc) {
+    *result = g_old_zone.malloc(malloc_default_zone(), size);
+  } else {
+    *result = malloc(size);
+  }
+#endif  // defined(ADDRESS_SANITIZER)
+
+  return *result != NULL;
+}
+
+bool UncheckedCallocMac(size_t num_items, size_t size, void** result) {
+#if defined(ADDRESS_SANITIZER)
+  *result = calloc(num_items, size);
+#else
+  if (g_old_zone.calloc) {
+    *result = g_old_zone.calloc(malloc_default_zone(), num_items, size);
+  } else {
+    *result = calloc(num_items, size);
+  }
+#endif  // defined(ADDRESS_SANITIZER)
+
+  return *result != NULL;
+}
+
+void StoreZoneFunctions(ChromeMallocZone* zone,
+                        MallocZoneFunctions* functions) {
+  functions->malloc = zone->malloc;
+  functions->calloc = zone->calloc;
+  functions->valloc = zone->valloc;
+  functions->free = zone->free;
+  functions->realloc = zone->realloc;
+  CHECK(functions->malloc && functions->calloc && functions->valloc &&
+        functions->free && functions->realloc);
+
+  if (zone->version >= 5) {
+    functions->memalign = zone->memalign;
+    CHECK(functions->memalign);
+  }
+}
+
+void ReplaceZoneFunctions(ChromeMallocZone* zone,
+                          const MallocZoneFunctions* functions) {
+  // Remove protection.
+  mach_vm_address_t reprotection_start = 0;
+  mach_vm_size_t reprotection_length = 0;
+  vm_prot_t reprotection_value = VM_PROT_NONE;
+  DeprotectMallocZone(zone, &reprotection_start, &reprotection_length,
+                      &reprotection_value);
+
+  zone->malloc = functions->malloc;
+  zone->calloc = functions->calloc;
+  zone->valloc = functions->valloc;
+  zone->free = functions->free;
+  zone->realloc = functions->realloc;
+  if (zone->version >= 5) {
+    zone->memalign = functions->memalign;
+  }
+
+  // Restore protection if it was active.
+  if (reprotection_start) {
+    kern_return_t result =
+        mach_vm_protect(mach_task_self(), reprotection_start,
+                        reprotection_length, false, reprotection_value);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+}
+
+void InterceptAllocationsMac() {
+  if (g_oom_killer_enabled)
+    return;
+
+  g_oom_killer_enabled = true;
+
+// === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+// This approach is not perfect, as requests for amounts of memory larger than
+// MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will
+// still fail with a NULL rather than dying (see
+// http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details).
+// Unfortunately, it's the best we can do. Also note that this does not affect
+// allocations from non-default zones.
+
+#if !defined(ADDRESS_SANITIZER)
+  // Don't do anything special on OOM for the malloc zones replaced by
+  // AddressSanitizer, as modifying or protecting them may not work correctly.
+  ChromeMallocZone* default_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
+  StoreZoneFunctions(default_zone, &g_old_zone);
+  MallocZoneFunctions new_functions;
+  new_functions.malloc = oom_killer_malloc;
+  new_functions.calloc = oom_killer_calloc;
+  new_functions.valloc = oom_killer_valloc;
+  new_functions.free = oom_killer_free;
+  new_functions.realloc = oom_killer_realloc;
+  new_functions.memalign = oom_killer_memalign;
+  ReplaceZoneFunctions(default_zone, &new_functions);
+
+  ChromeMallocZone* purgeable_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone());
+  if (purgeable_zone) {
+    StoreZoneFunctions(purgeable_zone, &g_old_purgeable_zone);
+    MallocZoneFunctions new_functions;
+    new_functions.malloc = oom_killer_malloc_purgeable;
+    new_functions.calloc = oom_killer_calloc_purgeable;
+    new_functions.valloc = oom_killer_valloc_purgeable;
+    new_functions.free = oom_killer_free_purgeable;
+    new_functions.realloc = oom_killer_realloc_purgeable;
+    new_functions.memalign = oom_killer_memalign_purgeable;
+    ReplaceZoneFunctions(purgeable_zone, &new_functions);
+  }
+#endif
+
+  // === C malloc_zone_batch_malloc ===
+
+  // batch_malloc is omitted because the default malloc zone's implementation
+  // only supports batch_malloc for "tiny" allocations from the free list. It
+  // will fail for allocations larger than "tiny", and will only allocate as
+  // many blocks as it's able to from the free list. These factors mean that it
+  // can return less than the requested memory even in a non-out-of-memory
+  // situation. There's no good way to detect whether a batch_malloc failure is
+  // due to these other factors, or due to genuine memory or address space
+  // exhaustion. The fact that it only allocates space from the "tiny" free list
+  // means that it's likely that a failure will not be due to memory exhaustion.
+  // Similarly, these constraints on batch_malloc mean that callers must always
+  // be expecting to receive less memory than was requested, even in situations
+  // where memory pressure is not a concern. Finally, the only public interface
+  // to batch_malloc is malloc_zone_batch_malloc, which is specific to the
+  // system's malloc implementation. It's unlikely that anyone's even heard of
+  // it.
+
+  // === C++ operator new ===
+
+  // Yes, operator new does call through to malloc, but this will catch failures
+  // that our imperfect handling of malloc cannot.
+
+  std::set_new_handler(oom_killer_new);
+
+#ifndef ADDRESS_SANITIZER
+  // === Core Foundation CFAllocators ===
+
+  // This will not catch allocation done by custom allocators, but will catch
+  // all allocation done by system-provided ones.
+
+  CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc &&
+        !g_old_cfallocator_malloc_zone)
+      << "Old allocators unexpectedly non-null";
+
+  bool cf_allocator_internals_known = CanGetContextForCFAllocator();
+
+  if (cf_allocator_internals_known) {
+    CFAllocatorContext* context =
+        ContextForCFAllocator(kCFAllocatorSystemDefault);
+    CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault.";
+    g_old_cfallocator_system_default = context->allocate;
+    CHECK(g_old_cfallocator_system_default)
+        << "Failed to get kCFAllocatorSystemDefault allocation function.";
+    context->allocate = oom_killer_cfallocator_system_default;
+
+    context = ContextForCFAllocator(kCFAllocatorMalloc);
+    CHECK(context) << "Failed to get context for kCFAllocatorMalloc.";
+    g_old_cfallocator_malloc = context->allocate;
+    CHECK(g_old_cfallocator_malloc)
+        << "Failed to get kCFAllocatorMalloc allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc;
+
+    context = ContextForCFAllocator(kCFAllocatorMallocZone);
+    CHECK(context) << "Failed to get context for kCFAllocatorMallocZone.";
+    g_old_cfallocator_malloc_zone = context->allocate;
+    CHECK(g_old_cfallocator_malloc_zone)
+        << "Failed to get kCFAllocatorMallocZone allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc_zone;
+  } else {
+    DLOG(WARNING) << "Internals of CFAllocator not known; out-of-memory "
+                     "failures via CFAllocator will not result in termination. "
+                     "http://crbug.com/45650";
+  }
+#endif
+
+  // === Cocoa NSObject allocation ===
+
+  // Note that both +[NSObject new] and +[NSObject alloc] call through to
+  // +[NSObject allocWithZone:].
+
+  CHECK(!g_old_allocWithZone) << "Old allocator unexpectedly non-null";
+
+  Class nsobject_class = [NSObject class];
+  Method orig_method =
+      class_getClassMethod(nsobject_class, @selector(allocWithZone:));
+  g_old_allocWithZone =
+      reinterpret_cast<allocWithZone_t>(method_getImplementation(orig_method));
+  CHECK(g_old_allocWithZone)
+      << "Failed to get allocWithZone allocation function.";
+  method_setImplementation(orig_method,
+                           reinterpret_cast<IMP>(oom_killer_allocWithZone));
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/base/process/memory_mac.mm b/base/process/memory_mac.mm
index 4c1b120..155004dc 100644
--- a/base/process/memory_mac.mm
+++ b/base/process/memory_mac.mm
@@ -4,25 +4,8 @@
 
 #include "base/process/memory.h"
 
-#include <CoreFoundation/CoreFoundation.h>
-#import <Foundation/Foundation.h>
-#include <errno.h>
-#include <mach/mach.h>
-#include <mach/mach_vm.h>
-#include <malloc/malloc.h>
-#import <objc/runtime.h>
-#include <stddef.h>
-
-#include <new>
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/mac/mac_util.h"
-#include "base/mac/mach_logging.h"
-#include "base/scoped_clear_errno.h"
+#include "base/allocator/allocator_interception_mac.h"
 #include "build/build_config.h"
-#include "third_party/apple_apsl/CFBase.h"
-#include "third_party/apple_apsl/malloc.h"
 
 namespace base {
 
@@ -32,521 +15,16 @@
 #endif
 }
 
-// ------------------------------------------------------------------------
-
-namespace {
-
-bool g_oom_killer_enabled;
-
-#if !defined(ADDRESS_SANITIZER)
-
-// Starting with Mac OS X 10.7, the zone allocators set up by the system are
-// read-only, to prevent them from being overwritten in an attack. However,
-// blindly unprotecting and reprotecting the zone allocators fails with
-// GuardMalloc because GuardMalloc sets up its zone allocator using a block of
-// memory in its bss. Explicit saving/restoring of the protection is required.
-//
-// This function takes a pointer to a malloc zone, de-protects it if necessary,
-// and returns (in the out parameters) a region of memory (if any) to be
-// re-protected when modifications are complete. This approach assumes that
-// there is no contention for the protection of this memory.
-void DeprotectMallocZone(ChromeMallocZone* default_zone,
-                         mach_vm_address_t* reprotection_start,
-                         mach_vm_size_t* reprotection_length,
-                         vm_prot_t* reprotection_value) {
-  mach_port_t unused;
-  *reprotection_start = reinterpret_cast<mach_vm_address_t>(default_zone);
-  struct vm_region_basic_info_64 info;
-  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
-  kern_return_t result =
-      mach_vm_region(mach_task_self(),
-                     reprotection_start,
-                     reprotection_length,
-                     VM_REGION_BASIC_INFO_64,
-                     reinterpret_cast<vm_region_info_t>(&info),
-                     &count,
-                     &unused);
-  MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_region";
-
-  // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
-  // balance it with a deallocate in case this ever changes. See 10.9.2
-  // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
-  mach_port_deallocate(mach_task_self(), unused);
-
-  // Does the region fully enclose the zone pointers? Possibly unwarranted
-  // simplification used: using the size of a full version 8 malloc zone rather
-  // than the actual smaller size if the passed-in zone is not version 8.
-  CHECK(*reprotection_start <=
-            reinterpret_cast<mach_vm_address_t>(default_zone));
-  mach_vm_size_t zone_offset = reinterpret_cast<mach_vm_size_t>(default_zone) -
-      reinterpret_cast<mach_vm_size_t>(*reprotection_start);
-  CHECK(zone_offset + sizeof(ChromeMallocZone) <= *reprotection_length);
-
-  if (info.protection & VM_PROT_WRITE) {
-    // No change needed; the zone is already writable.
-    *reprotection_start = 0;
-    *reprotection_length = 0;
-    *reprotection_value = VM_PROT_NONE;
-  } else {
-    *reprotection_value = info.protection;
-    result = mach_vm_protect(mach_task_self(),
-                             *reprotection_start,
-                             *reprotection_length,
-                             false,
-                             info.protection | VM_PROT_WRITE);
-    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
-  }
-}
-
-// === C malloc/calloc/valloc/realloc/posix_memalign ===
-
-typedef void* (*malloc_type)(struct _malloc_zone_t* zone,
-                             size_t size);
-typedef void* (*calloc_type)(struct _malloc_zone_t* zone,
-                             size_t num_items,
-                             size_t size);
-typedef void* (*valloc_type)(struct _malloc_zone_t* zone,
-                             size_t size);
-typedef void (*free_type)(struct _malloc_zone_t* zone,
-                          void* ptr);
-typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
-                              void* ptr,
-                              size_t size);
-typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
-                               size_t alignment,
-                               size_t size);
-
-malloc_type g_old_malloc;
-calloc_type g_old_calloc;
-valloc_type g_old_valloc;
-free_type g_old_free;
-realloc_type g_old_realloc;
-memalign_type g_old_memalign;
-
-malloc_type g_old_malloc_purgeable;
-calloc_type g_old_calloc_purgeable;
-valloc_type g_old_valloc_purgeable;
-free_type g_old_free_purgeable;
-realloc_type g_old_realloc_purgeable;
-memalign_type g_old_memalign_purgeable;
-
-void* oom_killer_malloc(struct _malloc_zone_t* zone,
-                        size_t size) {
-  void* result = g_old_malloc(zone, size);
-  if (!result && size)
-    TerminateBecauseOutOfMemory(size);
-  return result;
-}
-
-void* oom_killer_calloc(struct _malloc_zone_t* zone,
-                        size_t num_items,
-                        size_t size) {
-  void* result = g_old_calloc(zone, num_items, size);
-  if (!result && num_items && size)
-    TerminateBecauseOutOfMemory(num_items * size);
-  return result;
-}
-
-void* oom_killer_valloc(struct _malloc_zone_t* zone,
-                        size_t size) {
-  void* result = g_old_valloc(zone, size);
-  if (!result && size)
-    TerminateBecauseOutOfMemory(size);
-  return result;
-}
-
-void oom_killer_free(struct _malloc_zone_t* zone,
-                     void* ptr) {
-  g_old_free(zone, ptr);
-}
-
-void* oom_killer_realloc(struct _malloc_zone_t* zone,
-                         void* ptr,
-                         size_t size) {
-  void* result = g_old_realloc(zone, ptr, size);
-  if (!result && size)
-    TerminateBecauseOutOfMemory(size);
-  return result;
-}
-
-void* oom_killer_memalign(struct _malloc_zone_t* zone,
-                          size_t alignment,
-                          size_t size) {
-  void* result = g_old_memalign(zone, alignment, size);
-  // Only die if posix_memalign would have returned ENOMEM, since there are
-  // other reasons why NULL might be returned (see
-  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
-  if (!result && size && alignment >= sizeof(void*) &&
-      (alignment & (alignment - 1)) == 0) {
-    TerminateBecauseOutOfMemory(size);
-  }
-  return result;
-}
-
-void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
-                                  size_t size) {
-  void* result = g_old_malloc_purgeable(zone, size);
-  if (!result && size)
-    TerminateBecauseOutOfMemory(size);
-  return result;
-}
-
-void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
-                                  size_t num_items,
-                                  size_t size) {
-  void* result = g_old_calloc_purgeable(zone, num_items, size);
-  if (!result && num_items && size)
-    TerminateBecauseOutOfMemory(num_items * size);
-  return result;
-}
-
-void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
-                                  size_t size) {
-  void* result = g_old_valloc_purgeable(zone, size);
-  if (!result && size)
-    TerminateBecauseOutOfMemory(size);
-  return result;
-}
-
-void oom_killer_free_purgeable(struct _malloc_zone_t* zone,
-                               void* ptr) {
-  g_old_free_purgeable(zone, ptr);
-}
-
-void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
-                                   void* ptr,
-                                   size_t size) {
-  void* result = g_old_realloc_purgeable(zone, ptr, size);
-  if (!result && size)
-    TerminateBecauseOutOfMemory(size);
-  return result;
-}
-
-void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
-                                    size_t alignment,
-                                    size_t size) {
-  void* result = g_old_memalign_purgeable(zone, alignment, size);
-  // Only die if posix_memalign would have returned ENOMEM, since there are
-  // other reasons why NULL might be returned (see
-  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
-  if (!result && size && alignment >= sizeof(void*)
-      && (alignment & (alignment - 1)) == 0) {
-    TerminateBecauseOutOfMemory(size);
-  }
-  return result;
-}
-
-#endif  // !defined(ADDRESS_SANITIZER)
-
-// === C++ operator new ===
-
-void oom_killer_new() {
-  TerminateBecauseOutOfMemory(0);
-}
-
-#if !defined(ADDRESS_SANITIZER)
-
-// === Core Foundation CFAllocators ===
-
-bool CanGetContextForCFAllocator() {
-  return !base::mac::IsOSLaterThan10_12_DontCallThis();
-}
-
-CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
-  ChromeCFAllocatorLions* our_allocator =
-      const_cast<ChromeCFAllocatorLions*>(
-          reinterpret_cast<const ChromeCFAllocatorLions*>(allocator));
-  return &our_allocator->_context;
-}
-
-CFAllocatorAllocateCallBack g_old_cfallocator_system_default;
-CFAllocatorAllocateCallBack g_old_cfallocator_malloc;
-CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone;
-
-void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
-                                            CFOptionFlags hint,
-                                            void* info) {
-  void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
-  if (!result)
-    TerminateBecauseOutOfMemory(alloc_size);
-  return result;
-}
-
-void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
-                                    CFOptionFlags hint,
-                                    void* info) {
-  void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
-  if (!result)
-    TerminateBecauseOutOfMemory(alloc_size);
-  return result;
-}
-
-void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
-                                         CFOptionFlags hint,
-                                         void* info) {
-  void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
-  if (!result)
-    TerminateBecauseOutOfMemory(alloc_size);
-  return result;
-}
-
-#endif  // !defined(ADDRESS_SANITIZER)
-
-// === Cocoa NSObject allocation ===
-
-typedef id (*allocWithZone_t)(id, SEL, NSZone*);
-allocWithZone_t g_old_allocWithZone;
-
-id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone)
-{
-  id result = g_old_allocWithZone(self, _cmd, zone);
-  if (!result)
-    TerminateBecauseOutOfMemory(0);
-  return result;
-}
-
-}  // namespace
-
 bool UncheckedMalloc(size_t size, void** result) {
-#if defined(ADDRESS_SANITIZER)
-  *result = malloc(size);
-#else
-  if (g_old_malloc) {
-    *result = g_old_malloc(malloc_default_zone(), size);
-  } else {
-    *result = malloc(size);
-  }
-#endif  // defined(ADDRESS_SANITIZER)
-
-  return *result != NULL;
+  return allocator::UncheckedMallocMac(size, result);
 }
 
 bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
-#if defined(ADDRESS_SANITIZER)
-  *result = calloc(num_items, size);
-#else
-  if (g_old_calloc) {
-    *result = g_old_calloc(malloc_default_zone(), num_items, size);
-  } else {
-    *result = calloc(num_items, size);
-  }
-#endif  // defined(ADDRESS_SANITIZER)
-
-  return *result != NULL;
-}
-
-void* UncheckedMalloc(size_t size) {
-  void* address;
-  return UncheckedMalloc(size, &address) ? address : NULL;
-}
-
-void* UncheckedCalloc(size_t num_items, size_t size) {
-  void* address;
-  return UncheckedCalloc(num_items, size, &address) ? address : NULL;
+  return allocator::UncheckedCallocMac(num_items, size, result);
 }
 
 void EnableTerminationOnOutOfMemory() {
-  if (g_oom_killer_enabled)
-    return;
-
-  g_oom_killer_enabled = true;
-
-  // === C malloc/calloc/valloc/realloc/posix_memalign ===
-
-  // This approach is not perfect, as requests for amounts of memory larger than
-  // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will
-  // still fail with a NULL rather than dying (see
-  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details).
-  // Unfortunately, it's the best we can do. Also note that this does not affect
-  // allocations from non-default zones.
-
-#if !defined(ADDRESS_SANITIZER)
-  // Don't do anything special on OOM for the malloc zones replaced by
-  // AddressSanitizer, as modifying or protecting them may not work correctly.
-
-  CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc &&
-        !g_old_memalign) << "Old allocators unexpectedly non-null";
-
-  CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable &&
-        !g_old_valloc_purgeable && !g_old_realloc_purgeable &&
-        !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
-
-  ChromeMallocZone* default_zone =
-      reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
-  ChromeMallocZone* purgeable_zone =
-      reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone());
-
-  mach_vm_address_t default_reprotection_start = 0;
-  mach_vm_size_t default_reprotection_length = 0;
-  vm_prot_t default_reprotection_value = VM_PROT_NONE;
-  DeprotectMallocZone(default_zone,
-                      &default_reprotection_start,
-                      &default_reprotection_length,
-                      &default_reprotection_value);
-
-  mach_vm_address_t purgeable_reprotection_start = 0;
-  mach_vm_size_t purgeable_reprotection_length = 0;
-  vm_prot_t purgeable_reprotection_value = VM_PROT_NONE;
-  if (purgeable_zone) {
-    DeprotectMallocZone(purgeable_zone,
-                        &purgeable_reprotection_start,
-                        &purgeable_reprotection_length,
-                        &purgeable_reprotection_value);
-  }
-
-  // Default zone
-
-  g_old_malloc = default_zone->malloc;
-  g_old_calloc = default_zone->calloc;
-  g_old_valloc = default_zone->valloc;
-  g_old_free = default_zone->free;
-  g_old_realloc = default_zone->realloc;
-  CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free &&
-        g_old_realloc)
-      << "Failed to get system allocation functions.";
-
-  default_zone->malloc = oom_killer_malloc;
-  default_zone->calloc = oom_killer_calloc;
-  default_zone->valloc = oom_killer_valloc;
-  default_zone->free = oom_killer_free;
-  default_zone->realloc = oom_killer_realloc;
-
-  if (default_zone->version >= 5) {
-    g_old_memalign = default_zone->memalign;
-    if (g_old_memalign)
-      default_zone->memalign = oom_killer_memalign;
-  }
-
-  // Purgeable zone (if it exists)
-
-  if (purgeable_zone) {
-    g_old_malloc_purgeable = purgeable_zone->malloc;
-    g_old_calloc_purgeable = purgeable_zone->calloc;
-    g_old_valloc_purgeable = purgeable_zone->valloc;
-    g_old_free_purgeable = purgeable_zone->free;
-    g_old_realloc_purgeable = purgeable_zone->realloc;
-    CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable &&
-          g_old_valloc_purgeable && g_old_free_purgeable &&
-          g_old_realloc_purgeable)
-        << "Failed to get system allocation functions.";
-
-    purgeable_zone->malloc = oom_killer_malloc_purgeable;
-    purgeable_zone->calloc = oom_killer_calloc_purgeable;
-    purgeable_zone->valloc = oom_killer_valloc_purgeable;
-    purgeable_zone->free = oom_killer_free_purgeable;
-    purgeable_zone->realloc = oom_killer_realloc_purgeable;
-
-    if (purgeable_zone->version >= 5) {
-      g_old_memalign_purgeable = purgeable_zone->memalign;
-      if (g_old_memalign_purgeable)
-        purgeable_zone->memalign = oom_killer_memalign_purgeable;
-    }
-  }
-
-  // Restore protection if it was active.
-
-  if (default_reprotection_start) {
-    kern_return_t result = mach_vm_protect(mach_task_self(),
-                                           default_reprotection_start,
-                                           default_reprotection_length,
-                                           false,
-                                           default_reprotection_value);
-    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
-  }
-
-  if (purgeable_reprotection_start) {
-    kern_return_t result = mach_vm_protect(mach_task_self(),
-                                           purgeable_reprotection_start,
-                                           purgeable_reprotection_length,
-                                           false,
-                                           purgeable_reprotection_value);
-    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
-  }
-#endif
-
-  // === C malloc_zone_batch_malloc ===
-
-  // batch_malloc is omitted because the default malloc zone's implementation
-  // only supports batch_malloc for "tiny" allocations from the free list. It
-  // will fail for allocations larger than "tiny", and will only allocate as
-  // many blocks as it's able to from the free list. These factors mean that it
-  // can return less than the requested memory even in a non-out-of-memory
-  // situation. There's no good way to detect whether a batch_malloc failure is
-  // due to these other factors, or due to genuine memory or address space
-  // exhaustion. The fact that it only allocates space from the "tiny" free list
-  // means that it's likely that a failure will not be due to memory exhaustion.
-  // Similarly, these constraints on batch_malloc mean that callers must always
-  // be expecting to receive less memory than was requested, even in situations
-  // where memory pressure is not a concern. Finally, the only public interface
-  // to batch_malloc is malloc_zone_batch_malloc, which is specific to the
-  // system's malloc implementation. It's unlikely that anyone's even heard of
-  // it.
-
-  // === C++ operator new ===
-
-  // Yes, operator new does call through to malloc, but this will catch failures
-  // that our imperfect handling of malloc cannot.
-
-  std::set_new_handler(oom_killer_new);
-
-#ifndef ADDRESS_SANITIZER
-  // === Core Foundation CFAllocators ===
-
-  // This will not catch allocation done by custom allocators, but will catch
-  // all allocation done by system-provided ones.
-
-  CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc &&
-        !g_old_cfallocator_malloc_zone)
-      << "Old allocators unexpectedly non-null";
-
-  bool cf_allocator_internals_known = CanGetContextForCFAllocator();
-
-  if (cf_allocator_internals_known) {
-    CFAllocatorContext* context =
-        ContextForCFAllocator(kCFAllocatorSystemDefault);
-    CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault.";
-    g_old_cfallocator_system_default = context->allocate;
-    CHECK(g_old_cfallocator_system_default)
-        << "Failed to get kCFAllocatorSystemDefault allocation function.";
-    context->allocate = oom_killer_cfallocator_system_default;
-
-    context = ContextForCFAllocator(kCFAllocatorMalloc);
-    CHECK(context) << "Failed to get context for kCFAllocatorMalloc.";
-    g_old_cfallocator_malloc = context->allocate;
-    CHECK(g_old_cfallocator_malloc)
-        << "Failed to get kCFAllocatorMalloc allocation function.";
-    context->allocate = oom_killer_cfallocator_malloc;
-
-    context = ContextForCFAllocator(kCFAllocatorMallocZone);
-    CHECK(context) << "Failed to get context for kCFAllocatorMallocZone.";
-    g_old_cfallocator_malloc_zone = context->allocate;
-    CHECK(g_old_cfallocator_malloc_zone)
-        << "Failed to get kCFAllocatorMallocZone allocation function.";
-    context->allocate = oom_killer_cfallocator_malloc_zone;
-  } else {
-    DLOG(WARNING) << "Internals of CFAllocator not known; out-of-memory "
-                     "failures via CFAllocator will not result in termination. "
-                     "http://crbug.com/45650";
-  }
-#endif
-
-  // === Cocoa NSObject allocation ===
-
-  // Note that both +[NSObject new] and +[NSObject alloc] call through to
-  // +[NSObject allocWithZone:].
-
-  CHECK(!g_old_allocWithZone)
-      << "Old allocator unexpectedly non-null";
-
-  Class nsobject_class = [NSObject class];
-  Method orig_method = class_getClassMethod(nsobject_class,
-                                            @selector(allocWithZone:));
-  g_old_allocWithZone = reinterpret_cast<allocWithZone_t>(
-      method_getImplementation(orig_method));
-  CHECK(g_old_allocWithZone)
-      << "Failed to get allocWithZone allocation function.";
-  method_setImplementation(orig_method,
-                           reinterpret_cast<IMP>(oom_killer_allocWithZone));
+  allocator::InterceptAllocationsMac();
 }
 
 }  // namespace base
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index d6e93d3..0ecc9f76 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -373,6 +373,12 @@
     if (is_multi_dll_chrome) {
       defines += [ "CHROME_MULTIPLE_DLL_BROWSER" ]
       deps += [ "//content/public/app:browser" ]
+      assert_no_deps = [
+        # The browser DLL may not depend on blink or v8.
+        "//third_party/WebKit/public:blink",
+        "//gin",
+        "//v8",
+      ]
     } else {
       deps += [
         ":child_dependencies",
@@ -1219,16 +1225,20 @@
 
   if (!is_component_build) {
     assert_no_deps = [
-      # Blink and V8 should not be used in the browser process. In component
-      # build this is OK because all of content is linked into one library.
-      # Note that the blink_headers target is OK, so we can't do a wildcard for
-      # all blink targets.
+      # Blink should not be used in the browser process. In component build this
+      # is OK because all of content is linked into one library. Note that the
+      # blink_headers target is OK, so we can't do a wildcard for all blink
+      # targets.
       "//third_party/WebKit/public:blink",
-      # TODO(brettw) bug 581766: V8 should not be linked into the browser
-      # process, and then we can enable this. When testing whether you can
-      # enable this, run with a non-component build.
-      #"//v8/*",
     ]
+
+    if (is_win) {
+      assert_no_deps += [
+        # V8/Gin should not be used in the browser DLL on Windows.
+        "//gin",
+        "//v8",
+      ]
+    }
   }
 }
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 16b3c719..3b0661d 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=58
 MINOR=0
-BUILD=2993
+BUILD=2994
 PATCH=0
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
index 76aa1ef..a3cd928 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabModelImpl.java
@@ -230,7 +230,9 @@
         //   * Otherwise, if closing the last incognito tab, select the current normal tab.
         //   * Otherwise, select nothing.
         Tab nextTab = null;
-        if (tabToClose != currentTab && currentTab != null && !currentTab.isClosing()) {
+        if (!isCurrentModel()) {
+            nextTab = TabModelUtils.getCurrentTab(mModelDelegate.getCurrentModel());
+        } else if (tabToClose != currentTab && currentTab != null && !currentTab.isClosing()) {
             nextTab = currentTab;
         } else if (parentTab != null && !parentTab.isClosing()
                 && !mModelDelegate.isInOverviewMode()) {
@@ -239,10 +241,9 @@
             nextTab = adjacentTab;
         } else if (isIncognito()) {
             nextTab = TabModelUtils.getCurrentTab(mModelDelegate.getModel(false));
-            if (nextTab != null && nextTab.isClosing()) nextTab = null;
         }
 
-        return nextTab;
+        return nextTab != null && nextTab.isClosing() ? null : nextTab;
     }
 
     @Override
@@ -292,7 +293,7 @@
         WebContents webContents = tab.getWebContents();
         if (webContents != null) webContents.setAudioMuted(false);
 
-        boolean activeModel = mModelDelegate.getCurrentModel() == this;
+        boolean activeModel = isCurrentModel();
 
         if (mIndex == INVALID_TAB_INDEX) {
             // If we're the active model call setIndex to actually select this tab, otherwise just
@@ -443,14 +444,16 @@
     // Index of the given tab in the order of the tab stack.
     @Override
     public int indexOf(Tab tab) {
-        return mTabs.indexOf(tab);
+        if (tab == null) return INVALID_TAB_INDEX;
+        int retVal = mTabs.indexOf(tab);
+        return retVal == -1 ? INVALID_TAB_INDEX : retVal;
     }
 
     /**
      * @return true if this is the current model according to the model selector
      */
     private boolean isCurrentModel() {
-        return mModelDelegate.getCurrentModel() == this;
+        return mModelDelegate.getCurrentModel().isIncognito() == isIncognito();
     }
 
     // TODO(aurimas): Move this method to TabModelSelector when notifications move there.
@@ -544,8 +547,8 @@
         final int closingTabId = tab.getId();
         final int closingTabIndex = indexOf(tab);
 
-        Tab currentTab = TabModelUtils.getCurrentTab(this);
-        Tab adjacentTab = getTabAt(closingTabIndex == 0 ? 1 : closingTabIndex - 1);
+        Tab currentTabInModel = TabModelUtils.getCurrentTab(this);
+        Tab adjacentTabInModel = getTabAt(closingTabIndex == 0 ? 1 : closingTabIndex - 1);
         Tab nextTab = getNextTabIfClosed(closingTabId);
 
         // TODO(dtrainor): Update the list of undoable tabs instead of committing it.
@@ -567,8 +570,8 @@
         int nextTabIndex = nextTab == null ? INVALID_TAB_INDEX : TabModelUtils.getTabIndexById(
                 mModelDelegate.getModel(nextIsIncognito), nextTabId);
 
-        if (nextTab != currentTab) {
-            if (nextIsIncognito != isIncognito()) mIndex = indexOf(adjacentTab);
+        if (nextTab != currentTabInModel) {
+            if (nextIsIncognito != isIncognito()) mIndex = indexOf(adjacentTabInModel);
 
             TabModel nextModel = mModelDelegate.getModel(nextIsIncognito);
             nextModel.setIndex(nextTabIndex, selectionType);
diff --git a/chrome/app/mash/BUILD.gn b/chrome/app/mash/BUILD.gn
index 76dc0c4..e78d037 100644
--- a/chrome/app/mash/BUILD.gn
+++ b/chrome/app/mash/BUILD.gn
@@ -11,6 +11,7 @@
     "mash_runner.h",
   ]
   deps = [
+    ":catalog_cpp_source",
     "//base:i18n",
     "//components/tracing:startup_tracing",
     "//content/public/common",
@@ -28,10 +29,6 @@
     "//services/service_manager/standalone",
     "//url",
   ]
-  data_deps = [
-    ":catalog_copy",
-    "//chrome/app:service_manifests",
-  ]
 
   if (is_chromeos) {
     sources += [
@@ -80,12 +77,7 @@
   catalog_deps = [ "//chrome/app:catalog" ]
 }
 
-copy("catalog_copy") {
-  sources = get_target_outputs(":catalog")
-  outputs = [
-    "${root_out_dir}/chrome_mash_catalog.json",
-  ]
-  deps = [
-    ":catalog",
-  ]
+catalog_cpp_source("catalog_cpp_source") {
+  catalog = ":catalog"
+  output_symbol_name = "kChromeMashCatalogContents"
 }
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index 72da1805..42c50057 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -61,6 +61,9 @@
 
 using service_manager::mojom::ServiceFactory;
 
+// Defined externally by the ":catalog_cpp_source" target.
+extern const char kChromeMashCatalogContents[];
+
 namespace {
 
 // kProcessType used to identify child processes.
@@ -68,9 +71,6 @@
 
 const char kChromeMashServiceName[] = "chrome_mash";
 
-const base::FilePath::CharType kChromeMashCatalogFilename[] =
-    FILE_PATH_LITERAL("chrome_mash_catalog.json");
-
 bool IsChild() {
   return base::CommandLine::ForCurrentProcess()->HasSwitch(
              switches::kProcessType) &&
@@ -177,14 +177,8 @@
       ipc_thread.task_runner(),
       mojo::edk::ScopedIPCSupport::ShutdownPolicy::FAST);
 
-  std::string catalog_contents;
-  base::FilePath exe_path;
-  base::PathService::Get(base::DIR_EXE, &exe_path);
-  base::FilePath catalog_path = exe_path.Append(kChromeMashCatalogFilename);
-  bool result = base::ReadFileToString(catalog_path, &catalog_contents);
-  DCHECK(result);
   std::unique_ptr<base::Value> manifest_value =
-      base::JSONReader::Read(catalog_contents);
+      base::JSONReader::Read(kChromeMashCatalogContents);
   DCHECK(manifest_value);
 
   // TODO(sky): refactor BackgroundServiceManager so can supply own context, we
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f4006f4..da403fc 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1544,7 +1544,6 @@
     "//mojo/public/cpp/bindings",
     "//mojo/public/js",
     "//net:extras",
-    "//net:net_with_v8",
     "//ppapi/features",
     "//printing/features",
     "//rlz/features",
@@ -1589,9 +1588,19 @@
     "//ui/strings",
     "//ui/surface",
     "//ui/web_dialogs",
-    "//v8",
   ]
 
+  # Android does in-process PAC, so must link against V8 directly. Other
+  # platforms use OOP Mojo resolution.
+  if (is_android) {
+    deps += [
+      "//net:net_with_v8",
+      "//v8",
+    ]
+  } else {
+    deps += [ "//net:net" ]
+  }
+
   if (is_chromeos && use_cras) {
     defines += [ "USE_CRAS" ]
   }
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
index 054f8fe..44b3116 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -40,7 +40,6 @@
 #include "chromeos/cryptohome/async_method_caller.h"
 #include "chromeos/cryptohome/cryptohome_parameters.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/session_manager_client.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/ownership/owner_key_util.h"
 #include "components/prefs/pref_registry_simple.h"
@@ -52,7 +51,6 @@
 #include "content/public/browser/browser_thread.h"
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/manifest_handlers/kiosk_mode_info.h"
-#include "third_party/cros_system_api/switches/chrome_switches.h"
 
 namespace chromeos {
 
@@ -149,14 +147,6 @@
                                           minor_version, bugfix_version));
 }
 
-// Converts a flag constant to actual command line switch value.
-std::string GetSwitchString(const std::string& flag_name) {
-  base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
-  cmd_line.AppendSwitch(flag_name);
-  DCHECK_EQ(2U, cmd_line.argv().size());
-  return cmd_line.argv()[1];
-}
-
 }  // namespace
 
 // static
@@ -251,70 +241,10 @@
                                    const std::string& app_id) {
   LOG_IF(FATAL, app_session_) << "Kiosk session is already initialized.";
 
-  base::CommandLine session_flags(base::CommandLine::NO_PROGRAM);
-  if (GetSwitchesForSessionRestore(app_id, &session_flags)) {
-    base::CommandLine::StringVector flags;
-    // argv[0] is the program name |base::CommandLine::NO_PROGRAM|.
-    flags.assign(session_flags.argv().begin() + 1, session_flags.argv().end());
-
-    // Update user flags, but do not restart Chrome - the purpose of the flags
-    // set here is to be able to properly restore session if the session is
-    // restarted - e.g. due to crash. For example, this will ensure restarted
-    // app session restores auto-launched state.
-    DBusThreadManager::Get()->GetSessionManagerClient()->SetFlagsForUser(
-        cryptohome::Identification(
-            user_manager::UserManager::Get()->GetActiveUser()->GetAccountId()),
-        flags);
-  }
-
   app_session_.reset(new AppSession);
   app_session_->Init(profile, app_id);
 }
 
-bool KioskAppManager::GetSwitchesForSessionRestore(
-    const std::string& app_id,
-    base::CommandLine* switches) {
-  bool auto_launched = app_id == currently_auto_launched_with_zero_delay_app_;
-  const base::CommandLine* current_command_line =
-      base::CommandLine::ForCurrentProcess();
-  bool has_auto_launched_flag =
-      current_command_line->HasSwitch(switches::kAppAutoLaunched);
-  if (auto_launched == has_auto_launched_flag)
-    return false;
-
-  // Collect current policy defined switches, so they can be passed on to the
-  // session manager as well - otherwise they would get lost on restart.
-  // This ignores 'flag-switches-begin' - 'flag-switches-end' flags, but those
-  // should not be present for kiosk sessions.
-  bool in_policy_switches_block = false;
-  const std::string policy_switches_begin =
-      GetSwitchString(switches::kPolicySwitchesBegin);
-  const std::string policy_switches_end =
-      GetSwitchString(switches::kPolicySwitchesEnd);
-
-  for (const auto& it : current_command_line->argv()) {
-    if (it == policy_switches_begin) {
-      DCHECK(!in_policy_switches_block);
-      in_policy_switches_block = true;
-    }
-
-    if (in_policy_switches_block)
-      switches->AppendSwitch(it);
-
-    if (it == policy_switches_end) {
-      DCHECK(in_policy_switches_block);
-      in_policy_switches_block = false;
-    }
-  }
-
-  DCHECK(!in_policy_switches_block);
-
-  if (auto_launched)
-    switches->AppendSwitch(switches::kAppAutoLaunched);
-
-  return true;
-}
-
 void KioskAppManager::AddAppForTest(
     const std::string& app_id,
     const AccountId& account_id,
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.h b/chrome/browser/chromeos/app_mode/kiosk_app_manager.h
index f057d11..7aac2e7 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.h
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.h
@@ -26,10 +26,6 @@
 class PrefRegistrySimple;
 class Profile;
 
-namespace base {
-class CommandLine;
-}
-
 namespace extensions {
 class Extension;
 class ExternalLoader;
@@ -321,15 +317,6 @@
   // Returns the auto launch delay.
   base::TimeDelta GetAutoLaunchDelay() const;
 
-  // Gets list of user switches that should be passed to Chrome in case current
-  // session has to be restored, e.g. in case of a crash. The switches will be
-  // returned as |switches| command line arguments.
-  // Returns whether the set of switches would have to be changed in respect to
-  // the current set of switches - if that is not the case |switches| might not
-  // get populated.
-  bool GetSwitchesForSessionRestore(const std::string& app_id,
-                                    base::CommandLine* switches);
-
   // True if machine ownership is already established.
   bool ownership_established_;
   std::vector<std::unique_ptr<KioskAppData>> apps_;
diff --git a/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc
new file mode 100644
index 0000000..703a763
--- /dev/null
+++ b/chrome/browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc
@@ -0,0 +1,194 @@
+// 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 <memory>
+#include <string>
+
+#include "apps/test/app_window_waiter.h"
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/app_mode/fake_cws.h"
+#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
+#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
+#include "chrome/browser/chromeos/policy/device_local_account.h"
+#include "chrome/browser/chromeos/policy/device_policy_builder.h"
+#include "chrome/browser/extensions/browsertest_util.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_constants.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/chromeos_switches.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_session_manager_client.h"
+#include "chromeos/dbus/fake_shill_manager_client.h"
+#include "components/ownership/mock_owner_key_util.h"
+#include "extensions/browser/app_window/app_window.h"
+#include "extensions/browser/app_window/app_window_registry.h"
+#include "extensions/browser/app_window/native_app_window.h"
+#include "extensions/common/value_builder.h"
+#include "extensions/test/extension_test_message_listener.h"
+#include "net/dns/mock_host_resolver.h"
+
+namespace em = enterprise_management;
+
+namespace chromeos {
+
+namespace {
+
+const char kTestKioskApp[] = "ggbflgnkafappblpkiflbgpmkfdpnhhe";
+
+}  // namespace
+
+class KioskCrashRestoreTest : public InProcessBrowserTest {
+ public:
+  KioskCrashRestoreTest()
+      : owner_key_util_(new ownership::MockOwnerKeyUtil()),
+        fake_cws_(new FakeCWS) {}
+
+  // InProcessBrowserTest
+  void SetUp() override {
+    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+    InProcessBrowserTest::SetUp();
+  }
+
+  bool SetUpUserDataDirectory() override {
+    SetUpExistingKioskApp();
+    return true;
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    host_resolver()->AddRule("*", "127.0.0.1");
+    SimulateNetworkOnline();
+
+    OverrideDevicePolicy();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    const AccountId account_id = AccountId::FromUserEmail(GetTestAppUserId());
+    const cryptohome::Identification cryptohome_id(account_id);
+
+    command_line->AppendSwitchASCII(switches::kLoginUser, cryptohome_id.id());
+    command_line->AppendSwitchASCII(
+        switches::kLoginProfile,
+        CryptohomeClient::GetStubSanitizedUsername(cryptohome_id));
+
+    fake_cws_->Init(embedded_test_server());
+    fake_cws_->SetUpdateCrx(test_app_id_, test_app_id_ + ".crx", "1.0.0");
+  }
+
+  void SetUpOnMainThread() override {
+    extensions::browsertest_util::CreateAndInitializeLocalCache();
+
+    embedded_test_server()->StartAcceptingConnections();
+  }
+
+  const std::string GetTestAppUserId() const {
+    return policy::GenerateDeviceLocalAccountUserId(
+        test_app_id_, policy::DeviceLocalAccount::TYPE_KIOSK_APP);
+  }
+
+  const std::string& test_app_id() const { return test_app_id_; }
+
+ private:
+  void SetUpExistingKioskApp() {
+    // Create policy data that contains the test app as an existing kiosk app.
+    em::DeviceLocalAccountsProto* const device_local_accounts =
+        device_policy_.payload().mutable_device_local_accounts();
+
+    em::DeviceLocalAccountInfoProto* const account =
+        device_local_accounts->add_account();
+    account->set_account_id(test_app_id_);
+    account->set_type(
+        em::DeviceLocalAccountInfoProto_AccountType_ACCOUNT_TYPE_KIOSK_APP);
+    account->mutable_kiosk_app()->set_app_id(test_app_id_);
+    device_policy_.Build();
+
+    // Prepare the policy data to store in device policy cache.
+    em::PolicyData policy_data;
+    CHECK(device_policy_.payload().SerializeToString(
+        policy_data.mutable_policy_value()));
+    const std::string policy_data_string = policy_data.SerializeAsString();
+    std::string encoded;
+    base::Base64Encode(policy_data_string, &encoded);
+
+    // Store policy data and existing device local accounts in local state.
+    const std::string local_state_json =
+        extensions::DictionaryBuilder()
+            .Set(prefs::kDeviceSettingsCache, encoded)
+            .Set("PublicAccounts",
+                 extensions::ListBuilder().Append(GetTestAppUserId()).Build())
+            .ToJSON();
+
+    base::FilePath local_state_file;
+    CHECK(PathService::Get(chrome::DIR_USER_DATA, &local_state_file));
+    local_state_file = local_state_file.Append(chrome::kLocalStateFilename);
+    base::WriteFile(local_state_file, local_state_json.data(),
+                    local_state_json.size());
+  }
+
+  void SimulateNetworkOnline() {
+    NetworkPortalDetectorTestImpl* const network_portal_detector =
+        new NetworkPortalDetectorTestImpl();
+    // Takes ownership of |network_portal_detector|.
+    network_portal_detector::InitializeForTesting(network_portal_detector);
+    network_portal_detector->SetDefaultNetworkForTesting(
+        FakeShillManagerClient::kFakeEthernetNetworkGuid);
+
+    NetworkPortalDetector::CaptivePortalState online_state;
+    online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
+    online_state.response_code = 204;
+    network_portal_detector->SetDetectionResultsForTesting(
+        FakeShillManagerClient::kFakeEthernetNetworkGuid, online_state);
+  }
+
+  void OverrideDevicePolicy() {
+    OwnerSettingsServiceChromeOSFactory::GetInstance()
+        ->SetOwnerKeyUtilForTesting(owner_key_util_);
+    owner_key_util_->SetPublicKeyFromPrivateKey(
+        *device_policy_.GetSigningKey());
+
+    session_manager_client_ = new FakeSessionManagerClient;
+    session_manager_client_->set_device_policy(device_policy_.GetBlob());
+
+    DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
+        std::unique_ptr<SessionManagerClient>(session_manager_client_));
+  }
+
+  std::string test_app_id_ = kTestKioskApp;
+
+  policy::DevicePolicyBuilder device_policy_;
+  scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_;
+  FakeSessionManagerClient* session_manager_client_;
+  std::unique_ptr<FakeCWS> fake_cws_;
+
+  DISALLOW_COPY_AND_ASSIGN(KioskCrashRestoreTest);
+};
+
+IN_PROC_BROWSER_TEST_F(KioskCrashRestoreTest, Basic) {
+  ExtensionTestMessageListener launch_data_check_listener(
+      "launchData.isKioskSession = true", false);
+
+  Profile* const app_profile = ProfileManager::GetPrimaryUserProfile();
+  ASSERT_TRUE(app_profile);
+  extensions::AppWindowRegistry* const app_window_registry =
+      extensions::AppWindowRegistry::Get(app_profile);
+  extensions::AppWindow* const window =
+      apps::AppWindowWaiter(app_window_registry, test_app_id()).Wait();
+  ASSERT_TRUE(window);
+
+  window->GetBaseWindow()->Close();
+
+  // Wait until the app terminates if it is still running.
+  if (!app_window_registry->GetAppWindowsForApp(test_app_id()).empty())
+    base::RunLoop().Run();
+
+  EXPECT_TRUE(launch_data_check_listener.was_satisfied());
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc b/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
deleted file mode 100644
index 9b5f8c6..0000000
--- a/chrome/browser/chromeos/login/auto_launched_kiosk_browsertest.cc
+++ /dev/null
@@ -1,470 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "apps/test/app_window_waiter.h"
-#include "base/base64.h"
-#include "base/command_line.h"
-#include "base/files/file_path.h"
-#include "base/json/json_file_value_serializer.h"
-#include "base/logging.h"
-#include "base/path_service.h"
-#include "base/run_loop.h"
-#include "base/values.h"
-#include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/app_mode/fake_cws.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
-#include "chrome/browser/chromeos/login/app_launch_controller.h"
-#include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
-#include "chrome/browser/chromeos/policy/device_local_account.h"
-#include "chrome/browser/chromeos/policy/device_policy_builder.h"
-#include "chrome/browser/chromeos/settings/stub_install_attributes.h"
-#include "chrome/browser/extensions/browsertest_util.h"
-#include "chrome/browser/extensions/extension_apitest.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_constants.h"
-#include "chrome/common/chrome_paths.h"
-#include "chrome/common/pref_names.h"
-#include "chromeos/dbus/cryptohome_client.h"
-#include "chromeos/dbus/dbus_thread_manager.h"
-#include "chromeos/dbus/fake_session_manager_client.h"
-#include "chromeos/dbus/shill_manager_client.h"
-#include "components/ownership/mock_owner_key_util.h"
-#include "content/public/browser/notification_observer.h"
-#include "content/public/browser/notification_registrar.h"
-#include "content/public/browser/notification_service.h"
-#include "extensions/browser/app_window/app_window.h"
-#include "extensions/browser/app_window/app_window_registry.h"
-#include "extensions/browser/app_window/native_app_window.h"
-#include "extensions/common/value_builder.h"
-#include "extensions/test/extension_test_message_listener.h"
-#include "net/dns/mock_host_resolver.h"
-#include "third_party/cros_system_api/switches/chrome_switches.h"
-
-namespace em = enterprise_management;
-
-namespace chromeos {
-
-namespace {
-
-// This is a simple test app that creates an app window and immediately closes
-// it again. Webstore data json is in
-//   chrome/test/data/chromeos/app_mode/webstore/inlineinstall/
-//       detail/ggbflgnkafappblpkiflbgpmkfdpnhhe
-const char kTestKioskApp[] = "ggbflgnkafappblpkiflbgpmkfdpnhhe";
-
-const char kTestAccountId[] = "enterprise-kiosk-app@localhost";
-
-const char kSessionManagerStateCache[] = "test_session_manager_state.json";
-
-// Keys for values in dictionary used to preserve session manager state.
-const char kLoginArgsKey[] = "login_args";
-const char kExtraArgsKey[] = "extra_args";
-const char kArgNameKey[] = "name";
-const char kArgValueKey[] = "value";
-
-// Default set policy switches.
-const struct {
-  const char* name;
-  const char* value;
-} kDefaultPolicySwitches[] = {{"test_switch_1", ""},
-                              {"test_switch_2", "test_switch_2_value"}};
-
-// Fake session manager implementation that persists its state in local file.
-// It can be used to preserve session state in PRE_ browser tests.
-// Primarily used for testing user/login switches.
-class PersistentSessionManagerClient : public FakeSessionManagerClient {
- public:
-  PersistentSessionManagerClient() {}
-
-  ~PersistentSessionManagerClient() override {
-    PersistFlagsToFile(backing_file_);
-  }
-
-  // Initializes session state (primarily session flags)- if |backing_file|
-  // exists, the session state is restored from the file value. Otherwise it's
-  // set to the default session state.
-  void Initialize(const base::FilePath& backing_file) {
-    backing_file_ = backing_file;
-
-    if (ExtractFlagsFromFile(backing_file_))
-      return;
-
-    // Failed to extract ached flags - set the default values.
-    login_args_ = {{"login-manager", ""}};
-
-    extra_args_ = {{switches::kPolicySwitchesBegin, ""}};
-    for (size_t i = 0; i < arraysize(kDefaultPolicySwitches); ++i) {
-      extra_args_.push_back(
-          {kDefaultPolicySwitches[i].name, kDefaultPolicySwitches[i].value});
-    }
-    extra_args_.push_back({switches::kPolicySwitchesEnd, ""});
-  }
-
-  void AppendSwitchesToCommandLine(base::CommandLine* command_line) {
-    for (const auto& flag : login_args_)
-      command_line->AppendSwitchASCII(flag.name, flag.value);
-    for (const auto& flag : extra_args_)
-      command_line->AppendSwitchASCII(flag.name, flag.value);
-  }
-
-  void StartSession(const cryptohome::Identification& cryptohome_id) override {
-    FakeSessionManagerClient::StartSession(cryptohome_id);
-
-    std::string user_id_hash =
-        CryptohomeClient::GetStubSanitizedUsername(cryptohome_id);
-    login_args_ = {{"login-user", cryptohome_id.id()},
-                   {"login-profile", user_id_hash}};
-  }
-
-  void StopSession() override {
-    FakeSessionManagerClient::StopSession();
-
-    login_args_ = {{"login-manager", ""}};
-  }
-
-  bool SupportsRestartToApplyUserFlags() const override { return true; }
-
-  void SetFlagsForUser(const cryptohome::Identification& identification,
-                       const std::vector<std::string>& flags) override {
-    extra_args_.clear();
-    FakeSessionManagerClient::SetFlagsForUser(identification, flags);
-
-    std::vector<std::string> argv = {"" /* Empty program */};
-    argv.insert(argv.end(), flags.begin(), flags.end());
-
-    // Parse flag name-value pairs using command line initialization.
-    base::CommandLine cmd_line(base::CommandLine::NO_PROGRAM);
-    cmd_line.InitFromArgv(argv);
-
-    for (const auto& flag : cmd_line.GetSwitches())
-      extra_args_.push_back({flag.first, flag.second});
-  }
-
- private:
-  // Keeps information about a switch - its name and value.
-  struct Switch {
-    std::string name;
-    std::string value;
-  };
-
-  bool ExtractFlagsFromFile(const base::FilePath& backing_file) {
-    JSONFileValueDeserializer deserializer(backing_file);
-
-    int error_code = 0;
-    std::unique_ptr<base::Value> value =
-        deserializer.Deserialize(&error_code, nullptr);
-    if (error_code != JSONFileValueDeserializer::JSON_NO_ERROR)
-      return false;
-
-    std::unique_ptr<base::DictionaryValue> value_dict =
-        base::DictionaryValue::From(std::move(value));
-    DCHECK(value_dict);
-
-    CHECK(InitArgListFromCachedValue(*value_dict, kLoginArgsKey, &login_args_));
-    CHECK(InitArgListFromCachedValue(*value_dict, kExtraArgsKey, &extra_args_));
-    return true;
-  }
-
-  bool PersistFlagsToFile(const base::FilePath& backing_file) {
-    base::DictionaryValue cached_state;
-    cached_state.Set(kLoginArgsKey, GetArgListValue(login_args_));
-    cached_state.Set(kExtraArgsKey, GetArgListValue(extra_args_));
-
-    JSONFileValueSerializer serializer(backing_file);
-    return serializer.Serialize(cached_state);
-  }
-
-  std::unique_ptr<base::ListValue> GetArgListValue(
-      const std::vector<Switch>& args) {
-    std::unique_ptr<base::ListValue> result(new base::ListValue());
-    for (const auto& arg : args) {
-      result->Append(extensions::DictionaryBuilder()
-                         .Set(kArgNameKey, arg.name)
-                         .Set(kArgValueKey, arg.value)
-                         .Build());
-    }
-    return result;
-  }
-
-  bool InitArgListFromCachedValue(const base::DictionaryValue& cache_value,
-                                  const std::string& list_key,
-                                  std::vector<Switch>* arg_list_out) {
-    arg_list_out->clear();
-    const base::ListValue* arg_list_value;
-    if (!cache_value.GetList(list_key, &arg_list_value))
-      return false;
-    for (size_t i = 0; i < arg_list_value->GetSize(); ++i) {
-      const base::DictionaryValue* arg_value;
-      if (!arg_list_value->GetDictionary(i, &arg_value))
-        return false;
-      Switch arg;
-      if (!arg_value->GetStringASCII(kArgNameKey, &arg.name) ||
-          !arg_value->GetStringASCII(kArgValueKey, &arg.value)) {
-        return false;
-      }
-      arg_list_out->push_back(arg);
-    }
-    return true;
-  }
-
-  std::vector<Switch> login_args_;
-  std::vector<Switch> extra_args_;
-
-  base::FilePath backing_file_;
-
-  DISALLOW_COPY_AND_ASSIGN(PersistentSessionManagerClient);
-};
-
-// Used to listen for app termination notification.
-class TerminationObserver : public content::NotificationObserver {
- public:
-  TerminationObserver() {
-    registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
-                   content::NotificationService::AllSources());
-  }
-  ~TerminationObserver() override = default;
-
-  // Whether app has been terminated - i.e. whether app termination notification
-  // has been observed.
-  bool terminated() const { return notification_seen_; }
-
- private:
-  void Observe(int type,
-               const content::NotificationSource& source,
-               const content::NotificationDetails& details) override {
-    ASSERT_EQ(chrome::NOTIFICATION_APP_TERMINATING, type);
-    notification_seen_ = true;
-  }
-
-  bool notification_seen_ = false;
-  content::NotificationRegistrar registrar_;
-
-  DISALLOW_COPY_AND_ASSIGN(TerminationObserver);
-};
-
-}  // namespace
-
-class AutoLaunchedKioskTest : public ExtensionApiTest {
- public:
-  AutoLaunchedKioskTest()
-      : install_attributes_(
-            chromeos::ScopedStubInstallAttributes::CreateEnterprise(
-                "domain.com",
-                "device_id")),
-        owner_key_util_(new ownership::MockOwnerKeyUtil()),
-        fake_session_manager_(new PersistentSessionManagerClient()),
-        fake_cws_(new FakeCWS) {
-    set_chromeos_user_ = false;
-  }
-
-  ~AutoLaunchedKioskTest() override = default;
-
-  void SetUp() override {
-    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
-    AppLaunchController::SkipSplashWaitForTesting();
-
-    ExtensionApiTest::SetUp();
-  }
-
-  void SetUpCommandLine(base::CommandLine* command_line) override {
-    fake_cws_->Init(embedded_test_server());
-    fake_cws_->SetUpdateCrx(kTestKioskApp, std::string(kTestKioskApp) + ".crx",
-                            "1.0.0");
-    ExtensionApiTest::SetUpCommandLine(command_line);
-  }
-
-  bool SetUpUserDataDirectory() override {
-    InitDevicePolicy();
-
-    base::FilePath user_data_path;
-    CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_path));
-    CacheDevicePolicyToLocalState(user_data_path);
-
-    // Restore session_manager state and ensure session manager flags are
-    // applied.
-    fake_session_manager_->Initialize(
-        user_data_path.Append(kSessionManagerStateCache));
-    fake_session_manager_->AppendSwitchesToCommandLine(
-        base::CommandLine::ForCurrentProcess());
-
-    return true;
-  }
-
-  void SetUpInProcessBrowserTestFixture() override {
-    host_resolver()->AddRule("*", "127.0.0.1");
-
-    OwnerSettingsServiceChromeOSFactory::GetInstance()
-        ->SetOwnerKeyUtilForTesting(owner_key_util_);
-    owner_key_util_->SetPublicKeyFromPrivateKey(
-        *device_policy_.GetSigningKey());
-
-    fake_session_manager_->set_device_policy(device_policy_.GetBlob());
-    DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
-        std::move(fake_session_manager_));
-
-    ExtensionApiTest::SetUpInProcessBrowserTestFixture();
-  }
-
-  void SetUpOnMainThread() override {
-    extensions::browsertest_util::CreateAndInitializeLocalCache();
-
-    embedded_test_server()->StartAcceptingConnections();
-
-    ExtensionApiTest::SetUpOnMainThread();
-  }
-
-  void RunTestOnMainThreadLoop() override {
-    termination_observer_.reset(new TerminationObserver());
-
-    ExtensionApiTest::RunTestOnMainThreadLoop();
-  }
-
-  void TearDownOnMainThread() override {
-    termination_observer_.reset();
-
-    ExtensionApiTest::TearDownOnMainThread();
-  }
-
-  void InitDevicePolicy() {
-    // Create device policy, and cache it to local state.
-    em::DeviceLocalAccountsProto* const device_local_accounts =
-        device_policy_.payload().mutable_device_local_accounts();
-
-    em::DeviceLocalAccountInfoProto* const account =
-        device_local_accounts->add_account();
-    account->set_account_id(kTestAccountId);
-    account->set_type(em::DeviceLocalAccountInfoProto::ACCOUNT_TYPE_KIOSK_APP);
-    account->mutable_kiosk_app()->set_app_id(kTestKioskApp);
-
-    device_local_accounts->set_auto_login_id(kTestAccountId);
-
-    device_policy_.Build();
-  }
-
-  void CacheDevicePolicyToLocalState(const base::FilePath& user_data_path) {
-    em::PolicyData policy_data;
-    DCHECK(device_policy_.payload().SerializeToString(
-        policy_data.mutable_policy_value()));
-    const std::string policy_data_str = policy_data.SerializeAsString();
-    std::string policy_data_encoded;
-    base::Base64Encode(policy_data_str, &policy_data_encoded);
-
-    std::unique_ptr<base::DictionaryValue> local_state =
-        extensions::DictionaryBuilder()
-            .Set(prefs::kDeviceSettingsCache, policy_data_encoded)
-            .Set("PublicAccounts",
-                 extensions::ListBuilder().Append(GetTestAppUserId()).Build())
-            .Build();
-
-    JSONFileValueSerializer serializer(
-        user_data_path.Append(chrome::kLocalStateFilename));
-    CHECK(serializer.Serialize(*local_state));
-  }
-
-  const std::string GetTestAppUserId() const {
-    return policy::GenerateDeviceLocalAccountUserId(
-        kTestAccountId, policy::DeviceLocalAccount::TYPE_KIOSK_APP);
-  }
-
-  bool CloseAppWindow(const std::string& app_id) {
-    Profile* const app_profile = ProfileManager::GetPrimaryUserProfile();
-    if (!app_profile) {
-      ADD_FAILURE() << "No primary (app) profile.";
-      return false;
-    }
-
-    extensions::AppWindowRegistry* const app_window_registry =
-        extensions::AppWindowRegistry::Get(app_profile);
-    extensions::AppWindow* const window =
-        apps::AppWindowWaiter(app_window_registry, app_id).Wait();
-    if (!window) {
-      ADD_FAILURE() << "No app window found for " << app_id << ".";
-      return false;
-    }
-
-    window->GetBaseWindow()->Close();
-
-    // Wait until the app terminates if it is still running.
-    if (!app_window_registry->GetAppWindowsForApp(app_id).empty())
-      base::RunLoop().Run();
-    return true;
-  }
-
-  bool IsKioskAppAutoLaunched(const std::string& app_id) {
-    KioskAppManager::App app;
-    if (!KioskAppManager::Get()->GetApp(app_id, &app)) {
-      ADD_FAILURE() << "App " << app_id << " not found.";
-      return false;
-    }
-    return app.was_auto_launched_with_zero_delay;
-  }
-
-  void ExpectCommandLineHasDefaultPolicySwitches(
-      const base::CommandLine& cmd_line) {
-    for (size_t i = 0u; i < arraysize(kDefaultPolicySwitches); ++i) {
-      EXPECT_TRUE(cmd_line.HasSwitch(kDefaultPolicySwitches[i].name))
-          << "Missing flag " << kDefaultPolicySwitches[i].name;
-      EXPECT_EQ(kDefaultPolicySwitches[i].value,
-                cmd_line.GetSwitchValueASCII(kDefaultPolicySwitches[i].name))
-          << "Invalid value for switch " << kDefaultPolicySwitches[i].name;
-    }
-  }
-
- protected:
-  std::unique_ptr<TerminationObserver> termination_observer_;
-
- private:
-  chromeos::ScopedStubInstallAttributes install_attributes_;
-  policy::DevicePolicyBuilder device_policy_;
-  scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util_;
-  std::unique_ptr<PersistentSessionManagerClient> fake_session_manager_;
-  std::unique_ptr<FakeCWS> fake_cws_;
-
-  DISALLOW_COPY_AND_ASSIGN(AutoLaunchedKioskTest);
-};
-
-IN_PROC_BROWSER_TEST_F(AutoLaunchedKioskTest, PRE_CrashRestore) {
-  // Verify that Chrome hasn't already exited, e.g. in order to apply user
-  // session flags.
-  ASSERT_FALSE(termination_observer_->terminated());
-
-  // Set up default network connections, so tests think the device is online.
-  DBusThreadManager::Get()
-      ->GetShillManagerClient()
-      ->GetTestInterface()
-      ->SetupDefaultEnvironment();
-
-  // Check that policy flags have not been lost.
-  ExpectCommandLineHasDefaultPolicySwitches(
-      *base::CommandLine::ForCurrentProcess());
-
-  ExtensionTestMessageListener listener("appWindowLoaded", false);
-  EXPECT_TRUE(listener.WaitUntilSatisfied());
-
-  EXPECT_TRUE(IsKioskAppAutoLaunched(kTestKioskApp));
-
-  ASSERT_TRUE(CloseAppWindow(kTestKioskApp));
-}
-
-IN_PROC_BROWSER_TEST_F(AutoLaunchedKioskTest, CrashRestore) {
-  // Verify that Chrome hasn't already exited, e.g. in order to apply user
-  // session flags.
-  ASSERT_FALSE(termination_observer_->terminated());
-
-  ExpectCommandLineHasDefaultPolicySwitches(
-      *base::CommandLine::ForCurrentProcess());
-
-  ExtensionTestMessageListener listener("appWindowLoaded", false);
-  EXPECT_TRUE(listener.WaitUntilSatisfied());
-
-  EXPECT_TRUE(IsKioskAppAutoLaunched(kTestKioskApp));
-
-  ASSERT_TRUE(CloseAppWindow(kTestKioskApp));
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 145a9ee..fe16fe3 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -581,18 +581,14 @@
   // type has be set before kiosk app controller takes over, as at that point
   // kiosk app profile would already be initialized - feature session type
   // should be set before that.
+  // TODO(tbarzic): Note that this does not work well for auto-launched
+  //     sessions, as information about whether session was auto-launched is not
+  //     persisted over session restart - http://crbug.com/677340.
   if (user->GetType() == user_manager::USER_TYPE_KIOSK_APP) {
     if (base::CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kLoginUser)) {
-      // For kiosk session crash recovery, feature session type has be set
-      // before kiosk app controller takes over, as at that point iosk app
-      // profile would already be initialized - feature session type
-      // should be set before that.
-      bool auto_launched = base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kAppAutoLaunched);
       extensions::SetCurrentFeatureSessionType(
-          auto_launched ? extensions::FeatureSessionType::AUTOLAUNCHED_KIOSK
-                        : extensions::FeatureSessionType::KIOSK);
+          extensions::FeatureSessionType::KIOSK);
     }
     return;
   }
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index f785b60..a3f7408 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -30,7 +30,6 @@
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
-#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_app_launcher.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "chrome/browser/chromeos/login/signin/auth_sync_observer.h"
@@ -860,13 +859,6 @@
   // Disable window animation since kiosk app runs in a single full screen
   // window and window animation causes start-up janks.
   command_line->AppendSwitch(wm::switches::kWindowAnimationsDisabled);
-
-  // If restoring auto-launched kiosk session, make sure the app is marked
-  // as auto-launched.
-  if (command_line->HasSwitch(switches::kLoginUser) &&
-      command_line->HasSwitch(switches::kAppAutoLaunched)) {
-    KioskAppManager::Get()->SetAppWasAutoLaunchedWithZeroDelay(kiosk_app_id);
-  }
 }
 
 void ChromeUserManagerImpl::ArcKioskAppLoggedIn(user_manager::User* user) {
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index b4ad845..cbc4ded 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -339,6 +339,9 @@
            GetLocalState()->GetBoolean(prefs::kOobeMdMode))
     SetShowMdOobe(true);
 
+  // Disable md oobe by default in m57.
+  SetShowMdOobe(false);
+
   // TODO(drcrash): Remove this after testing (http://crbug.com/647411).
   if (IsRemoraPairingOobe() || IsSharkRequisition() || IsRemoraRequisition()) {
     SetShowMdOobe(false);
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc
index 31896bc6..b4852c6 100644
--- a/chrome/browser/media/encrypted_media_browsertest.cc
+++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -60,6 +60,8 @@
     "org.chromium.externalclearkey.platformverificationtest";
 const char kExternalClearKeyCrashKeySystem[] =
     "org.chromium.externalclearkey.crash";
+const char kExternalClearKeyVerifyCdmHostTestKeySystem[] =
+    "org.chromium.externalclearkey.verifycdmhosttest";
 
 // Supported media types.
 const char kWebMVorbisAudioOnly[] = "audio/webm; codecs=\"vorbis\"";
@@ -274,6 +276,8 @@
       RegisterPepperCdm(command_line, kClearKeyCdmBaseDirectory,
                         kClearKeyCdmAdapterFileName, kClearKeyCdmDisplayName,
                         kClearKeyCdmPepperMimeType);
+      // Need to tell CdmHostFile(s) to ignore missing CDM host files in tests.
+      command_line->AppendSwitch(switches::kIgnoreMissingCdmHostFile);
       command_line->AppendSwitchASCII(switches::kEnableFeatures,
                                       media::kExternalClearKeyForTesting.name);
     }
@@ -673,4 +677,9 @@
                    kEmeSessionNotFound);
 }
 
+IN_PROC_BROWSER_TEST_F(ECKEncryptedMediaTest, VerifyCdmHostTest) {
+  TestNonPlaybackCases(kExternalClearKeyVerifyCdmHostTestKeySystem,
+                       kUnitTestSuccess);
+}
+
 #endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index f8dd499f..bb1ca3f 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -401,6 +401,9 @@
   { key::kForceEphemeralProfiles,
     prefs::kForceEphemeralProfiles,
     base::Value::Type::BOOLEAN },
+  { key::kDHEEnabled,
+    ssl_config::prefs::kDHEEnabled,
+    base::Value::Type::BOOLEAN },
   { key::kNTPContentSuggestionsEnabled,
     ntp_snippets::prefs::kEnableSnippets,
     base::Value::Type::BOOLEAN },
diff --git a/chrome/browser/resources/md_downloads/item.html b/chrome/browser/resources/md_downloads/item.html
index d1b4ec0..98d711f 100644
--- a/chrome/browser/resources/md_downloads/item.html
+++ b/chrome/browser/resources/md_downloads/item.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
@@ -14,7 +15,7 @@
 
 <dom-module id="downloads-item">
   <template>
-    <style>
+    <style include="action-link">
       :host {
         display: flex;
         flex-direction: column;
@@ -316,6 +317,5 @@
     </div>
 
   </template>
-  <link rel="import" type="css" href="chrome://resources/css/action_link.css">
   <script src="chrome://downloads/item.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
index 29a6ca68..66db1a9 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -587,7 +587,7 @@
    * @return {boolean}
    * @private
    */
-  dialogIsVisible_(dialogId, dialogToShow) {
+  dialogIsVisible_: function(dialogId, dialogToShow) {
     return dialogToShow == dialogId;
   },
 
diff --git a/chrome/browser/resources/settings/device_page/device_page.js b/chrome/browser/resources/settings/device_page/device_page.js
index 5ec0105a..b3bb4acc 100644
--- a/chrome/browser/resources/settings/device_page/device_page.js
+++ b/chrome/browser/resources/settings/device_page/device_page.js
@@ -219,7 +219,7 @@
    * @return {string} Description of the power source.
    * @private
    */
-  computePowerSourceName_(powerSources, lowPowerCharger) {
+  computePowerSourceName_: function (powerSources, lowPowerCharger) {
     if (lowPowerCharger)
       return this.i18n('powerSourceLowPowerCharger');
     if (powerSources.length)
diff --git a/chrome/browser/resources/settings/device_page/display.js b/chrome/browser/resources/settings/device_page/display.js
index 31e25c8..1a9a8c9 100644
--- a/chrome/browser/resources/settings/device_page/display.js
+++ b/chrome/browser/resources/settings/device_page/display.js
@@ -118,7 +118,7 @@
    * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays
    * @private
    */
-  displayInfoFetched_(displays) {
+  displayInfoFetched_: function(displays) {
     if (!displays.length)
       return;
     settings.display.systemDisplayApi.getDisplayLayout(
@@ -130,7 +130,7 @@
    * @param {!Array<!chrome.system.display.DisplayLayout>} layouts
    * @private
    */
-  displayLayoutFetched_(displays, layouts) {
+  displayLayoutFetched_: function(displays, layouts) {
     this.layouts = layouts;
     this.displays = displays;
     this.updateDisplayInfo_();
diff --git a/chrome/browser/resources/settings/device_page/stylus.html b/chrome/browser/resources/settings/device_page/stylus.html
index 2d4a473..f6620b6 100644
--- a/chrome/browser/resources/settings/device_page/stylus.html
+++ b/chrome/browser/resources/settings/device_page/stylus.html
@@ -22,11 +22,13 @@
       </settings-toggle-button>
     </div>
 
+    <!-- TODO(scottchen): Make a proper a[href].settings-box with
+         icon-external (see: https://crbug.com/684005)-->
     <div class="settings-box">
       <!-- TODO(jdufault): This should launch an intent (using the
         enable-intent-picker flag) that opens up the play store to a curated
         list of apps. -->
-      <a is="action-link" target="_blank"
+      <a target="_blank"
          href="https://play.google.com/store/apps/collection/promotion_30023cb_stylus_apps">
         $i18n{stylusFindMoreApps}
       </a>
diff --git a/chrome/browser/resources/settings/internet_page/internet_page.js b/chrome/browser/resources/settings/internet_page/internet_page.js
index cd63a51..342bab9 100644
--- a/chrome/browser/resources/settings/internet_page/internet_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_page.js
@@ -236,7 +236,7 @@
    * @param {!chrome.networkingPrivate.GlobalPolicy} globalPolicy
    * @return {boolean}
    */
-  allowAddConnection_(globalPolicy) {
+  allowAddConnection_: function(globalPolicy) {
     return !globalPolicy.AllowOnlyPolicyNetworksToConnect;
   },
 
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 40c730e..6940b89 100644
--- a/chrome/browser/resources/settings/internet_page/network_summary_item.html
+++ b/chrome/browser/resources/settings/internet_page/network_summary_item.html
@@ -1,6 +1,8 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
 <link rel="import" href="chrome://resources/cr_elements/network/cr_network_list.html">
 <link rel="import" href="chrome://resources/cr_elements/network/cr_network_list_item.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
@@ -13,7 +15,7 @@
 
 <dom-module name="network-summary-item">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       paper-spinner {
         @apply(--cr-icon-height-width);
         margin: 0 var(--settings-box-row-padding);
@@ -23,12 +25,6 @@
         padding: 0 var(--settings-box-row-padding);
       }
 
-      .button-row {
-        align-items: center;
-        display: flex;
-        min-height: var(--settings-row-min-height);
-      }
-
       .padded {
         @apply(--settings-list-frame-padding);
       }
@@ -109,8 +105,11 @@
           </cr-network-list>
           <template is="dom-if"
               if="[[knownNetworksIsVisible_(activeNetworkState)]]">
-            <div class="button-row" actionable on-tap="onKnownNetworksTap_">
-              <a is="action-link">$i18n{knownNetworksButton}</a>
+            <div class="list-item">
+              <a is="action-link" class="list-button"
+                  on-tap="onKnownNetworksTap_">
+                $i18n{knownNetworksButton}
+              </a>
             </div>
           </template>
         </div>
diff --git a/chrome/browser/resources/settings/languages_page/languages_page.html b/chrome/browser/resources/settings/languages_page/languages_page.html
index 8684f16..00635ba 100644
--- a/chrome/browser/resources/settings/languages_page/languages_page.html
+++ b/chrome/browser/resources/settings/languages_page/languages_page.html
@@ -1,4 +1,5 @@
 <link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/assert.html">
 <link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
@@ -29,7 +30,7 @@
 
 <dom-module id="settings-languages-page">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       #languagesCollapse .list-item.selected {
         min-height: var(--settings-row-two-line-min-height);
       }
@@ -125,8 +126,11 @@
                 </paper-icon-button>
               </div>
             </template>
-            <div class="list-item list-button" on-tap="onAddLanguagesTap_">
-              <a is="action-link">$i18n{addLanguages}</a>
+            <div class="list-item">
+              <a is="action-link" class="list-button"
+                  on-tap="onAddLanguagesTap_">
+                $i18n{addLanguages}
+              </a>
             </div>
           </div>
         </iron-collapse>
@@ -167,9 +171,11 @@
                 </paper-icon-button>
               </div>
             </template>
-            <div class="list-item list-button"
-                on-tap="onManageInputMethodsTap_">
-              <a is="action-link">$i18n{manageInputMethods}</a>
+            <div class="list-item">
+              <a is="action-link" class="list-button"
+                  on-tap="onManageInputMethodsTap_">
+                $i18n{manageInputMethods}
+              </a>
             </div>
           </div>
         </iron-collapse>
@@ -199,8 +205,11 @@
                 </paper-checkbox>
               </label>
             </template>
-            <div class="list-item list-button" on-tap="onEditDictionaryTap_">
-              <a is="action-link">$i18n{manageSpellCheck}</a>
+            <div class="list-item">
+              <a is="action-link" class="list-button"
+                  on-tap="onEditDictionaryTap_">
+                $i18n{manageSpellCheck}
+              </a>
             </div>
           </div>
         </iron-collapse>
diff --git a/chrome/browser/resources/settings/languages_page/manage_input_methods_page.js b/chrome/browser/resources/settings/languages_page/manage_input_methods_page.js
index ad3690d96..92d1223 100644
--- a/chrome/browser/resources/settings/languages_page/manage_input_methods_page.js
+++ b/chrome/browser/resources/settings/languages_page/manage_input_methods_page.js
@@ -144,8 +144,8 @@
         language: displayLanguage,
         inputMethods: combinedInputMethods,
       });
-      for (var languageCode of languageFamilyCodes)
-        usedLanguages.add(languageCode);
+      for (var k = 0; k < languageFamilyCodes.length; k++)
+        usedLanguages.add(languageFamilyCodes[k]);
     }
 
     this.languageList_ = languageList;
@@ -163,9 +163,9 @@
     var /** !Set<string> */ usedInputMethods = new Set();
     /** @type {!Array<chrome.languageSettingsPrivate.InputMethod>} */
     var combinedInputMethods = [];
-    for (var languageCode of languageCodes) {
+    for (var i = 0; i < languageCodes.length; i++) {
       var inputMethods = this.languageHelper.getInputMethodsForLanguage(
-          languageCode);
+          languageCodes[i]);
       // Get the language's unused input methods and mark them as used.
       var newInputMethods = inputMethods.filter(function(inputMethod) {
         if (usedInputMethods.has(inputMethod.id))
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
index 8a4a1bf14..2627254 100644
--- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
+++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
@@ -1,4 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
@@ -11,7 +13,7 @@
 
 <dom-module id="settings-startup-urls-page">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       #outer {
         @apply(--settings-list-frame-padding);
         max-height: 395px;  /** Enough height to show six entries. */
@@ -39,11 +41,17 @@
       </div>
       <template is="dom-if" if="[[!prefs.session.startup_urls.controlledBy]]"
           restamp>
-        <div class="list-item list-button" id="addPage" on-tap="onAddPageTap_">
-          $i18n{onStartupAddNewPage}
+        <div class="list-item" id="addPage">
+          <a is="action-link" class="list-button" on-tap="onAddPageTap_">
+            $i18n{onStartupAddNewPage}
+          </a>
         </div>
-        <div class="list-item list-button" id="useCurrentPages"
-            on-tap="onUseCurrentPagesTap_">$i18n{onStartupUseCurrent}</div>
+        <div class="list-item" id="useCurrentPages">
+          <a is="action-link" class="list-button"
+              on-tap="onUseCurrentPagesTap_">
+            $i18n{onStartupUseCurrent}
+          </a>
+        </div>
       </template>
       <template is="dom-if" if="[[prefs.session.startup_urls.extensionId]]"
           restamp>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
index c11eec9..275186eb 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
 <link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="/i18n_setup.html">
@@ -9,9 +10,8 @@
 <link rel="import" href="/settings_shared_css.html">
 
 <dom-module id="settings-autofill-section">
-  <link rel="import" type="css" href="chrome://resources/css/action_link.css">
   <template>
-    <style include="settings-shared passwords-shared">
+    <style include="settings-shared passwords-shared action-link">
       .type-column {
         align-items: center;
         flex: 2;
@@ -82,8 +82,10 @@
           hidden$="[[hasSome_(addresses)]]">
         $i18n{noAddressesFound}
       </div>
-      <div class="list-item list-button">
-        <a is="action-link" on-tap="onAddAddressTap_">$i18n{addAddress}</a>
+      <div class="list-item">
+        <a is="action-link" class="list-button" on-tap="onAddAddressTap_">
+          $i18n{addAddress}
+        </a>
       </div>
     </div>
     <dialog is="cr-action-menu" id="addressSharedMenu">
@@ -136,8 +138,8 @@
           hidden$="[[hasSome_(creditCards)]]">
         $i18n{noCreditCardsFound}
       </div>
-      <div class="list-item list-button">
-        <a is="action-link" on-tap="onAddCreditCardTap_">
+      <div class="list-item">
+        <a is="action-link" class="list-button" on-tap="onAddCreditCardTap_">
           $i18n{addCreditCard}
         </a>
       </div>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
index 7c9cfe4..befa6ed 100644
--- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
+++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -12,8 +12,6 @@
 <link rel="import" href="/settings_shared_css.html">
 
 <dom-module id="passwords-section">
-  <!-- action_link.css is needed for the |managePasswordsLabel| link -->
-  <link rel="import" type="css" href="chrome://resources/css/action_link.css">
   <template>
     <style include="settings-shared passwords-shared">
       #password {
diff --git a/chrome/browser/resources/settings/people_page/camera.js b/chrome/browser/resources/settings/people_page/camera.js
index e31a25d..ce25918 100644
--- a/chrome/browser/resources/settings/people_page/camera.js
+++ b/chrome/browser/resources/settings/people_page/camera.js
@@ -141,8 +141,8 @@
    */
   stopVideoTracks_: function(stream) {
     var tracks = stream.getVideoTracks();
-    for (var t of tracks)
-      t.stop();
+    for (var i = 0; i < tracks.length; i++)
+      tracks[i].stop();
   },
 
   /**
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index cf290e9..017c2b7 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -1,6 +1,7 @@
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
 <link rel="import" href="/controls/settings_toggle_button.html">
 <link rel="import" href="/people_page/lock_screen_constants.html">
@@ -13,14 +14,10 @@
 
 <dom-module id="settings-lock-screen">
   <template>
-    <style include="settings-shared"></style>
+    <style include="settings-shared action-link"></style>
     <style>
       .radio-indent {
-        margin-left: 28px;
-      }
-
-      paper-button {
-        text-transform: none;
+        margin-left: 36px;
       }
     </style>
 
@@ -33,15 +30,13 @@
           <paper-radio-button name="pin+password">
             $i18n{lockScreenPinOrPassword}
           </paper-radio-button>
-          <div class="settings-box continuation radio-indent"
-              hidden$="[[!showConfigurePinButton_(selectedUnlockType)]]">
-            <!-- TODO(dbeam): I seriously doubt paper-button[is=action-link] is
-                 a good idea. -->
-            <paper-button is="action-link" on-tap="onConfigurePin_">
-              [[getSetupPinText_(hasPin)]]
-            </paper-button>
-          </div>
         </paper-radio-group>
+        <div class="list-item radio-indent"
+            hidden$="[[!showConfigurePinButton_(selectedUnlockType)]]">
+          <a is="action-link" class="list-button" on-tap="onConfigurePin_">
+            [[getSetupPinText_(hasPin)]]
+          </a>
+        </div>
       </div>
 
       <div class="settings-box">
diff --git a/chrome/browser/resources/settings/people_page/users_page.html b/chrome/browser/resources/settings/people_page/users_page.html
index f0ddb52..36686f1 100644
--- a/chrome/browser/resources/settings/people_page/users_page.html
+++ b/chrome/browser/resources/settings/people_page/users_page.html
@@ -1,3 +1,5 @@
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
@@ -8,7 +10,7 @@
 
 <dom-module id="settings-users-page">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       .users {
         /* The users box must line up with the checkbox text. */
         -webkit-margin-start: var(--settings-indent-width);
@@ -59,11 +61,12 @@
             disabled="[[isEditingUsersDisabled_(isOwner_, isWhitelistManaged_,
                 prefs.cros.accounts.allowGuest.value)]]">
         </settings-user-list>
-        <div id="add-user-button" class="list-item list-button"
-            on-tap="openAddUserDialog_"
+        <div id="add-user-button" class="list-item"
             hidden="[[isEditingUsersDisabled_(isOwner_, isWhitelistManaged_,
                 prefs.cros.accounts.allowGuest.value)]]">
-          $i18n{addUsers}
+          <a is="action-link" class="list-button" on-tap="openAddUserDialog_">
+            $i18n{addUsers}
+          </a>
         </div>
       </div>
     </div>
diff --git a/chrome/browser/resources/settings/printing_page/cups_printers.html b/chrome/browser/resources/settings/printing_page/cups_printers.html
index be8dfb4..677f48c9 100644
--- a/chrome/browser/resources/settings/printing_page/cups_printers.html
+++ b/chrome/browser/resources/settings/printing_page/cups_printers.html
@@ -1,3 +1,5 @@
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="/printing_page/cups_add_printer_dialog.html">
 <link rel="import" href="/printing_page/cups_printers_list.html">
@@ -5,17 +7,7 @@
 
 <dom-module id="settings-cups-printers">
   <template>
-    <style include="settings-shared">
-      a[is='action-link'] {
-        display: inline-block;
-        text-decoration: none;
-      }
-
-      a[is='action-link']:hover {
-        color: blue;
-        text-decoration: underline;
-      }
-
+    <style include="settings-shared action-link">
       .settings-box .start {
         color: var(--paper-grey-500);
       }
@@ -54,7 +46,7 @@
     </style>
 
     <div class="settings-box first">
-      <a is="action-link" on-tap="onAddPrinterTap_" actionable
+      <a is="action-link" on-tap="onAddPrinterTap_"
           hidden="[[!canAddPrinter_]]">
         $i18n{addCupsPrinter}
       </a>
@@ -79,7 +71,7 @@
       </div>
       <div class="center" id="addPrinterErrorMessage" hidden>
         <span>$i18n{printerAddedFailedMessage}</span>
-        <a is="action-link" on-tap="onAddPrinterTap_" actionable>
+        <a is="action-link" on-tap="onAddPrinterTap_">
           $i18n{printerAddedTryAgainMessage}
         </a>
       </div>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html
index c9a7031..f0f28d98 100644
--- a/chrome/browser/resources/settings/privacy_page/privacy_page.html
+++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -352,7 +352,10 @@
 <if expr="chromeos">
           <div actionable class="settings-box"
               on-tap="onAdobeFlashStorageClicked_">
-            <div class="list-item list-button">$i18n{adobeFlashStorage}</div>
+            <div class="start">
+              $i18n{adobeFlashStorage}
+            </div>
+            <button class="icon-external" is="paper-icon-button-light"></button>
           </div>
 </if>
           <category-setting-exceptions
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
index e5cb1c0..1dfd9a4 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
@@ -1,5 +1,6 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
@@ -10,9 +11,8 @@
 <link rel="import" href="/settings_shared_css.html">
 
 <dom-module id="settings-reset-profile-dialog">
-  <link rel="import" type="css" href="chrome://resources/css/action_link.css">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       .footer a {
         vertical-align: middle;
       }
diff --git a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
index 35a512f..bae938a 100644
--- a/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
+++ b/chrome/browser/resources/settings/search_engines_page/search_engines_page.html
@@ -1,6 +1,7 @@
-<link rel="import" href="chrome://resources/html/action_link.html">
-<link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
+<link rel="import" href="chrome://resources/html/cr.html">
 <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="/search_engines_page/search_engines_browser_proxy.html">
 <link rel="import" href="/search_engines_page/search_engine_dialog.html">
@@ -9,9 +10,8 @@
 <link rel="import" href="/settings_shared_css.html">
 
 <dom-module id="settings-search-engines-page">
-  <link rel="import" type="css" href="chrome://resources/css/action_link.css">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       .extension-engines {
         @apply(--settings-list-frame-padding);
       }
@@ -35,12 +35,12 @@
     <div class="settings-box first">
       <h2>$i18n{searchEnginesOther}</h2>
     </div>
-    <!-- TODO(dbeam): why does on-click work with keyboard but on-tap
-         doesn't? -->
     <settings-search-engines-list engines="[[otherEngines]]">
-      <a class="list-item list-button" is="action-link"
-          on-tap="onAddSearchEngineTap_" id="addSearchEngine">
-          $i18n{searchEnginesAddSearchEngine}</a>
+      <div class="list-item" id="addSearchEngine">
+        <a is="action-link" class="list-button" on-tap="onAddSearchEngineTap_">
+          $i18n{searchEnginesAddSearchEngine}
+        </a>
+      </div>
     </settings-search-engines-list>
 
     <template is="dom-if" if="[[showExtensionsList_]]">
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index 9526560..22646f8 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -78,10 +78,6 @@
         -webkit-margin-start: 4px;
       }
 
-      [is='action-link'],
-      [is='action-link']:active,
-      [is='action-link']:hover,
-      [is='action-link']:visited,
       .primary-button,
       .tertiary-button,
       a[href] {
@@ -95,8 +91,7 @@
         };
       }
 
-      a[href],
-      [is='action-link']:hover {
+      a[href] {
         text-decoration: none;
       }
 
@@ -232,10 +227,11 @@
       }
 
       /* This button has no ink ripple. */
-      .list-item.list-button {
-        @apply(--settings-actionable);
+      .list-button[is='action-link'] {
+        min-height: inherit;
+        display: flex;
         align-items: center;
-        color: var(--google-blue-500);
+        flex: 1;
         font-weight: 500;
       }
 
diff --git a/chrome/browser/resources/settings/site_settings/site_details.html b/chrome/browser/resources/settings/site_settings/site_details.html
index 0898ee3..767d5e3b 100644
--- a/chrome/browser/resources/settings/site_settings/site_details.html
+++ b/chrome/browser/resources/settings/site_settings/site_details.html
@@ -1,4 +1,6 @@
 <link rel="import" href="chrome://resources/html/polymer.html">
+<link rel="import" href="chrome://resources/html/action_link.html">
+<link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html">
@@ -12,7 +14,7 @@
 
 <dom-module id="site-details">
   <template>
-    <style include="settings-shared">
+    <style include="settings-shared action-link">
       .favicon-image {
         margin: 2px;
       }
@@ -108,8 +110,10 @@
           label="$i18n{siteSettingsUnsandboxedPlugins}" site="[[site]]">
       </site-details-permission>
 
-      <div on-tap="onClearAndReset_" raised class="list-item list-button">
-        $i18n{siteSettingsClearAndReset}
+      <div class="list-item">
+        <a is="action-link" class="list-button" on-tap="onClearAndReset_" >
+          $i18n{siteSettingsClearAndReset}
+        </a>
       </div>
     </div>
     <website-usage-private-api id="usageApi"
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 3a31875..4e8f3cbd 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -575,7 +575,7 @@
     "//device/usb",
     "//extensions/features",
     "//media",
-    "//net:net_with_v8",
+    "//net:net",
     "//ppapi/features",
     "//printing/features",
     "//rlz/features",
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index acc2361..fb23d30 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -530,6 +530,14 @@
       "//sandbox/linux:sandbox_services",
     ]
   }
+
+  if (enable_pepper_cdms) {
+    sources += [
+      "media/cdm_host_file_path.cc",
+      "media/cdm_host_file_path.h",
+    ]
+    public_deps += [ "//chrome/common:version_header" ]
+  }
 }
 
 process_version("version_header") {
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 29930ce..d480ff03 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -116,6 +116,8 @@
 #if defined(OS_MACOSX)
 const base::FilePath::CharType kFrameworkName[] =
     FPL(PRODUCT_STRING " Framework.framework");
+const base::FilePath::CharType kFrameworkExecutableName[] =
+    FPL(PRODUCT_STRING " Framework");
 #endif  // OS_MACOSX
 
 #if defined(OS_WIN)
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 53a3b71..d738b8e 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -29,6 +29,7 @@
 // TODO(tfarina): Remove the comment above, when you fix components to use plist
 // on Mac.
 extern const base::FilePath::CharType kFrameworkName[];
+extern const base::FilePath::CharType kFrameworkExecutableName[];
 #endif  // OS_MACOSX
 #if defined(OS_WIN)
 extern const base::FilePath::CharType kBrowserResourcesDll[];
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 2e67b3b..be0eb7e6 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -86,6 +86,10 @@
 #include "chrome/common/widevine_cdm_constants.h"
 #endif
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#include "chrome/common/media/cdm_host_file_path.h"
+#endif
+
 #if defined(OS_ANDROID)
 #include "chrome/common/chrome_media_client_android.h"
 #endif
@@ -540,26 +544,35 @@
 }
 
 void ChromeContentClient::AddContentDecryptionModules(
-    std::vector<content::CdmInfo>* cdms) {
+    std::vector<content::CdmInfo>* cdms,
+    std::vector<content::CdmHostFilePath>* cdm_host_file_paths) {
+  if (cdms) {
 // TODO(jrummell): Need to have a better flag to indicate systems Widevine
 // is available on. For now we continue to use ENABLE_PEPPER_CDMS so that
 // we can experiment between pepper and mojo.
 #if defined(WIDEVINE_CDM_AVAILABLE_NOT_COMPONENT)
-  base::FilePath adapter_path;
-  base::FilePath cdm_path;
-  std::vector<std::string> codecs_supported;
-  if (IsWidevineAvailable(&adapter_path, &cdm_path, &codecs_supported)) {
-    // CdmInfo needs |path| to be the actual Widevine library,
-    // not the adapter, so adjust as necessary. It will be in the
-    // same directory as the installed adapter.
-    const base::Version version(WIDEVINE_CDM_VERSION_STRING);
-    DCHECK(version.IsValid());
-    cdms->push_back(content::CdmInfo(kWidevineCdmType, version, cdm_path,
-                                     codecs_supported));
-  }
+    base::FilePath adapter_path;
+    base::FilePath cdm_path;
+    std::vector<std::string> codecs_supported;
+    if (IsWidevineAvailable(&adapter_path, &cdm_path, &codecs_supported)) {
+      // CdmInfo needs |path| to be the actual Widevine library,
+      // not the adapter, so adjust as necessary. It will be in the
+      // same directory as the installed adapter.
+      const base::Version version(WIDEVINE_CDM_VERSION_STRING);
+      DCHECK(version.IsValid());
+      cdms->push_back(content::CdmInfo(kWidevineCdmType, version, cdm_path,
+                                       codecs_supported));
+    }
 #endif  // defined(WIDEVINE_CDM_AVAILABLE_NOT_COMPONENT)
 
-  // TODO(jrummell): Add External Clear Key CDM for testing, if it's available.
+    // TODO(jrummell): Add External Clear Key CDM for testing, if it's
+    // available.
+  }
+
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+  if (cdm_host_file_paths)
+    chrome::AddCdmHostFilePaths(cdm_host_file_paths);
+#endif
 }
 
 static const char* const kChromeStandardURLSchemes[] = {
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h
index 15f2628a..2eff7f7 100644
--- a/chrome/common/chrome_content_client.h
+++ b/chrome/common/chrome_content_client.h
@@ -73,7 +73,9 @@
   void AddPepperPlugins(
       std::vector<content::PepperPluginInfo>* plugins) override;
   void AddContentDecryptionModules(
-      std::vector<content::CdmInfo>* cdms) override;
+      std::vector<content::CdmInfo>* cdms,
+      std::vector<content::CdmHostFilePath>* cdm_host_file_paths) override;
+
   void AddAdditionalSchemes(Schemes* schemes) override;
   std::string GetProduct() const override;
   std::string GetUserAgent() const override;
diff --git a/chrome/common/media/cdm_host_file_path.cc b/chrome/common/media/cdm_host_file_path.cc
new file mode 100644
index 0000000..421f4db
--- /dev/null
+++ b/chrome/common/media/cdm_host_file_path.cc
@@ -0,0 +1,103 @@
+// 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 "chrome/common/media/cdm_host_file_path.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/path_service.h"
+#include "build/build_config.h"
+#include "chrome/common/chrome_version.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/bundle_locations.h"
+#include "chrome/common/chrome_constants.h"
+#endif
+
+namespace chrome {
+
+namespace {
+
+using content::CdmHostFilePath;
+
+// TODO(xhwang): Move this to a common place if needed.
+const base::FilePath::CharType kSignatureFileExtension[] =
+    FILE_PATH_LITERAL(".sig");
+
+// Returns the signature file path given the |file_path|. This function should
+// only be used when the signature file and the file are located in the same
+// directory.
+base::FilePath GetSigFilePath(const base::FilePath& file_path) {
+  return file_path.AddExtension(kSignatureFileExtension);
+}
+
+}  // namespace
+
+void AddCdmHostFilePaths(
+    std::vector<content::CdmHostFilePath>* cdm_host_file_paths) {
+  DVLOG(1) << __func__;
+  DCHECK(cdm_host_file_paths);
+  DCHECK(cdm_host_file_paths->empty());
+
+#if defined(OS_WIN)
+
+  static const base::FilePath::CharType* const kUnversionedFiles[] = {
+      FILE_PATH_LITERAL("chrome.exe")};
+  static const base::FilePath::CharType* const kVersionedFiles[] = {
+      FILE_PATH_LITERAL("chrome.dll"), FILE_PATH_LITERAL("chrome_child.dll")};
+
+  // Find where chrome.exe is installed.
+  base::FilePath chrome_exe_dir;
+  if (!PathService::Get(base::DIR_EXE, &chrome_exe_dir))
+    NOTREACHED();
+
+  cdm_host_file_paths->reserve(arraysize(kUnversionedFiles) +
+                               arraysize(kVersionedFiles));
+
+  for (size_t i = 0; i < arraysize(kUnversionedFiles); ++i) {
+    base::FilePath file_path = chrome_exe_dir.Append(kUnversionedFiles[i]);
+    DVLOG(2) << __func__ << ": unversioned file " << i << " at "
+             << file_path.value();
+    cdm_host_file_paths->push_back(
+        CdmHostFilePath(file_path, GetSigFilePath(file_path)));
+  }
+
+  base::FilePath version_dir(chrome_exe_dir.AppendASCII(CHROME_VERSION_STRING));
+  for (size_t i = 0; i < arraysize(kVersionedFiles); ++i) {
+    base::FilePath file_path = version_dir.Append(kVersionedFiles[i]);
+    DVLOG(2) << __func__ << ": versioned file " << i << " at "
+             << file_path.value();
+    cdm_host_file_paths->push_back(
+        CdmHostFilePath(file_path, GetSigFilePath(file_path)));
+  }
+
+#elif defined(OS_MACOSX)
+
+  base::FilePath chrome_framework_path =
+      base::mac::FrameworkBundlePath().Append(chrome::kFrameworkExecutableName);
+
+  DVLOG(2) << __func__
+           << ": chrome_framework_path=" << chrome_framework_path.value();
+  cdm_host_file_paths->push_back(CdmHostFilePath(
+      chrome_framework_path, GetSigFilePath(chrome_framework_path)));
+
+#elif defined(OS_LINUX)
+
+  base::FilePath chrome_exe_dir;
+  if (!PathService::Get(base::DIR_EXE, &chrome_exe_dir))
+    NOTREACHED();
+
+  base::FilePath chrome_path =
+      chrome_exe_dir.Append(FILE_PATH_LITERAL("chrome"));
+  DVLOG(2) << __func__ << ": chrome_path=" << chrome_path.value();
+  cdm_host_file_paths->push_back(
+      CdmHostFilePath(chrome_path, GetSigFilePath(chrome_path)));
+
+#endif  // defined(OS_WIN)
+}
+
+}  // namespace chrome
diff --git a/chrome/common/media/cdm_host_file_path.h b/chrome/common/media/cdm_host_file_path.h
new file mode 100644
index 0000000..3495536a
--- /dev/null
+++ b/chrome/common/media/cdm_host_file_path.h
@@ -0,0 +1,20 @@
+// 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 CHROME_COMMON_MEDIA_CDM_HOST_FILE_PATH_H_
+#define CHROME_COMMON_MEDIA_CDM_HOST_FILE_PATH_H_
+
+#include <vector>
+
+#include "content/public/common/cdm_info.h"
+
+namespace chrome {
+
+// Gets a list of CDM host file paths and put them in |cdm_host_file_paths|.
+void AddCdmHostFilePaths(
+    std::vector<content::CdmHostFilePath>* cdm_host_file_paths);
+
+}  // namespace chrome
+
+#endif  // CHROME_COMMON_MEDIA_CDM_HOST_FILE_PATH_H_
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 9375555..de68108 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -63,6 +63,8 @@
 // External Clear Key (used for testing).
 static void AddExternalClearKey(
     std::vector<std::unique_ptr<KeySystemProperties>>* concrete_key_systems) {
+  // TODO(xhwang): Move these into an array so we can use a for loop to add
+  // supported key systems below.
   static const char kExternalClearKeyKeySystem[] =
       "org.chromium.externalclearkey";
   static const char kExternalClearKeyDecryptOnlyKeySystem[] =
@@ -79,6 +81,8 @@
       "org.chromium.externalclearkey.initializefail";
   static const char kExternalClearKeyCrashKeySystem[] =
       "org.chromium.externalclearkey.crash";
+  static const char kExternalClearKeyVerifyCdmHostTestKeySystem[] =
+      "org.chromium.externalclearkey.verifycdmhosttest";
 
   std::vector<base::string16> additional_param_names;
   std::vector<base::string16> additional_param_values;
@@ -120,6 +124,10 @@
   // A key system that triggers a crash in ClearKeyCdm.
   concrete_key_systems->emplace_back(
       new cdm::ExternalClearKeyProperties(kExternalClearKeyCrashKeySystem));
+
+  // A key system that triggers the verify host files test in ClearKeyCdm.
+  concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
+      kExternalClearKeyVerifyCdmHostTestKeySystem));
 }
 
 #if defined(WIDEVINE_CDM_AVAILABLE)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index e16115f..7179c43 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2186,6 +2186,7 @@
         "../browser/chromeos/app_mode/arc/arc_kiosk_app_manager_browsertest.cc",
         "../browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc",
         "../browser/chromeos/app_mode/kiosk_app_update_service_browsertest.cc",
+        "../browser/chromeos/app_mode/kiosk_crash_restore_browsertest.cc",
         "../browser/chromeos/arc/arc_session_manager_browsertest.cc",
         "../browser/chromeos/arc/auth/arc_robot_auth_code_fetcher_browsertest.cc",
         "../browser/chromeos/arc/intent_helper/arc_settings_service_browsertest.cc",
@@ -2230,7 +2231,6 @@
         "../browser/chromeos/first_run/goodies_displayer_browsertest.cc",
         "../browser/chromeos/input_method/input_method_engine_browsertests.cc",
         "../browser/chromeos/input_method/mode_indicator_browsertest.cc",
-        "../browser/chromeos/login/auto_launched_kiosk_browsertest.cc",
         "../browser/chromeos/login/bluetooth_host_pairing_browsertest.cc",
         "../browser/chromeos/login/crash_restore_browsertest.cc",
         "../browser/chromeos/login/demo_mode/demo_app_launcher_browsertest.cc",
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index 46150a0..2e1d91b 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -1944,11 +1944,9 @@
   },
 
   "SSLVersionMin": {
-    "note": "This policy is retired, see https://crbug.com/487730."
   },
 
   "SSLVersionFallbackMin": {
-    "note": "This policy is retired, see https://crbug.com/621780."
   },
 
   "CertificateTransparencyEnforcementDisabledForUrls": {
@@ -1960,11 +1958,16 @@
   },
 
   "RC4Enabled": {
-    "note": "This policy is retired, see https://crbug.com/375342."
   },
 
   "DHEEnabled": {
-    "note": "This policy is retired, see https://crbug.com/619194."
+    "os": ["win", "linux", "mac", "chromeos"],
+    "test_policy": { "DHEEnabled": true },
+    "pref_mappings": [
+      { "pref": "ssl.dhe_enabled",
+        "local_state": true
+      }
+    ]
   },
 
   "WelcomePageOnOSUpgradeEnabled": {
diff --git a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
index aad0d078..418edb82 100644
--- a/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/quick_unlock_authenticate_browsertest_chromeos.js
@@ -237,7 +237,7 @@
               getFromElement('paper-radio-button[name="password"]');
           pinPasswordRadioButton =
               getFromElement('paper-radio-button[name="pin+password"]');
-          configureButton = getFromElement('paper-button');
+          configureButton = getFromElement('a[is="action-link"]');
 
           done();
         });
diff --git a/chrome/test/data/webui/settings/search_engines_page_test.js b/chrome/test/data/webui/settings/search_engines_page_test.js
index 6f26ef0..07456114 100644
--- a/chrome/test/data/webui/settings/search_engines_page_test.js
+++ b/chrome/test/data/webui/settings/search_engines_page_test.js
@@ -328,7 +328,7 @@
       // button is tapped.
       test('AddSearchEngineDialog', function() {
         assertFalse(!!page.$$('settings-search-engine-dialog'));
-        var addSearchEngineButton = page.$.addSearchEngine;
+        var addSearchEngineButton = page.$$('#addSearchEngine > a');
         assertTrue(!!addSearchEngineButton);
 
         MockInteractions.tap(addSearchEngineButton);
diff --git a/chrome/test/data/webui/settings/startup_urls_page_test.js b/chrome/test/data/webui/settings/startup_urls_page_test.js
index a0fa115..8028da3 100644
--- a/chrome/test/data/webui/settings/startup_urls_page_test.js
+++ b/chrome/test/data/webui/settings/startup_urls_page_test.js
@@ -216,14 +216,14 @@
     });
 
     test('UseCurrentPages', function() {
-      var useCurrentPagesButton = page.$$('#useCurrentPages');
+      var useCurrentPagesButton = page.$$('#useCurrentPages > a');
       assertTrue(!!useCurrentPagesButton);
       MockInteractions.tap(useCurrentPagesButton);
       return browserProxy.whenCalled('useCurrentPages');
     });
 
     test('AddPage_OpensDialog', function() {
-      var addPageButton = page.$$('#addPage');
+      var addPageButton = page.$$('#addPage > a');
       assertTrue(!!addPageButton);
       assertFalse(!!page.$$('settings-startup-url-dialog'));
 
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 48caceec..9e04b6d 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -55,11 +55,6 @@
 // mode. This can be enabled by this flag.
 const char kAllowRAInDevMode[] = "allow-ra-in-dev-mode";
 
-// Specifies whether an app launched in kiosk mode was auto launched with zero
-// delay. Used in order to properly restore auto-launched state during session
-// restore flow.
-const char kAppAutoLaunched[] = "app-auto-launched";
-
 // Path for app's OEM manifest file.
 const char kAppOemManifestFile[] = "app-mode-oem-manifest";
 
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 86d216a..90e0850 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -27,7 +27,6 @@
 CHROMEOS_EXPORT extern const char kAllowDataRoamingByDefault[];
 CHROMEOS_EXPORT extern const char kAllowFailedPolicyFetchForTest[];
 CHROMEOS_EXPORT extern const char kAllowRAInDevMode[];
-CHROMEOS_EXPORT extern const char kAppAutoLaunched[];
 CHROMEOS_EXPORT extern const char kAppOemManifestFile[];
 CHROMEOS_EXPORT extern const char kArcAvailable[];
 CHROMEOS_EXPORT extern const char kArtifactsDir[];
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index f6bcad3..d4c757a9 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -8199,7 +8199,6 @@
         'dynamic_refresh': True,
         'per_profile': False,
       },
-      'deprecated': True,
       'example_value': 'ssl3',
       'id': 279,
       'caption': '''Minimum SSL version enabled''',
@@ -8301,7 +8300,6 @@
         'dynamic_refresh': True,
         'per_profile': False,
       },
-      'deprecated': True,
       'example_value': False,
       'id': 310,
       'caption': '''Whether RC4 cipher suites in TLS are enabled''',
@@ -8326,7 +8324,6 @@
         'dynamic_refresh': True,
         'per_profile': False,
       },
-      'deprecated': True,
       'example_value': False,
       'id': 334,
       'caption': '''Whether DHE cipher suites in TLS are enabled''',
diff --git a/components/ssl_config/ssl_config_prefs.cc b/components/ssl_config/ssl_config_prefs.cc
index 7a515124..540be23a 100644
--- a/components/ssl_config/ssl_config_prefs.cc
+++ b/components/ssl_config/ssl_config_prefs.cc
@@ -15,6 +15,7 @@
 const char kSSLVersionMin[] = "ssl.version_min";
 const char kSSLVersionMax[] = "ssl.version_max";
 const char kCipherSuiteBlacklist[] = "ssl.cipher_suites.blacklist";
+const char kDHEEnabled[] = "ssl.dhe_enabled";
 
 }  // namespace prefs
 }  // namespace ssl_config
diff --git a/components/ssl_config/ssl_config_prefs.h b/components/ssl_config/ssl_config_prefs.h
index c10ed21..7f19e1e 100644
--- a/components/ssl_config/ssl_config_prefs.h
+++ b/components/ssl_config/ssl_config_prefs.h
@@ -14,6 +14,7 @@
 extern const char kSSLVersionMin[];
 extern const char kSSLVersionMax[];
 extern const char kCipherSuiteBlacklist[];
+extern const char kDHEEnabled[];
 
 }  // namespace prefs
 }  // namespace ssl_config
diff --git a/components/ssl_config/ssl_config_service_manager_pref.cc b/components/ssl_config/ssl_config_service_manager_pref.cc
index 9437237..0dab204 100644
--- a/components/ssl_config/ssl_config_service_manager_pref.cc
+++ b/components/ssl_config/ssl_config_service_manager_pref.cc
@@ -175,6 +175,7 @@
   BooleanPrefMember sha1_local_anchors_enabled_;
   StringPrefMember ssl_version_min_;
   StringPrefMember ssl_version_max_;
+  BooleanPrefMember dhe_enabled_;
 
   // The cached list of disabled SSL cipher suites.
   std::vector<uint16_t> disabled_cipher_suites_;
@@ -215,6 +216,8 @@
                         local_state_callback);
   ssl_version_max_.Init(ssl_config::prefs::kSSLVersionMax, local_state,
                         local_state_callback);
+  dhe_enabled_.Init(ssl_config::prefs::kDHEEnabled, local_state,
+                    local_state_callback);
 
   local_state_change_registrar_.Init(local_state);
   local_state_change_registrar_.Add(ssl_config::prefs::kCipherSuiteBlacklist,
@@ -243,6 +246,8 @@
   registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMax,
                                std::string());
   registry->RegisterListPref(ssl_config::prefs::kCipherSuiteBlacklist);
+  registry->RegisterBooleanPref(ssl_config::prefs::kDHEEnabled,
+                                default_config.dhe_enabled);
 }
 
 net::SSLConfigService* SSLConfigServiceManagerPref::Get() {
@@ -290,6 +295,7 @@
     config->version_max = version_max;
   }
   config->disabled_cipher_suites = disabled_cipher_suites_;
+  config->dhe_enabled = dhe_enabled_.GetValue();
 }
 
 void SSLConfigServiceManagerPref::OnDisabledCipherSuitesChange(
diff --git a/components/translate/core/browser/translate_manager.cc b/components/translate/core/browser/translate_manager.cc
index 1c9183a..33d3c51 100644
--- a/components/translate/core/browser/translate_manager.cc
+++ b/components/translate/core/browser/translate_manager.cc
@@ -4,7 +4,6 @@
 
 #include "components/translate/core/browser/translate_manager.h"
 
-#include <iostream>
 #include <map>
 
 #include "base/bind.h"
@@ -225,14 +224,12 @@
   InitTranslateEvent(language_code, target_lang, *translate_prefs);
 
   // Don't translate similar languages (ex: en-US to en).
-  // Also do not offer to translate between Simplified and Traditional Chinese.
-  if (language_code == target_lang ||
-      (language_code == "zh-CN" && target_lang == "zh-TW") ||
-      (language_code == "zh-TW" && target_lang == "zh-CN")) {
+  if (language_code == target_lang) {
     TranslateBrowserMetrics::ReportInitiationStatus(
         TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES);
     return;
   }
+
   // Nothing to do if either the language Chrome is in or the language of the
   // page is not supported by the translation server.
   if (target_lang.empty() ||
diff --git a/components/translate/core/browser/translate_manager_unittest.cc b/components/translate/core/browser/translate_manager_unittest.cc
index dfe0696..fda38d7 100644
--- a/components/translate/core/browser/translate_manager_unittest.cc
+++ b/components/translate/core/browser/translate_manager_unittest.cc
@@ -307,64 +307,6 @@
       1);
 }
 
-// The test measures that Translate is not triggered for a zh-TW page for a
-// zh-CN user.
-TEST_F(TranslateManagerTest,
-       DontTranslateZhTraditionalPageForZhSimplifiedLocale) {
-  TranslateManager::SetIgnoreMissingKeyForTesting(true);
-  translate_manager_.reset(new translate::TranslateManager(
-      &mock_translate_client_, kAcceptLanguages));
-
-  const char kMetricName[] = "Translate.InitiationStatus.v2";
-  base::HistogramTester histogram_tester;
-
-  const std::string locale = "zh-TW";
-  const std::string page_lang = "zh-CN";
-
-  network_notifier_.SimulateOnline();
-  manager_->set_application_locale(locale);
-  ON_CALL(mock_translate_client_, IsTranslatableURL(_))
-      .WillByDefault(Return(true));
-
-  EXPECT_EQ("zh-TW", translate_manager_->GetTargetLanguage(&translate_prefs_));
-  translate_manager_->GetLanguageState().LanguageDetermined(page_lang, true);
-  translate_manager_->InitiateTranslation(page_lang);
-
-  histogram_tester.ExpectUniqueSample(
-      kMetricName,
-      translate::TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES,
-      1);
-}
-
-// The test measures that Translate is not triggered for a zh-CN page for a
-// zh-TW user.
-TEST_F(TranslateManagerTest,
-       DontTranslateZhSimplifiedPageForZhTraditionalLocale) {
-  TranslateManager::SetIgnoreMissingKeyForTesting(true);
-  translate_manager_.reset(new translate::TranslateManager(
-      &mock_translate_client_, kAcceptLanguages));
-
-  const char kMetricName[] = "Translate.InitiationStatus.v2";
-  base::HistogramTester histogram_tester;
-
-  const std::string locale = "zh-CN";
-  const std::string page_lang = "zh-TW";
-
-  network_notifier_.SimulateOnline();
-  manager_->set_application_locale(locale);
-  ON_CALL(mock_translate_client_, IsTranslatableURL(_))
-      .WillByDefault(Return(true));
-
-  EXPECT_EQ("zh-CN", translate_manager_->GetTargetLanguage(&translate_prefs_));
-  translate_manager_->GetLanguageState().LanguageDetermined(page_lang, true);
-  translate_manager_->InitiateTranslation(page_lang);
-
-  histogram_tester.ExpectUniqueSample(
-      kMetricName,
-      translate::TranslateBrowserMetrics::INITIATION_STATUS_SIMILAR_LANGUAGES,
-      1);
-}
-
 // Utility function to set the threshold params
 void ChangeThresholdInParams(
     const char* initiate_translation_confidence_threshold,
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 0994d24..a48d5b6d 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -112,6 +112,10 @@
 #include "crypto/nss_util.h"
 #endif
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#include "content/common/media/cdm_host_files.h"
+#endif
+
 namespace content {
 extern int GpuMain(const content::MainFunctionParams&);
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -334,6 +338,15 @@
       command_line.GetSwitchValueASCII(switches::kProcessType);
   ContentClientInitializer::Set(process_type, delegate);
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+  if (process_type != switches::kPpapiPluginProcess) {
+    DVLOG(1) << "Closing CDM files for non-ppapi process.";
+    CdmHostFiles::TakeGlobalInstance().reset();
+  } else {
+    DVLOG(1) << "Not closing CDM files for ppapi process.";
+  }
+#endif
+
   MainFunctionParams main_params(command_line);
   main_params.zygote_child = true;
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index e4e9bb0..587428e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -79,7 +79,6 @@
     "//device/sensors/public/cpp",
     "//device/vibration",
     "//device/wake_lock",
-    "//gin",
     "//google_apis",
     "//gpu",
     "//gpu/command_buffer/client:gles2_implementation",
@@ -1458,6 +1457,9 @@
       "file_descriptor_info_impl.cc",
       "file_descriptor_info_impl.h",
     ]
+
+    # On Windows, the browser cannot depend on gin/V8.
+    deps += [ "//gin" ]
   }
 
   if (enable_basic_printing || enable_print_preview) {
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 06eee06..375720da 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -27,6 +27,8 @@
   "+device/vibration",  # For Vibration API
   "+device/vr",  # For WebVR API
   "+device/wake_lock",
+  # This can only be used on POSIX, in particular it mustn't be used on Windows
+  # in the browser DLL.
   "+gin/v8_initializer.h",
   "+mojo",
   "+services",
diff --git a/content/browser/media/cdm_registry_impl.cc b/content/browser/media/cdm_registry_impl.cc
index fba9689..1f38fe0 100644
--- a/content/browser/media/cdm_registry_impl.cc
+++ b/content/browser/media/cdm_registry_impl.cc
@@ -30,7 +30,7 @@
 
 void CdmRegistryImpl::Init() {
   // Let embedders register CDMs.
-  GetContentClient()->AddContentDecryptionModules(&cdms_);
+  GetContentClient()->AddContentDecryptionModules(&cdms_, nullptr);
 }
 
 void CdmRegistryImpl::RegisterCdm(const CdmInfo& info) {
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 7b541e7..56d2023 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -33,6 +33,7 @@
 #include "content/public/common/sandbox_type.h"
 #include "content/public/common/sandboxed_process_launcher_delegate.h"
 #include "content/public/common/service_names.mojom.h"
+#include "media/base/media_switches.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "net/base/network_change_notifier.h"
 #include "ppapi/proxy/ppapi_messages.h"
@@ -399,6 +400,8 @@
 #if defined(OS_MACOSX)
       switches::kEnableSandboxLogging,
 #endif
+      // Need to tell CdmHostFile(s) to ignore missing CDM host files.
+      switches::kIgnoreMissingCdmHostFile,
       switches::kNoSandbox,
       switches::kPpapiStartupDialog,
     };
diff --git a/content/browser/zygote_host/zygote_communication_linux.cc b/content/browser/zygote_host/zygote_communication_linux.cc
index 47554825..76548d22 100644
--- a/content/browser/zygote_host/zygote_communication_linux.cc
+++ b/content/browser/zygote_host/zygote_communication_linux.cc
@@ -22,6 +22,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
+#include "media/base/media_switches.h"
 #include "ui/display/display_switches.h"
 #include "ui/gfx/switches.h"
 
@@ -250,8 +251,7 @@
   // Should this list be obtained from browser_render_process_host.cc?
   static const char* const kForwardSwitches[] = {
       switches::kAllowSandboxDebugging, switches::kAndroidFontsPath,
-      switches::kDisableSeccompFilterSandbox,
-      switches::kEnableHeapProfiling,
+      switches::kDisableSeccompFilterSandbox, switches::kEnableHeapProfiling,
       switches::kEnableLogging,  // Support, e.g., --enable-logging=stderr.
       // Need to tell the zygote that it is headless so that we don't try to use
       // the wrong type of main delegate.
@@ -261,6 +261,8 @@
       switches::kForceDeviceScaleFactor, switches::kLoggingLevel,
       switches::kNoSandbox, switches::kPpapiInProcess,
       switches::kRegisterPepperPlugins, switches::kV, switches::kVModule,
+      // Need to tell CdmHostFile(s) to ignore missing CDM host files.
+      switches::kIgnoreMissingCdmHostFile,
   };
   cmd_line.CopySwitchesFrom(browser_command_line, kForwardSwitches,
                             arraysize(kForwardSwitches));
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 46b56be6..c2efa7c 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -531,6 +531,23 @@
       "external_ipc_dumper.h",
     ]
   }
+
+  if (enable_pepper_cdms) {
+    sources += [
+      "media/cdm_host_file.cc",
+      "media/cdm_host_file.h",
+      "media/cdm_host_files.cc",
+      "media/cdm_host_files.h",
+    ]
+    deps += [
+      "//media:cdm_paths",
+
+      # Needed for finding CDM path from CDM adapter path.
+      # TODO(xhwang): Remove this dependency when CDM adapter is deprecated.
+      # See http://crbug.com/403462
+      "//third_party/widevine/cdm:headers",
+    ]
+  }
 }
 
 # See comment at the top of //content/BUILD.gn for how this works.
diff --git a/content/common/media/cdm_host_file.cc b/content/common/media/cdm_host_file.cc
new file mode 100644
index 0000000..99d5cca2
--- /dev/null
+++ b/content/common/media/cdm_host_file.cc
@@ -0,0 +1,72 @@
+// 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 "content/common/media/cdm_host_file.h"
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "media/base/media_switches.h"
+#include "media/cdm/api/content_decryption_module_ext.h"
+
+namespace content {
+
+namespace {
+
+bool IgnoreMissingCdmHostFile() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kIgnoreMissingCdmHostFile);
+}
+
+}  // namespace
+
+// static
+std::unique_ptr<CdmHostFile> CdmHostFile::Create(
+    const base::FilePath& file_path,
+    const base::FilePath& sig_file_path) {
+  // Open file at |file_path|.
+  base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+  if (!file.IsValid()) {
+    DVLOG(1) << "Failed to open file at " << file_path.MaybeAsASCII();
+    return nullptr;
+  }
+
+  // Also open the sig file at |sig_file_path|.
+  base::File sig_file(sig_file_path,
+                      base::File::FLAG_OPEN | base::File::FLAG_READ);
+  if (!sig_file.IsValid()) {
+    DVLOG(1) << "Failed to open sig file at " << sig_file_path.MaybeAsASCII();
+    if (!IgnoreMissingCdmHostFile())
+      return nullptr;
+
+    DVLOG(1) << "Ignoring sig file failure at " << sig_file_path.MaybeAsASCII();
+  }
+
+  return std::unique_ptr<CdmHostFile>(
+      new CdmHostFile(file_path, std::move(file), std::move(sig_file)));
+}
+
+cdm::HostFile CdmHostFile::TakePlatformFile() {
+  return cdm::HostFile(file_path_.value().c_str(), file_.TakePlatformFile(),
+                       sig_file_.TakePlatformFile());
+}
+
+CdmHostFile::CdmHostFile(const base::FilePath& file_path,
+                         base::File file,
+                         base::File sig_file)
+    : file_path_(file_path),
+      file_(std::move(file)),
+      sig_file_(std::move(sig_file)) {
+  DVLOG(1) << __func__ << ": " << file_path_.value();
+  DCHECK(!file_path_.empty()) << "File path is empty.";
+  DCHECK(file_.IsValid()) << "Invalid file.";
+
+  if (!IgnoreMissingCdmHostFile())
+    DCHECK(sig_file_.IsValid()) << "Invalid signature file.";
+}
+
+}  // namespace content
diff --git a/content/common/media/cdm_host_file.h b/content/common/media/cdm_host_file.h
new file mode 100644
index 0000000..ade3a27
--- /dev/null
+++ b/content/common/media/cdm_host_file.h
@@ -0,0 +1,53 @@
+// 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 CONTENT_COMMON_MEDIA_CDM_HOST_FILE_H_
+#define CONTENT_COMMON_MEDIA_CDM_HOST_FILE_H_
+
+#include <memory>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+
+namespace cdm {
+struct HostFile;
+}
+
+namespace content {
+
+// Represents a file that participated in hosting the CDM.
+class CdmHostFile {
+ public:
+  // Opens the file at |file_path| and the corresponding signature file at
+  // |sig_file_path|. Upon success, constructs and returns a CdmHostFile object.
+  // Otherwise returns nullptr. The opened files are closed when |this| is
+  // destructed unless TakePlatformFile() was called, in which case the caller
+  // must make sure the files are closed properly.
+  static std::unique_ptr<CdmHostFile> Create(
+      const base::FilePath& file_path,
+      const base::FilePath& sig_file_path);
+
+  // Takes the PlatformFile of the |file_| and |sig_file_| and put them in the
+  // returned cdm::HostFile. The caller must make sure the PlatformFiles are
+  // properly closed after use.
+  cdm::HostFile TakePlatformFile();
+
+ private:
+  CdmHostFile(const base::FilePath& file_path,
+              base::File file,
+              base::File sig_file);
+
+  base::FilePath file_path_;
+  base::File file_;
+
+  // The signature file associated with |file_|.
+  base::File sig_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(CdmHostFile);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_MEDIA_CDM_HOST_FILE_H_
diff --git a/content/common/media/cdm_host_files.cc b/content/common/media/cdm_host_files.cc
new file mode 100644
index 0000000..637891e
--- /dev/null
+++ b/content/common/media/cdm_host_files.cc
@@ -0,0 +1,338 @@
+// 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 "content/common/media/cdm_host_files.h"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/native_library.h"
+#include "base/path_service.h"
+#include "base/scoped_native_library.h"
+#include "build/build_config.h"
+#include "content/common/media/cdm_host_file.h"
+#include "content/public/common/cdm_info.h"
+#include "content/public/common/content_client.h"
+#include "media/base/media_switches.h"
+#include "media/cdm/api/content_decryption_module_ext.h"
+#include "media/cdm/cdm_paths.h"
+
+#if defined(POSIX_WITH_ZYGOTE)
+#include "content/common/pepper_plugin_list.h"
+#include "content/public/common/pepper_plugin_info.h"
+#endif
+
+#include "widevine_cdm_version.h"  // In SHARED_INTERMEDIATE_DIR.
+
+namespace content {
+
+namespace {
+
+bool IgnoreMissingCdmHostFile() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kIgnoreMissingCdmHostFile);
+}
+
+// TODO(xhwang): Move this to a common place if needed.
+const base::FilePath::CharType kSignatureFileExtension[] =
+    FILE_PATH_LITERAL(".sig");
+
+// Returns the signature file path given the |file_path|. This function should
+// only be used when the signature file and the file are located in the same
+// directory, which is the case for the CDM and CDM adapter.
+base::FilePath GetSigFilePath(const base::FilePath& file_path) {
+  return file_path.AddExtension(kSignatureFileExtension);
+}
+
+// Returns the CDM library file name given the |cdm_adapter_file_name|. Returns
+// nullptr if |cdm_adapter_file_name| does not correspond to a known CDM.
+const char* GetCdmFileName(const base::FilePath& cdm_adapter_file_name) {
+#if defined(WIDEVINE_CDM_AVAILABLE)
+  if (cdm_adapter_file_name ==
+      base::FilePath::FromUTF8Unsafe(kWidevineCdmAdapterFileName))
+    return kWidevineCdmLibraryName;
+#endif
+
+  // Clear Key CDM. For test only.
+  if (cdm_adapter_file_name ==
+      base::FilePath::FromUTF8Unsafe(media::kClearKeyCdmAdapterFileName))
+    return media::kClearKeyCdmLibraryName;
+
+  return nullptr;
+}
+
+// Returns the path to the CDM binary given the |cdm_adapter_path|. Returns an
+// empty path if |cdm_adapter_path| does not correspond to a known CDM.
+base::FilePath GetCdmPath(const base::FilePath& cdm_adapter_path) {
+  const char* cdm_file_name = GetCdmFileName(cdm_adapter_path.BaseName());
+  if (!cdm_file_name)
+    return base::FilePath();
+
+  return cdm_adapter_path.DirName().AppendASCII(
+      base::GetNativeLibraryName(cdm_file_name));
+}
+
+#if defined(POSIX_WITH_ZYGOTE)
+// From the list of registered plugins, finds all registered CDMs and fills
+// |cdm_adapter_paths| with found CDM adapters paths.
+void GetRegisteredCdms(std::vector<base::FilePath>* cdm_adapter_paths) {
+  std::vector<PepperPluginInfo> plugins;
+  ComputePepperPluginList(&plugins);
+  for (const auto& plugin : plugins) {
+    // CDM is not an internal plugin.
+    if (plugin.is_internal)
+      continue;
+
+    if (IsCdm(plugin.path))
+      cdm_adapter_paths->push_back(plugin.path);
+  }
+}
+
+// A global instance used on platforms where we have to open the files in the
+// Zygote process.
+base::LazyInstance<std::unique_ptr<CdmHostFiles>> g_cdm_host_files =
+    LAZY_INSTANCE_INITIALIZER;
+#endif
+
+}  // namespace
+
+CdmHostFiles::CdmHostFiles() {
+  DVLOG(1) << __func__;
+}
+
+CdmHostFiles::~CdmHostFiles() {
+  DVLOG(1) << __func__;
+}
+
+#if defined(POSIX_WITH_ZYGOTE)
+// static
+void CdmHostFiles::CreateGlobalInstance() {
+  DVLOG(1) << __func__;
+  DCHECK(!g_cdm_host_files.Get().get());
+
+  std::unique_ptr<CdmHostFiles> cdm_host_files =
+      base::MakeUnique<CdmHostFiles>();
+  if (!cdm_host_files->OpenFilesForAllRegisteredCdms()) {
+    DVLOG(1) << __func__ << " failed.";
+    cdm_host_files.reset();
+    return;
+  }
+
+  g_cdm_host_files.Get().reset(cdm_host_files.release());
+}
+
+// static
+std::unique_ptr<CdmHostFiles> CdmHostFiles::TakeGlobalInstance() {
+  return std::move(g_cdm_host_files.Get());
+}
+#endif
+
+// static
+std::unique_ptr<CdmHostFiles> CdmHostFiles::Create(
+    const base::FilePath& cdm_adapter_path) {
+  DVLOG(1) << __func__;
+  std::unique_ptr<CdmHostFiles> cdm_host_files =
+      base::MakeUnique<CdmHostFiles>();
+  if (!cdm_host_files->OpenFiles(cdm_adapter_path)) {
+    cdm_host_files.reset();
+    return nullptr;
+  }
+
+  return cdm_host_files;
+}
+
+bool CdmHostFiles::VerifyFiles(base::NativeLibrary cdm_adapter_library,
+                               const base::FilePath& cdm_adapter_path) {
+  DVLOG(1) << __func__;
+  DCHECK(cdm_adapter_library);
+
+  // Get function pointer exported by the CDM.
+  // See media/cdm/api/content_decryption_module_ext.h.
+  using VerifyCdmHostFunc =
+      bool (*)(const cdm::HostFile* cdm_host_files, uint32_t num_files);
+  static const char kVerifyCdmHostFuncName[] = "VerifyCdmHost_0";
+
+  base::NativeLibrary cdm_library;
+#if defined(OS_LINUX) || defined(OS_MACOSX)
+  // On POSIX, "the dlsym() function shall search for the named symbol in all
+  // objects loaded automatically as a result of loading the object referenced
+  // by handle". Since the CDM is loaded automatically as a result of loading
+  // the CDM adapter, we can just use the adapter to look for CDM symbols.
+  cdm_library = cdm_adapter_library;
+#elif defined(OS_WIN)
+  // On Windows, we have manually load the CDM.
+  base::ScopedNativeLibrary scoped_cdm_library;
+  base::NativeLibraryLoadError error;
+  scoped_cdm_library.Reset(
+      base::LoadNativeLibrary(GetCdmPath(cdm_adapter_path), &error));
+  if (!scoped_cdm_library.is_valid()) {
+    LOG(ERROR) << "Failed to load CDM (error: " << error.ToString() << ")";
+    CloseAllFiles();
+    return true;
+  }
+  cdm_library = scoped_cdm_library.get();
+#endif
+
+  VerifyCdmHostFunc verify_cdm_host_func = reinterpret_cast<VerifyCdmHostFunc>(
+      base::GetFunctionPointerFromNativeLibrary(cdm_library,
+                                                kVerifyCdmHostFuncName));
+  if (!verify_cdm_host_func) {
+    LOG(ERROR) << "Function " << kVerifyCdmHostFuncName << " not found.";
+    CloseAllFiles();
+    return true;
+  }
+
+  // Fills |cdm_host_files| with common and CDM specific files for
+  // |cdm_adapter_path|.
+  std::vector<cdm::HostFile> cdm_host_files;
+  if (!TakePlatformFiles(cdm_adapter_path, &cdm_host_files)) {
+    DVLOG(1) << "Failed to take platform files.";
+    CloseAllFiles();
+    return true;
+  }
+
+  // Call |verify_cdm_host_func| on the CDM with |cdm_host_files|. Note that
+  // the ownership of these files are transferred to the CDM, which will close
+  // the files immediately after use.
+  DVLOG(1) << __func__ << ": Calling " << kVerifyCdmHostFuncName << "().";
+  if (!verify_cdm_host_func(cdm_host_files.data(), cdm_host_files.size())) {
+    DVLOG(1) << "Failed to verify CDM host.";
+    CloseAllFiles();
+    return false;
+  }
+
+  // Close all files not passed to the CDM.
+  CloseAllFiles();
+  return true;
+}
+
+#if defined(POSIX_WITH_ZYGOTE)
+bool CdmHostFiles::OpenFilesForAllRegisteredCdms() {
+  std::vector<base::FilePath> cdm_adapter_paths;
+  GetRegisteredCdms(&cdm_adapter_paths);
+  if (cdm_adapter_paths.empty()) {
+    DVLOG(1) << "No CDM registered.";
+    return false;
+  }
+
+  // Ignore
+  for (auto& cdm_adapter_path : cdm_adapter_paths) {
+    bool result = OpenCdmFiles(cdm_adapter_path);
+    if (!result)
+      DVLOG(1) << "CDM files cannot be opened for " << cdm_adapter_path.value();
+    // Ignore the failure and try other registered CDM.
+  }
+
+  if (cdm_specific_files_map_.empty()) {
+    DVLOG(1) << "CDM specific files cannot be opened for any registered CDM.";
+    return false;
+  }
+
+  return OpenCommonFiles();
+}
+#endif
+
+bool CdmHostFiles::OpenFiles(const base::FilePath& cdm_adapter_path) {
+  if (!OpenCdmFiles(cdm_adapter_path))
+    return false;
+
+  return OpenCommonFiles();
+}
+
+bool CdmHostFiles::OpenCommonFiles() {
+  DCHECK(common_files_.empty());
+
+  std::vector<CdmHostFilePath> cdm_host_file_paths;
+  GetContentClient()->AddContentDecryptionModules(nullptr,
+                                                  &cdm_host_file_paths);
+
+  for (const CdmHostFilePath& value : cdm_host_file_paths) {
+    std::unique_ptr<CdmHostFile> cdm_host_file =
+        CdmHostFile::Create(value.file_path, value.sig_file_path);
+    if (cdm_host_file) {
+      common_files_.push_back(std::move(cdm_host_file));
+      continue;
+    }
+
+    if (!IgnoreMissingCdmHostFile())
+      return false;
+  }
+
+  return true;
+}
+
+bool CdmHostFiles::OpenCdmFiles(const base::FilePath& cdm_adapter_path) {
+  DCHECK(!cdm_adapter_path.empty());
+  DCHECK(!cdm_specific_files_map_.count(cdm_adapter_path));
+
+  std::unique_ptr<CdmHostFile> cdm_adapter_file =
+      CdmHostFile::Create(cdm_adapter_path, GetSigFilePath(cdm_adapter_path));
+  if (!cdm_adapter_file)
+    return false;
+
+  base::FilePath cdm_path = GetCdmPath(cdm_adapter_path);
+  std::unique_ptr<CdmHostFile> cdm_file =
+      CdmHostFile::Create(cdm_path, GetSigFilePath(cdm_path));
+  if (!cdm_file)
+    return false;
+
+  ScopedFileVector cdm_specific_files;
+  cdm_specific_files.reserve(2);
+  cdm_specific_files.push_back(std::move(cdm_adapter_file));
+  cdm_specific_files.push_back(std::move(cdm_file));
+
+  cdm_specific_files_map_[cdm_adapter_path] = std::move(cdm_specific_files);
+  return true;
+}
+
+bool CdmHostFiles::TakePlatformFiles(
+    const base::FilePath& cdm_adapter_path,
+    std::vector<cdm::HostFile>* cdm_host_files) {
+  DCHECK(cdm_host_files->empty());
+
+  if (!IgnoreMissingCdmHostFile())
+    DCHECK(!common_files_.empty());
+
+  // Check whether CDM specific files exist.
+  const auto& iter = cdm_specific_files_map_.find(cdm_adapter_path);
+  if (iter == cdm_specific_files_map_.end()) {
+    // This could happen on Linux where CDM files fail to open for Foo CDM, but
+    // now we hit Bar CDM.
+    DVLOG(1) << "No CDM specific files for " << cdm_adapter_path.value();
+    return false;
+  }
+
+  const ScopedFileVector& cdm_specific_files = iter->second;
+
+  cdm_host_files->reserve(common_files_.size() + cdm_specific_files.size());
+
+  // Populate an array of cdm::HostFile.
+  for (const auto& file : common_files_)
+    cdm_host_files->push_back(file->TakePlatformFile());
+
+  for (const auto& file : cdm_specific_files)
+    cdm_host_files->push_back(file->TakePlatformFile());
+
+  return true;
+}
+
+void CdmHostFiles::CloseAllFiles() {
+  common_files_.clear();
+  cdm_specific_files_map_.clear();
+}
+
+// Question(xhwang): Any better way to check whether a plugin is a CDM? Maybe
+// when we register the plugin we can set some flag explicitly?
+bool IsCdm(const base::FilePath& cdm_adapter_path) {
+  return !GetCdmPath(cdm_adapter_path).empty();
+}
+
+}  // namespace content
diff --git a/content/common/media/cdm_host_files.h b/content/common/media/cdm_host_files.h
new file mode 100644
index 0000000..5ec1daf
--- /dev/null
+++ b/content/common/media/cdm_host_files.h
@@ -0,0 +1,110 @@
+// 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 CONTENT_COMMON_MEDIA_CDM_HOST_FILES_H_
+#define CONTENT_COMMON_MEDIA_CDM_HOST_FILES_H_
+
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/native_library.h"
+#include "base/path_service.h"
+#include "build/build_config.h"
+#include "content/common/media/cdm_host_file.h"
+#include "content/common/pepper_plugin_list.h"
+#include "content/public/common/pepper_plugin_info.h"
+#include "media/cdm/api/content_decryption_module_ext.h"
+#include "media/cdm/cdm_paths.h"
+
+// On systems that use the zygote process to spawn child processes, we must
+// open files in the zygote process.
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_MACOSX) && \
+    !defined(OS_ANDROID)
+#define POSIX_WITH_ZYGOTE 1
+#endif
+
+namespace base {
+class FilePath;
+}
+
+namespace content {
+
+// Manages all CDM host files.
+class CdmHostFiles {
+ public:
+  CdmHostFiles();
+  ~CdmHostFiles();
+
+#if defined(POSIX_WITH_ZYGOTE)
+  // Opens CDM host files for all registered CDMs and set the global
+  // CdmHostFiles instance.  On any failure, the global instance will not be
+  // set and no file will be left open.
+  static void CreateGlobalInstance();
+
+  // Takes and returns the global CdmHostFiles instance. The return value could
+  // be nullptr if CreateGlobalInstance() failed.
+  static std::unique_ptr<CdmHostFiles> TakeGlobalInstance();
+#endif
+
+  // Opens CDM host files for the CDM adapter at |cdm_adapter_path| and returns
+  // the created CdmHostFiles instance. Returns nullptr if any of the files
+  // cannot be opened, in which case no file will be left open.
+  static std::unique_ptr<CdmHostFiles> Create(
+      const base::FilePath& cdm_adapter_path);
+
+  // Verifies |cdm_adapter_path| CDM files by calling the function exported
+  // by the CDM. If unexpected error happens, all files will be closed.
+  // Otherwise, the PlatformFiles are passed to the CDM which will close the
+  // files later.
+  // Only returns false if the CDM returns false (when there's an immediate
+  // failure). Otherwise always returns true for backward compatibility, e.g.
+  // when using an old CDM which doesn't implement the verification API.
+  bool VerifyFiles(base::NativeLibrary cdm_adapter_library,
+                   const base::FilePath& cdm_adapter_path);
+
+ private:
+#if defined(POSIX_WITH_ZYGOTE)
+  // Opens all common files and CDM specific files for all registered CDMs.
+  bool OpenFilesForAllRegisteredCdms();
+#endif
+
+  // Opens all common files and CDM specific files for the CDM adapter
+  // registered at |cdm_adapter_path|.
+  bool OpenFiles(const base::FilePath& cdm_adapter_path);
+
+  // Opens common CDM host files shared by all CDMs. Upon failure, close all
+  // files opened.
+  bool OpenCommonFiles();
+
+  // Opens CDM specific files for the CDM adapter registered at
+  // |cdm_adapter_path|. Returns whether all CDM specific files are opened.
+  // Upon failure, close all files opened.
+  bool OpenCdmFiles(const base::FilePath& cdm_adapter_path);
+
+  // Fills |cdm_host_files| with common and CDM specific files for
+  // |cdm_adapter_path|. The ownership of those files are also transferred.
+  // Returns true upon success where the remaining files will be closed.
+  // Returns false upon any failure and all files will be closed.
+  bool TakePlatformFiles(const base::FilePath& cdm_adapter_path,
+                         std::vector<cdm::HostFile>* cdm_host_files);
+
+  void CloseAllFiles();
+
+  using ScopedFileVector = std::vector<std::unique_ptr<CdmHostFile>>;
+  ScopedFileVector common_files_;
+  std::map<base::FilePath, ScopedFileVector> cdm_specific_files_map_;
+};
+
+// Returns whether the |cdm_adapter_path| corresponds to a known CDM.
+bool IsCdm(const base::FilePath& cdm_adapter_path);
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_MEDIA_CDM_HOST_FILES_H_
diff --git a/content/common/media/cdm_info.cc b/content/common/media/cdm_info.cc
index 0a3a7b1..3dbdcdab 100644
--- a/content/common/media/cdm_info.cc
+++ b/content/common/media/cdm_info.cc
@@ -19,4 +19,10 @@
 
 CdmInfo::~CdmInfo() {}
 
+CdmHostFilePath::CdmHostFilePath(const base::FilePath& file_path,
+                                 const base::FilePath& sig_file_path)
+    : file_path(file_path), sig_file_path(sig_file_path) {}
+
+CdmHostFilePath::~CdmHostFilePath() {}
+
 }  // namespace content
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 7aa89dd..6743e954 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -65,6 +65,10 @@
 #include "content/common/sandbox_init_mac.h"
 #endif
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#include "content/common/media/cdm_host_files.h"
+#endif
+
 #if defined(OS_WIN)
 const char kWidevineCdmAdapterFileName[] = "widevinecdmadapter.dll";
 
@@ -372,6 +376,22 @@
     }
   }
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+  // Use a local instance of CdmHostFiles so that if we return early for any
+  // error, all files will closed automatically.
+  std::unique_ptr<CdmHostFiles> cdm_host_files;
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  // Open CDM host files before the process is sandboxed.
+  if (!is_broker_ && IsCdm(path))
+    cdm_host_files = CdmHostFiles::Create(path);
+#elif defined(OS_LINUX)
+  cdm_host_files = CdmHostFiles::TakeGlobalInstance();
+  if (is_broker_ || !IsCdm(path))
+    cdm_host_files.reset();  // Close all opened files.
+#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+#endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
+
 #if defined(OS_WIN)
   // If code subsequently tries to exit using abort(), force a crash (since
   // otherwise these would be silent terminations and fly under the radar).
@@ -458,6 +478,18 @@
       ReportLoadResult(path, INIT_FAILED);
       return;
     }
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+    // Now the process is sandboxed. Verify CDM host.
+    if (cdm_host_files) {
+      DCHECK(IsCdm(path));
+      if (!cdm_host_files->VerifyFiles(library.get(), path)) {
+        LOG(WARNING) << "CDM host verification failed.";
+        // TODO(xhwang): Add a new load result if needed.
+        ReportLoadResult(path, INIT_FAILED);
+        return;
+      }
+    }
+#endif  // BUILDFLAG(ENABLE_PEPPER_CDMS)
   }
 
   // Initialization succeeded, so keep the plugin DLL loaded.
diff --git a/content/public/common/cdm_info.h b/content/public/common/cdm_info.h
index ee6780b2..ca66734 100644
--- a/content/public/common/cdm_info.h
+++ b/content/public/common/cdm_info.h
@@ -39,6 +39,18 @@
   std::vector<std::string> supported_codecs;
 };
 
+struct CONTENT_EXPORT CdmHostFilePath {
+  CdmHostFilePath(const base::FilePath& file_path,
+                  const base::FilePath& sig_file_path);
+  ~CdmHostFilePath();
+
+  // Path to a file that takes part in hosting the CDM.
+  base::FilePath file_path;
+
+  // Path to a signature file of the file at |file_path|.
+  base::FilePath sig_file_path;
+};
+
 }  // namespace content
 
 #endif  // CONTENT_PUBLIC_COMMON_CDM_INFO_H_
diff --git a/content/public/common/content_client.h b/content/public/common/content_client.h
index 57a52fa..ea0bb0d 100644
--- a/content/public/common/content_client.h
+++ b/content/public/common/content_client.h
@@ -45,6 +45,7 @@
 class ContentRendererClient;
 class ContentUtilityClient;
 class OriginTrialPolicy;
+struct CdmHostFilePath;
 struct CdmInfo;
 struct PepperPluginInfo;
 
@@ -87,10 +88,13 @@
   virtual void AddPepperPlugins(
       std::vector<content::PepperPluginInfo>* plugins) {}
 
-  // Gives the embedder a chance to register the content decryption
-  // modules it supports.
+  // Gives the embedder a chance to register the Content Decryption Modules
+  // (CDM) it supports, as well as the CDM host file paths to verify CDM host.
+  // |cdms| or |cdm_host_file_paths| can be null which means that specific list
+  // is not needed.
   virtual void AddContentDecryptionModules(
-      std::vector<content::CdmInfo>* cdms) {}
+      std::vector<content::CdmInfo>* cdms,
+      std::vector<content::CdmHostFilePath>* cdm_host_file_paths) {}
 
   // Gives the embedder a chance to register its own schemes early in the
   // startup sequence.
diff --git a/content/renderer/mus/BUILD.gn b/content/renderer/mus/BUILD.gn
index 9f9daac6..5409466 100644
--- a/content/renderer/mus/BUILD.gn
+++ b/content/renderer/mus/BUILD.gn
@@ -7,10 +7,10 @@
   visibility = [ "//content/renderer/*" ]
 
   sources = [
-    "render_widget_mus_connection.cc",
-    "render_widget_mus_connection.h",
     "render_widget_window_tree_client_factory.cc",
     "render_widget_window_tree_client_factory.h",
+    "renderer_window_tree_client.cc",
+    "renderer_window_tree_client.h",
   ]
 
   configs += [ "//content:content_implementation" ]
diff --git a/content/renderer/mus/render_widget_mus_connection.cc b/content/renderer/mus/render_widget_mus_connection.cc
deleted file mode 100644
index 0d473b1..0000000
--- a/content/renderer/mus/render_widget_mus_connection.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/mus/render_widget_mus_connection.h"
-
-#include <map>
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "content/renderer/render_thread_impl.h"
-#include "content/renderer/render_view_impl.h"
-#include "services/ui/public/cpp/window_compositor_frame_sink.h"
-#include "services/ui/public/interfaces/window_tree.mojom.h"
-
-namespace content {
-
-namespace {
-
-typedef std::map<int, RenderWidgetMusConnection*> ConnectionMap;
-base::LazyInstance<ConnectionMap>::Leaky g_connections =
-    LAZY_INSTANCE_INITIALIZER;
-}
-
-void RenderWidgetMusConnection::Bind(
-    mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request) {
-  // TODO(sad): crbug.com/672913
-}
-
-std::unique_ptr<cc::CompositorFrameSink>
-RenderWidgetMusConnection::CreateCompositorFrameSink(
-    const cc::FrameSinkId& frame_sink_id,
-    scoped_refptr<cc::ContextProvider> context_provider,
-    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
-  // TODO(sad): crbug.com/672913
-  return nullptr;
-}
-
-// static
-RenderWidgetMusConnection* RenderWidgetMusConnection::Get(int routing_id) {
-  auto it = g_connections.Get().find(routing_id);
-  if (it != g_connections.Get().end())
-    return it->second;
-  return nullptr;
-}
-
-// static
-RenderWidgetMusConnection* RenderWidgetMusConnection::GetOrCreate(
-    int routing_id) {
-  RenderWidgetMusConnection* connection = Get(routing_id);
-  if (!connection) {
-    connection = new RenderWidgetMusConnection(routing_id);
-    g_connections.Get().insert(std::make_pair(routing_id, connection));
-  }
-  return connection;
-}
-
-RenderWidgetMusConnection::RenderWidgetMusConnection(int routing_id)
-    : routing_id_(routing_id) {
-  DCHECK(routing_id);
-}
-
-RenderWidgetMusConnection::~RenderWidgetMusConnection() {}
-
-}  // namespace content
diff --git a/content/renderer/mus/render_widget_mus_connection.h b/content/renderer/mus/render_widget_mus_connection.h
deleted file mode 100644
index edf6697..0000000
--- a/content/renderer/mus/render_widget_mus_connection.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_MUS_RENDER_WIDGET_MUS_CONNECTION_H_
-#define CONTENT_RENDERER_MUS_RENDER_WIDGET_MUS_CONNECTION_H_
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "cc/output/compositor_frame_sink.h"
-#include "cc/output/context_provider.h"
-#include "content/common/content_export.h"
-#include "services/ui/public/interfaces/window_tree.mojom.h"
-
-namespace gpu {
-class GpuMemoryBufferManager;
-}
-
-namespace ui {
-class WindowCompositorFrameSinkBinding;
-}
-
-namespace content {
-
-// This lives in the main-thread, and manages the connection to the mus window
-// server for a RenderWidget.
-class CONTENT_EXPORT RenderWidgetMusConnection {
- public:
-  // Bind to a WindowTreeClient request.
-  void Bind(mojo::InterfaceRequest<ui::mojom::WindowTreeClient> request);
-
-  // Create a cc output surface.
-  std::unique_ptr<cc::CompositorFrameSink> CreateCompositorFrameSink(
-      const cc::FrameSinkId& frame_sink_id,
-      scoped_refptr<cc::ContextProvider> context_provider,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
-
-  static RenderWidgetMusConnection* Get(int routing_id);
-
-  // Get the connection from a routing_id, if the connection doesn't exist,
-  // a new connection will be created.
-  static RenderWidgetMusConnection* GetOrCreate(int routing_id);
-
- private:
-  friend class CompositorMusConnection;
-  friend class CompositorMusConnectionTest;
-
-  explicit RenderWidgetMusConnection(int routing_id);
-  ~RenderWidgetMusConnection();
-
-  const int routing_id_;
-  std::unique_ptr<ui::WindowCompositorFrameSinkBinding>
-      window_compositor_frame_sink_binding_;
-
-  DISALLOW_COPY_AND_ASSIGN(RenderWidgetMusConnection);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_MUS_RENDER_WIDGET_MUS_CONNECTION_H_
diff --git a/content/renderer/mus/render_widget_window_tree_client_factory.cc b/content/renderer/mus/render_widget_window_tree_client_factory.cc
index 642a0e7a..e2a1998 100644
--- a/content/renderer/mus/render_widget_window_tree_client_factory.cc
+++ b/content/renderer/mus/render_widget_window_tree_client_factory.cc
@@ -16,7 +16,7 @@
 #include "content/common/render_widget_window_tree_client_factory.mojom.h"
 #include "content/public/common/connection_filter.h"
 #include "content/public/common/service_manager_connection.h"
-#include "content/renderer/mus/render_widget_mus_connection.h"
+#include "content/renderer/mus/renderer_window_tree_client.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
@@ -31,9 +31,7 @@
 void BindMusConnectionOnMainThread(
     uint32_t routing_id,
     ui::mojom::WindowTreeClientRequest request) {
-  RenderWidgetMusConnection* connection =
-      RenderWidgetMusConnection::GetOrCreate(routing_id);
-  connection->Bind(std::move(request));
+  RendererWindowTreeClient::Get(routing_id)->Bind(std::move(request));
 }
 
 // This object's lifetime is managed by ServiceManagerConnection because it's a
diff --git a/content/renderer/mus/renderer_window_tree_client.cc b/content/renderer/mus/renderer_window_tree_client.cc
new file mode 100644
index 0000000..2be8bcf
--- /dev/null
+++ b/content/renderer/mus/renderer_window_tree_client.cc
@@ -0,0 +1,225 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/mus/renderer_window_tree_client.h"
+
+#include <map>
+
+#include "base/lazy_instance.h"
+#include "services/ui/public/cpp/window_compositor_frame_sink.h"
+
+namespace content {
+
+namespace {
+typedef std::map<int, RendererWindowTreeClient*> ConnectionMap;
+base::LazyInstance<ConnectionMap>::Leaky g_connections =
+    LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+// static
+RendererWindowTreeClient* RendererWindowTreeClient::Get(int routing_id) {
+  auto it = g_connections.Get().find(routing_id);
+  if (it != g_connections.Get().end())
+    return it->second;
+  return nullptr;
+}
+
+// static
+void RendererWindowTreeClient::Create(int routing_id) {
+  DCHECK(g_connections.Get().find(routing_id) == g_connections.Get().end());
+  RendererWindowTreeClient* connection =
+      new RendererWindowTreeClient(routing_id);
+  g_connections.Get().insert(std::make_pair(routing_id, connection));
+}
+
+RendererWindowTreeClient::RendererWindowTreeClient(int routing_id)
+    : routing_id_(routing_id), binding_(this) {}
+
+RendererWindowTreeClient::~RendererWindowTreeClient() {
+  g_connections.Get().erase(routing_id_);
+}
+
+void RendererWindowTreeClient::Bind(
+    ui::mojom::WindowTreeClientRequest request) {
+  binding_.Bind(std::move(request));
+}
+
+std::unique_ptr<cc::CompositorFrameSink>
+RendererWindowTreeClient::CreateCompositorFrameSink(
+    const cc::FrameSinkId& frame_sink_id,
+    scoped_refptr<cc::ContextProvider> context_provider,
+    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager) {
+  std::unique_ptr<ui::WindowCompositorFrameSinkBinding> frame_sink_binding;
+  auto frame_sink = ui::WindowCompositorFrameSink::Create(
+      frame_sink_id, std::move(context_provider), gpu_memory_buffer_manager,
+      &frame_sink_binding);
+  if (tree_) {
+    tree_->AttachCompositorFrameSink(
+        root_window_id_, frame_sink_binding->TakeFrameSinkRequest(),
+        mojo::MakeProxy(frame_sink_binding->TakeFrameSinkClient()));
+  } else {
+    pending_frame_sink_ = std::move(frame_sink_binding);
+  }
+  return std::move(frame_sink);
+}
+
+void RendererWindowTreeClient::DestroySelf() {
+  delete this;
+}
+
+void RendererWindowTreeClient::OnEmbed(ui::ClientSpecificId client_id,
+                                       ui::mojom::WindowDataPtr root,
+                                       ui::mojom::WindowTreePtr tree,
+                                       int64_t display_id,
+                                       ui::Id focused_window_id,
+                                       bool drawn) {
+  root_window_id_ = root->window_id;
+  tree_ = std::move(tree);
+  if (pending_frame_sink_) {
+    tree_->AttachCompositorFrameSink(
+        root_window_id_, pending_frame_sink_->TakeFrameSinkRequest(),
+        mojo::MakeProxy(pending_frame_sink_->TakeFrameSinkClient()));
+    pending_frame_sink_ = nullptr;
+  }
+}
+
+void RendererWindowTreeClient::OnEmbeddedAppDisconnected(ui::Id window_id) {
+  // TODO(sad): Embedded mus-client (oopif) is gone. Figure out what to do.
+}
+
+void RendererWindowTreeClient::OnUnembed(ui::Id window_id) {
+  CHECK_EQ(window_id, root_window_id_);
+  DestroySelf();
+}
+
+void RendererWindowTreeClient::OnCaptureChanged(ui::Id new_capture_window_id,
+                                                ui::Id old_capture_window_id) {}
+
+void RendererWindowTreeClient::OnTopLevelCreated(uint32_t change_id,
+                                                 ui::mojom::WindowDataPtr data,
+                                                 int64_t display_id,
+                                                 bool drawn) {
+  NOTREACHED();
+}
+
+void RendererWindowTreeClient::OnWindowBoundsChanged(
+    ui::Id window_id,
+    const gfx::Rect& old_bounds,
+    const gfx::Rect& new_bounds) {}
+
+void RendererWindowTreeClient::OnClientAreaChanged(
+    uint32_t window_id,
+    const gfx::Insets& new_client_area,
+    const std::vector<gfx::Rect>& new_additional_client_areas) {}
+
+void RendererWindowTreeClient::OnTransientWindowAdded(
+    uint32_t window_id,
+    uint32_t transient_window_id) {}
+
+void RendererWindowTreeClient::OnTransientWindowRemoved(
+    uint32_t window_id,
+    uint32_t transient_window_id) {}
+
+void RendererWindowTreeClient::OnWindowHierarchyChanged(
+    ui::Id window_id,
+    ui::Id old_parent_id,
+    ui::Id new_parent_id,
+    std::vector<ui::mojom::WindowDataPtr> windows) {}
+
+void RendererWindowTreeClient::OnWindowReordered(
+    ui::Id window_id,
+    ui::Id relative_window_id,
+    ui::mojom::OrderDirection direction) {}
+
+void RendererWindowTreeClient::OnWindowDeleted(ui::Id window_id) {
+  // TODO(sad): With OOPIF, |window_id| may not be |root_window_id_|. We need to
+  // make sure that works correctly.
+  CHECK_EQ(window_id, root_window_id_);
+  DestroySelf();
+}
+
+void RendererWindowTreeClient::OnWindowVisibilityChanged(ui::Id window_id,
+                                                         bool visible) {}
+
+void RendererWindowTreeClient::OnWindowOpacityChanged(ui::Id window_id,
+                                                      float old_opacity,
+                                                      float new_opacity) {}
+
+void RendererWindowTreeClient::OnWindowParentDrawnStateChanged(ui::Id window_id,
+                                                               bool drawn) {}
+
+void RendererWindowTreeClient::OnWindowSharedPropertyChanged(
+    ui::Id window_id,
+    const std::string& name,
+    const base::Optional<std::vector<uint8_t>>& new_data) {}
+
+void RendererWindowTreeClient::OnWindowInputEvent(
+    uint32_t event_id,
+    ui::Id window_id,
+    std::unique_ptr<ui::Event> event,
+    bool matches_pointer_watcher) {
+  NOTREACHED();
+}
+
+void RendererWindowTreeClient::OnPointerEventObserved(
+    std::unique_ptr<ui::Event> event,
+    uint32_t window_id) {
+  NOTREACHED();
+}
+
+void RendererWindowTreeClient::OnWindowFocused(ui::Id focused_window_id) {}
+
+void RendererWindowTreeClient::OnWindowPredefinedCursorChanged(
+    ui::Id window_id,
+    ui::mojom::Cursor cursor) {}
+
+void RendererWindowTreeClient::OnWindowSurfaceChanged(
+    ui::Id window_id,
+    const cc::SurfaceInfo& surface_info) {
+  NOTIMPLEMENTED();
+}
+
+void RendererWindowTreeClient::OnDragDropStart(
+    const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data) {}
+
+void RendererWindowTreeClient::OnDragEnter(
+    ui::Id window_id,
+    uint32_t event_flags,
+    const gfx::Point& position,
+    uint32_t effect_bitmask,
+    const OnDragEnterCallback& callback) {}
+
+void RendererWindowTreeClient::OnDragOver(ui::Id window_id,
+                                          uint32_t event_flags,
+                                          const gfx::Point& position,
+                                          uint32_t effect_bitmask,
+                                          const OnDragOverCallback& callback) {}
+
+void RendererWindowTreeClient::OnDragLeave(ui::Id window_id) {}
+
+void RendererWindowTreeClient::OnCompleteDrop(
+    ui::Id window_id,
+    uint32_t event_flags,
+    const gfx::Point& position,
+    uint32_t effect_bitmask,
+    const OnCompleteDropCallback& callback) {}
+
+void RendererWindowTreeClient::OnPerformDragDropCompleted(
+    uint32_t window,
+    bool success,
+    uint32_t action_taken) {}
+
+void RendererWindowTreeClient::OnDragDropDone() {}
+
+void RendererWindowTreeClient::OnChangeCompleted(uint32_t change_id,
+                                                 bool success) {}
+
+void RendererWindowTreeClient::RequestClose(uint32_t window_id) {}
+
+void RendererWindowTreeClient::GetWindowManager(
+    mojo::AssociatedInterfaceRequest<ui::mojom::WindowManager> internal) {
+  NOTREACHED();
+}
+
+}  // namespace content
diff --git a/content/renderer/mus/renderer_window_tree_client.h b/content/renderer/mus/renderer_window_tree_client.h
new file mode 100644
index 0000000..81662e5
--- /dev/null
+++ b/content/renderer/mus/renderer_window_tree_client.h
@@ -0,0 +1,153 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_MUS_RENDERER_WINDOW_TREE_CLIENT_H_
+#define CONTENT_RENDERER_MUS_RENDERER_WINDOW_TREE_CLIENT_H_
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/ui/common/types.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
+
+namespace cc {
+class CompositorFrameSink;
+class ContextProvider;
+}
+
+namespace gpu {
+class GpuMemoryBufferManager;
+}
+
+namespace ui {
+class WindowCompositorFrameSinkBinding;
+}
+
+namespace content {
+
+// ui.mojom.WindowTreeClient implementation for RenderWidget. This lives and
+// operates on the renderer's main thread.
+class RendererWindowTreeClient : public ui::mojom::WindowTreeClient {
+ public:
+  // Creates a RendererWindowTreeClient instance for the RenderWidget instance
+  // associated with |routing_id|. The instance self-destructs when the
+  // connection to mus is lost, or when the window is closed.
+  static void Create(int routing_id);
+
+  // Returns the RendererWindowTreeClient associated with |routing_id|. Returns
+  // nullptr if none exists.
+  static RendererWindowTreeClient* Get(int routing_id);
+
+  void Bind(ui::mojom::WindowTreeClientRequest request);
+
+  std::unique_ptr<cc::CompositorFrameSink> CreateCompositorFrameSink(
+      const cc::FrameSinkId& frame_sink_id,
+      scoped_refptr<cc::ContextProvider> context_provider,
+      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
+
+ private:
+  explicit RendererWindowTreeClient(int routing_id);
+  ~RendererWindowTreeClient() override;
+
+  void DestroySelf();
+
+  // ui::mojom::WindowTreeClient:
+  // Note: A number of the following are currently not-implemented. Some of
+  // these will remain unimplemented in the long-term. Some of the
+  // implementations would require some amount of refactoring out of
+  // RenderWidget and related classes (e.g. resize, input, ime etc.).
+  void OnEmbed(ui::ClientSpecificId client_id,
+               ui::mojom::WindowDataPtr root,
+               ui::mojom::WindowTreePtr tree,
+               int64_t display_id,
+               ui::Id focused_window_id,
+               bool drawn) override;
+  void OnEmbeddedAppDisconnected(ui::Id window_id) override;
+  void OnUnembed(ui::Id window_id) override;
+  void OnCaptureChanged(ui::Id new_capture_window_id,
+                        ui::Id old_capture_window_id) override;
+  void OnTopLevelCreated(uint32_t change_id,
+                         ui::mojom::WindowDataPtr data,
+                         int64_t display_id,
+                         bool drawn) override;
+  void OnWindowBoundsChanged(ui::Id window_id,
+                             const gfx::Rect& old_bounds,
+                             const gfx::Rect& new_bounds) override;
+  void OnClientAreaChanged(
+      uint32_t window_id,
+      const gfx::Insets& new_client_area,
+      const std::vector<gfx::Rect>& new_additional_client_areas) override;
+  void OnTransientWindowAdded(uint32_t window_id,
+                              uint32_t transient_window_id) override;
+  void OnTransientWindowRemoved(uint32_t window_id,
+                                uint32_t transient_window_id) override;
+  void OnWindowHierarchyChanged(
+      ui::Id window_id,
+      ui::Id old_parent_id,
+      ui::Id new_parent_id,
+      std::vector<ui::mojom::WindowDataPtr> windows) override;
+  void OnWindowReordered(ui::Id window_id,
+                         ui::Id relative_window_id,
+                         ui::mojom::OrderDirection direction) override;
+  void OnWindowDeleted(ui::Id window_id) override;
+  void OnWindowVisibilityChanged(ui::Id window_id, bool visible) override;
+  void OnWindowOpacityChanged(ui::Id window_id,
+                              float old_opacity,
+                              float new_opacity) override;
+  void OnWindowParentDrawnStateChanged(ui::Id window_id, bool drawn) override;
+  void OnWindowSharedPropertyChanged(
+      ui::Id window_id,
+      const std::string& name,
+      const base::Optional<std::vector<uint8_t>>& new_data) override;
+  void OnWindowInputEvent(uint32_t event_id,
+                          ui::Id window_id,
+                          std::unique_ptr<ui::Event> event,
+                          bool matches_pointer_watcher) override;
+  void OnPointerEventObserved(std::unique_ptr<ui::Event> event,
+                              uint32_t window_id) override;
+  void OnWindowFocused(ui::Id focused_window_id) override;
+  void OnWindowPredefinedCursorChanged(ui::Id window_id,
+                                       ui::mojom::Cursor cursor) override;
+  void OnWindowSurfaceChanged(ui::Id window_id,
+                              const cc::SurfaceInfo& surface_info) override;
+  void OnDragDropStart(
+      const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data)
+      override;
+  void OnDragEnter(ui::Id window_id,
+                   uint32_t event_flags,
+                   const gfx::Point& position,
+                   uint32_t effect_bitmask,
+                   const OnDragEnterCallback& callback) override;
+  void OnDragOver(ui::Id window_id,
+                  uint32_t event_flags,
+                  const gfx::Point& position,
+                  uint32_t effect_bitmask,
+                  const OnDragOverCallback& callback) override;
+  void OnDragLeave(ui::Id window_id) override;
+  void OnCompleteDrop(ui::Id window_id,
+                      uint32_t event_flags,
+                      const gfx::Point& position,
+                      uint32_t effect_bitmask,
+                      const OnCompleteDropCallback& callback) override;
+  void OnPerformDragDropCompleted(uint32_t window,
+                                  bool success,
+                                  uint32_t action_taken) override;
+  void OnDragDropDone() override;
+  void OnChangeCompleted(uint32_t change_id, bool success) override;
+  void RequestClose(uint32_t window_id) override;
+  void GetWindowManager(
+      mojo::AssociatedInterfaceRequest<ui::mojom::WindowManager> internal)
+      override;
+
+  const int routing_id_;
+  ui::Id root_window_id_;
+  ui::mojom::WindowTreePtr tree_;
+  std::unique_ptr<ui::WindowCompositorFrameSinkBinding> pending_frame_sink_;
+  mojo::Binding<ui::mojom::WindowTreeClient> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(RendererWindowTreeClient);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_RENDERER_MUS_RENDERER_WINDOW_TREE_CLIENT_H_
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index e374de41..791b768e 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -199,8 +199,8 @@
 #endif
 
 #include "content/public/common/service_manager_connection.h"
-#include "content/renderer/mus/render_widget_mus_connection.h"
 #include "content/renderer/mus/render_widget_window_tree_client_factory.h"
+#include "content/renderer/mus/renderer_window_tree_client.h"
 #include "services/ui/public/cpp/gpu/gpu.h"
 
 #if defined(ENABLE_IPC_FUZZER)
@@ -1894,13 +1894,12 @@
     use_software = true;
 
 #if defined(USE_AURA)
-  if (GetServiceManagerConnection() && !use_software &&
-      command_line.HasSwitch(switches::kUseMusInRenderer)) {
-    RenderWidgetMusConnection* connection =
-        RenderWidgetMusConnection::GetOrCreate(routing_id);
-    return connection->CreateCompositorFrameSink(
-        frame_sink_id, gpu_->CreateContextProvider(EstablishGpuChannelSync()),
-        GetGpuMemoryBufferManager());
+  if (!use_software && command_line.HasSwitch(switches::kUseMusInRenderer)) {
+    return RendererWindowTreeClient::Get(routing_id)
+        ->CreateCompositorFrameSink(
+            frame_sink_id,
+            gpu_->CreateContextProvider(EstablishGpuChannelSync()),
+            GetGpuMemoryBufferManager());
   }
 #endif
 
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 90a1550..3d64c0d 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -106,8 +106,7 @@
 #endif  // defined(OS_POSIX)
 
 #if defined(USE_AURA)
-#include "content/public/common/service_manager_connection.h"
-#include "content/renderer/mus/render_widget_mus_connection.h"
+#include "content/renderer/mus/renderer_window_tree_client.h"
 #endif
 
 #if defined(OS_MACOSX)
@@ -385,6 +384,12 @@
                                           ->NewRenderWidgetSchedulingState();
     render_widget_scheduling_state_->SetHidden(is_hidden_);
   }
+#if defined(USE_AURA)
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kUseMusInRenderer)) {
+    RendererWindowTreeClient::Create(routing_id_);
+  }
+#endif
 }
 
 RenderWidget::~RenderWidget() {
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index 8a57b370..77a2c78 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -222,6 +222,9 @@
     self.Flaky('conformance2/textures/image_bitmap_from_video/' +
         'tex-2d-rgba16f-rgba-half_float.html',
         ['mac', ('nvidia', 0xfe9)], bug=682834)
+    self.Fail('conformance/uniforms/' +
+        'no-over-optimization-on-uniform-array-12.html',
+        ['mac', ('nvidia', 0xfe9)], bug=684903)
 
     self.Fail('deqp/functional/gles3/framebufferblit/conversion_04.html',
         ['mac', ('nvidia', 0xfe9)], bug=483282)
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 4b00720..fcb0434 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -379,9 +379,6 @@
         ['mac', ('nvidia', 0xfe9)], bug=635081)
     self.Fail('conformance/textures/misc/tex-input-validation.html',
         ['mac', ('nvidia', 0xfe9)], bug=635081)
-    self.Fail('conformance/uniforms/' +
-        'no-over-optimization-on-uniform-array-12.html',
-        ['mac', ('nvidia', 0xfe9)], bug=684903)
 
     # Mac ASAN only
     self.Fail(
diff --git a/content/zygote/zygote_main_linux.cc b/content/zygote/zygote_main_linux.cc
index 02beffa..e1b5489 100644
--- a/content/zygote/zygote_main_linux.cc
+++ b/content/zygote/zygote_main_linux.cc
@@ -76,6 +76,10 @@
 #include <sanitizer/coverage_interface.h>
 #endif
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+#include "content/common/media/cdm_host_files.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -367,6 +371,10 @@
   InitializeWebRtcModule();
 #endif
 
+#if BUILDFLAG(ENABLE_PEPPER_CDMS)
+  CdmHostFiles::CreateGlobalInstance();
+#endif
+
   SkFontConfigInterface::SetGlobal(
       new FontConfigIPC(GetSandboxFD()))->unref();
 
diff --git a/docs/updating_clang_format_binaries.md b/docs/updating_clang_format_binaries.md
index 1915152..c030518d 100644
--- a/docs/updating_clang_format_binaries.md
+++ b/docs/updating_clang_format_binaries.md
@@ -28,7 +28,7 @@
 # [double check you have the tools you need]
 where cmake.exe  # You need to install this.
 where svn.exe  # Maybe fix with: set PATH=%PATH%;D:\src\depot_tools\svn_bin
-"c:\Program Files (x86)\Microsoft Visual Studio 12.0\vc\vcvarsall.bat" amd64_x86
+"c:\Program Files (x86)\Microsoft Visual Studio 14.0\vc\vcvarsall.bat" amd64_x86
 
 set CLANG_REV=198831  # You must change this value (see above)
 
@@ -43,8 +43,8 @@
 cd ..\..\llvm-build
 set CC=cl
 set CXX=cl
-cmake -G Ninja ..\llvm -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_CRT_RELEASE=MT \
-    -DLLVM_ENABLE_ASSERTIONS=NO -DLLVM_ENABLE_THREADS=NO \
+cmake -G Ninja ..\llvm -DCMAKE_BUILD_TYPE=Release -DLLVM_USE_CRT_RELEASE=MT ^
+    -DLLVM_ENABLE_ASSERTIONS=NO -DLLVM_ENABLE_THREADS=NO ^
     -DPYTHON_EXECUTABLE=d:\src\depot_tools\python276_bin\python.exe
 ninja clang-format
 bin\clang-format.exe --version
@@ -65,7 +65,7 @@
 cd ../../llvm-build
 
 # Option 1: with cmake
-MACOSX_DEPLOYMENT_TARGET=10.9 cmake -G Ninja  -DCMAKE_BUILD_TYPE=Release \
+MACOSX_DEPLOYMENT_TARGET=10.9 cmake -G Ninja -DCMAKE_BUILD_TYPE=Release \
     -DLLVM_ENABLE_ASSERTIONS=NO -DLLVM_ENABLE_THREADS=NO ../llvm/
 time caffeinate ninja clang-format
 strip bin/clang-format
diff --git a/ios/chrome/browser/context_menu/context_menu_egtest.mm b/ios/chrome/browser/context_menu/context_menu_egtest.mm
index 7afbc4c..398e057 100644
--- a/ios/chrome/browser/context_menu/context_menu_egtest.mm
+++ b/ios/chrome/browser/context_menu/context_menu_egtest.mm
@@ -70,8 +70,7 @@
   };
   GREYAssert(testing::WaitUntilConditionOrTimeout(
                  testing::kWaitForUIElementTimeout, condition),
-             [NSString stringWithFormat:@"Waiting for matcher %@ failed.",
-                                        contextMenuItemButton]);
+             @"Waiting for matcher %@ failed.", contextMenuItemButton);
 }
 
 // Long press on |elementId| to trigger context menu and then tap on
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
index 266f54d5..4412291 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -71,7 +71,7 @@
   };
   GREYAssert(
       testing::WaitUntilConditionOrTimeout(kWaitElementTimeout, condition),
-      [NSString stringWithFormat:@"Waiting for matcher %@ failed.", name]);
+      @"Waiting for matcher %@ failed.", name);
 }
 
 // Wait until |matcher| is accessible (not nil) and tap on it.
@@ -373,10 +373,9 @@
       histogramTester.GetHistogramSamplesSinceCreation(
           kPageLoadsBeforeEvictedTabSelected);
   int sampleSum = samples ? samples->sum() : 0;
-  GREYAssertEqual(
-      sampleSum, numberOfTabs * 2,
-      [NSString stringWithFormat:@"Expected page loads is %d, actual %d.",
-                                 numberOfTabs * 2, sampleSum]);
+  GREYAssertEqual(sampleSum, numberOfTabs * 2,
+                  @"Expected page loads is %d, actual %d.", numberOfTabs * 2,
+                  sampleSum);
 }
 
 // Tests that tabs reloaded on cold start are reported as
@@ -779,10 +778,8 @@
       histogramTester.GetHistogramSamplesSinceCreation(
           kPageLoadsBeforeEvictedTabSelected);
   int sampleSum = samples->sum();
-  GREYAssertEqual(
-      sampleSum, 1,
-      [NSString stringWithFormat:@"Expected page loads is %d, actual is %d.", 1,
-                                 sampleSum]);
+  GREYAssertEqual(sampleSum, 1, @"Expected page loads is %d, actual is %d.", 1,
+                  sampleSum);
 }
 
 // Tests that navigations are correctly reported in
@@ -826,10 +823,8 @@
       histogramTester.GetHistogramSamplesSinceCreation(
           kPageLoadsBeforeEvictedTabSelected);
   int sampleSum = samples->sum();
-  GREYAssertEqual(
-      sampleSum, 2,
-      [NSString stringWithFormat:@"Expected page loads is %d, actual %d.", 2,
-                                 sampleSum]);
+  GREYAssertEqual(sampleSum, 2, @"Expected page loads is %d, actual %d.", 2,
+                  sampleSum);
 
   FailureBlock failureBlock = ^(NSString* error) {
     GREYFail(error);
diff --git a/ios/chrome/browser/ui/authentication/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/authentication/signin_interaction_controller_egtest.mm
index 6617b7d..d827393 100644
--- a/ios/chrome/browser/ui/authentication/signin_interaction_controller_egtest.mm
+++ b/ios/chrome/browser/ui/authentication/signin_interaction_controller_egtest.mm
@@ -104,10 +104,9 @@
                                                              error:&error];
     return error == nil;
   };
-  GREYAssert(
-      testing::WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout,
-                                           condition),
-      [NSString stringWithFormat:@"Waiting for matcher %@ failed.", matcher]);
+  GREYAssert(testing::WaitUntilConditionOrTimeout(
+                 testing::kWaitForUIElementTimeout, condition),
+             @"Waiting for matcher %@ failed.", matcher);
 }
 
 // Asserts that |identity| is actually signed in to the active profile.
diff --git a/ios/chrome/browser/web/browsing_prevent_default_egtest.mm b/ios/chrome/browser/web/browsing_prevent_default_egtest.mm
index cd6e955..87a96c66 100644
--- a/ios/chrome/browser/web/browsing_prevent_default_egtest.mm
+++ b/ios/chrome/browser/web/browsing_prevent_default_egtest.mm
@@ -109,9 +109,8 @@
   chrome_test_util::AssertMainTabCount(1U);
   const GURL& currentURL =
       chrome_test_util::GetCurrentWebState()->GetVisibleURL();
-  GREYAssert(currentURL == testURL,
-             [NSString stringWithFormat:@"Page navigated unexpectedly %s",
-                                        currentURL.spec().c_str()]);
+  GREYAssert(currentURL == testURL, @"Page navigated unexpectedly %s",
+             currentURL.spec().c_str());
 }
 
 // Taps a link with onclick="event.preventDefault()" and target="_blank" and
diff --git a/ios/chrome/test/earl_grey/chrome_assertions.mm b/ios/chrome/test/earl_grey/chrome_assertions.mm
index 1088f2f..947d09ac 100644
--- a/ios/chrome/test/earl_grey/chrome_assertions.mm
+++ b/ios/chrome/test/earl_grey/chrome_assertions.mm
@@ -20,8 +20,7 @@
                  ^{
                    return GetMainTabCount() == expected_tab_count;
                  }),
-             [NSString stringWithFormat:@"Did not receive %" PRIuNS " tabs",
-                                        expected_tab_count]);
+             @"Did not receive %" PRIuNS " tabs", expected_tab_count);
 }
 
 void AssertIncognitoTabCount(NSUInteger expected_tab_count) {
@@ -30,11 +29,9 @@
   ConditionBlock condition = ^{
     return GetIncognitoTabCount() == expected_tab_count;
   };
-  GREYAssert(
-      testing::WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout,
-                                           condition),
-      [NSString stringWithFormat:@"Did not receive %" PRIuNS " incognito tabs",
-                                 expected_tab_count]);
+  GREYAssert(testing::WaitUntilConditionOrTimeout(
+                 testing::kWaitForUIElementTimeout, condition),
+             @"Did not receive %" PRIuNS " incognito tabs", expected_tab_count);
 }
 
 }  // namespace chrome_test_util
diff --git a/ios/chrome/test/earl_grey/chrome_earl_grey.mm b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
index c29a73f..16ec1cf0 100644
--- a/ios/chrome/test/earl_grey/chrome_earl_grey.mm
+++ b/ios/chrome/test/earl_grey/chrome_earl_grey.mm
@@ -87,10 +87,8 @@
   BOOL success =
       web::test::TapWebViewElementWithId(chrome_test_util::GetCurrentWebState(),
                                          base::SysNSStringToUTF8(elementID));
-  GREYAssertTrue(
-      success,
-      [NSString stringWithFormat:@"Failed to tap web view element with ID: %@",
-                                 elementID]);
+  GREYAssertTrue(success, @"Failed to tap web view element with ID: %@",
+                 elementID);
 }
 
 @end
diff --git a/ios/third_party/earl_grey/BUILD.gn b/ios/third_party/earl_grey/BUILD.gn
index be7a6f68..90314bb 100644
--- a/ios/third_party/earl_grey/BUILD.gn
+++ b/ios/third_party/earl_grey/BUILD.gn
@@ -28,6 +28,8 @@
     "src/EarlGrey/Action/GREYPathGestureUtils.m",
     "src/EarlGrey/Action/GREYPickerAction.h",
     "src/EarlGrey/Action/GREYPickerAction.m",
+    "src/EarlGrey/Action/GREYPinchAction.h",
+    "src/EarlGrey/Action/GREYPinchAction.m",
     "src/EarlGrey/Action/GREYScrollAction.h",
     "src/EarlGrey/Action/GREYScrollAction.m",
     "src/EarlGrey/Action/GREYScrollActionError.h",
@@ -97,6 +99,7 @@
     "src/EarlGrey/Assertion/GREYAssertions.m",
     "src/EarlGrey/Common/GREYAnalytics.h",
     "src/EarlGrey/Common/GREYAnalytics.m",
+    "src/EarlGrey/Common/GREYAnalyticsDelegate.h",
     "src/EarlGrey/Common/GREYConfiguration.h",
     "src/EarlGrey/Common/GREYConfiguration.m",
     "src/EarlGrey/Common/GREYConstants.h",
@@ -104,16 +107,36 @@
     "src/EarlGrey/Common/GREYDefines.h",
     "src/EarlGrey/Common/GREYElementHierarchy.h",
     "src/EarlGrey/Common/GREYElementHierarchy.m",
+    "src/EarlGrey/Common/GREYError+Internal.h",
+    "src/EarlGrey/Common/GREYError.h",
+    "src/EarlGrey/Common/GREYError.m",
     "src/EarlGrey/Common/GREYExposed.h",
-    "src/EarlGrey/Common/GREYPrivate.h",
+    "src/EarlGrey/Common/GREYFailureFormatter.h",
+    "src/EarlGrey/Common/GREYFailureFormatter.m",
+    "src/EarlGrey/Common/GREYFailureScreenshotter+Internal.h",
+    "src/EarlGrey/Common/GREYFailureScreenshotter.h",
+    "src/EarlGrey/Common/GREYFailureScreenshotter.m",
+    "src/EarlGrey/Common/GREYLogger.h",
+    "src/EarlGrey/Common/GREYLogger.m",
+    "src/EarlGrey/Common/GREYObjectFormatter+Internal.h",
+    "src/EarlGrey/Common/GREYObjectFormatter.h",
+    "src/EarlGrey/Common/GREYObjectFormatter.m",
+    "src/EarlGrey/Common/GREYScreenshotUtil+Internal.h",
     "src/EarlGrey/Common/GREYScreenshotUtil.h",
     "src/EarlGrey/Common/GREYScreenshotUtil.m",
+    "src/EarlGrey/Common/GREYStopwatch.h",
+    "src/EarlGrey/Common/GREYStopwatch.m",
     "src/EarlGrey/Common/GREYSwizzler.h",
     "src/EarlGrey/Common/GREYSwizzler.m",
+    "src/EarlGrey/Common/GREYTestCaseInvocation.h",
+    "src/EarlGrey/Common/GREYTestCaseInvocation.m",
     "src/EarlGrey/Common/GREYTestHelper.h",
     "src/EarlGrey/Common/GREYTestHelper.m",
+    "src/EarlGrey/Common/GREYVisibilityChecker+Internal.h",
     "src/EarlGrey/Common/GREYVisibilityChecker.h",
     "src/EarlGrey/Common/GREYVisibilityChecker.m",
+    "src/EarlGrey/Common/GREYWeakObjectContainer.h",
+    "src/EarlGrey/Common/GREYWeakObjectContainer.m",
     "src/EarlGrey/Core/GREYAutomationSetup.h",
     "src/EarlGrey/Core/GREYAutomationSetup.m",
     "src/EarlGrey/Core/GREYElementFinder.h",
@@ -134,10 +157,14 @@
     "src/EarlGrey/Delegate/GREYUIWebViewDelegate.m",
     "src/EarlGrey/EarlGrey.h",
     "src/EarlGrey/EarlGrey.m",
-    "src/EarlGrey/Event/GREYSingleSequenceTouchInjector.h",
-    "src/EarlGrey/Event/GREYSingleSequenceTouchInjector.m",
     "src/EarlGrey/Event/GREYSyntheticEvents.h",
     "src/EarlGrey/Event/GREYSyntheticEvents.m",
+    "src/EarlGrey/Event/GREYTouchInfo.h",
+    "src/EarlGrey/Event/GREYTouchInfo.m",
+    "src/EarlGrey/Event/GREYTouchInjector.h",
+    "src/EarlGrey/Event/GREYTouchInjector.m",
+    "src/EarlGrey/Event/GREYZeroToleranceTimer.h",
+    "src/EarlGrey/Event/GREYZeroToleranceTimer.m",
     "src/EarlGrey/Exception/GREYDefaultFailureHandler.h",
     "src/EarlGrey/Exception/GREYDefaultFailureHandler.m",
     "src/EarlGrey/Exception/GREYFailureHandler.h",
@@ -176,6 +203,10 @@
     "src/EarlGrey/Synchronization/GREYCondition.m",
     "src/EarlGrey/Synchronization/GREYDispatchQueueIdlingResource.h",
     "src/EarlGrey/Synchronization/GREYDispatchQueueIdlingResource.m",
+    "src/EarlGrey/Synchronization/GREYDispatchQueueTracker.h",
+    "src/EarlGrey/Synchronization/GREYDispatchQueueTracker.m",
+    "src/EarlGrey/Synchronization/GREYManagedObjectContextIdlingResource.h",
+    "src/EarlGrey/Synchronization/GREYManagedObjectContextIdlingResource.m",
     "src/EarlGrey/Synchronization/GREYNSTimerIdlingResource.h",
     "src/EarlGrey/Synchronization/GREYNSTimerIdlingResource.m",
     "src/EarlGrey/Synchronization/GREYOperationQueueIdlingResource.h",
@@ -197,6 +228,7 @@
     "src/EarlGrey/Action/GREYActionBlock.h",
     "src/EarlGrey/Action/GREYActions.h",
     "src/EarlGrey/Action/GREYBaseAction.h",
+    "src/EarlGrey/Action/GREYPinchAction.h",
     "src/EarlGrey/Action/GREYScrollActionError.h",
     "src/EarlGrey/AppSupport/GREYIdlingResource.h",
     "src/EarlGrey/Assertion/GREYAssertion.h",
@@ -208,6 +240,7 @@
     "src/EarlGrey/Common/GREYDefines.h",
     "src/EarlGrey/Common/GREYElementHierarchy.h",
     "src/EarlGrey/Common/GREYScreenshotUtil.h",
+    "src/EarlGrey/Common/GREYStopwatch.h",
     "src/EarlGrey/Common/GREYTestHelper.h",
     "src/EarlGrey/Core/GREYElementFinder.h",
     "src/EarlGrey/Core/GREYElementInteraction.h",
@@ -225,6 +258,7 @@
     "src/EarlGrey/Matcher/GREYNot.h",
     "src/EarlGrey/Provider/GREYDataEnumerator.h",
     "src/EarlGrey/Provider/GREYProvider.h",
+    "src/EarlGrey/Synchronization/GREYManagedObjectContextIdlingResource.h",
     "src/EarlGrey/Synchronization/GREYNSTimerIdlingResource.h",
     "src/EarlGrey/Synchronization/GREYOperationQueueIdlingResource.h",
     "src/EarlGrey/Synchronization/GREYDispatchQueueIdlingResource.h",
@@ -240,10 +274,9 @@
   public_deps = [
     "//ios/third_party/ochamcrest:ochamcrest+link",
   ]
-  precompiled_header = "src/EarlGrey.pch"
-  precompiled_source = "src/EarlGrey.pch"
 
   libs = [
+    "CoreData.framework",
     "CoreGraphics.framework",
     "Foundation.framework",
     "IOKit.framework",
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 5299efe7..30431d7 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -126,6 +126,11 @@
 const char kMSEAudioBufferSizeLimit[] = "mse-audio-buffer-size-limit";
 const char kMSEVideoBufferSizeLimit[] = "mse-video-buffer-size-limit";
 
+// By default, if any CDM host (including signature) file is missing, the CDM
+// will not be called to verify the host. Enable this switch to ignore missing
+// CDM host files. This can be used in tests.
+const char kIgnoreMissingCdmHostFile[] = "ignore-missing-cdm-host-file";
+
 }  // namespace switches
 
 namespace media {
diff --git a/media/base/media_switches.h b/media/base/media_switches.h
index 781e927..7964461 100644
--- a/media/base/media_switches.h
+++ b/media/base/media_switches.h
@@ -71,6 +71,8 @@
 MEDIA_EXPORT extern const char kMSEAudioBufferSizeLimit[];
 MEDIA_EXPORT extern const char kMSEVideoBufferSizeLimit[];
 
+MEDIA_EXPORT extern const char kIgnoreMissingCdmHostFile[];
+
 }  // namespace switches
 
 namespace media {
diff --git a/media/blink/webcontentdecryptionmodulesession_impl.cc b/media/blink/webcontentdecryptionmodulesession_impl.cc
index bfb089e..e7546ffa 100644
--- a/media/blink/webcontentdecryptionmodulesession_impl.cc
+++ b/media/blink/webcontentdecryptionmodulesession_impl.cc
@@ -495,7 +495,11 @@
 void WebContentDecryptionModuleSessionImpl::OnSessionExpirationUpdate(
     base::Time new_expiry_time) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  client_->expirationChanged(new_expiry_time.ToJsTime());
+  // The check works around an issue in base::Time that converts null base::Time
+  // to |1601-01-01 00:00:00 UTC| in ToJsTime(). See http://crbug.com/679079
+  client_->expirationChanged(new_expiry_time.is_null()
+                                 ? std::numeric_limits<double>::quiet_NaN()
+                                 : new_expiry_time.ToJsTime());
 }
 
 void WebContentDecryptionModuleSessionImpl::OnSessionClosed() {
diff --git a/media/cdm/cdm_paths.cc b/media/cdm/cdm_paths.cc
index 7caeff1..b72daea 100644
--- a/media/cdm/cdm_paths.cc
+++ b/media/cdm/cdm_paths.cc
@@ -13,6 +13,15 @@
 // Name of the ClearKey CDM library.
 const char kClearKeyCdmLibraryName[] = "clearkeycdm";
 
+const char kClearKeyCdmAdapterFileName[] =
+#if defined(OS_MACOSX)
+    "clearkeycdmadapter.plugin";
+#elif defined(OS_WIN)
+    "clearkeycdmadapter.dll";
+#elif defined(OS_POSIX)
+    "libclearkeycdmadapter.so";
+#endif
+
 // Note: This file must be in sync with cdm_paths.gni.
 // TODO(xhwang): Improve how we enable platform specific path. See
 // http://crbug.com/468584
diff --git a/media/cdm/cdm_paths.h b/media/cdm/cdm_paths.h
index 8ae6fe05..6060729 100644
--- a/media/cdm/cdm_paths.h
+++ b/media/cdm/cdm_paths.h
@@ -14,6 +14,9 @@
 // Name of the ClearKey CDM library.
 extern const char kClearKeyCdmLibraryName[];
 
+// Platform-specific filename relative to kClearKeyCdmBaseDirectory.
+extern const char kClearKeyCdmAdapterFileName[];
+
 // Returns the path of a CDM relative to DIR_COMPONENTS.
 // On platforms where a platform specific path is used, returns
 //   |cdm_base_path|/_platform_specific/<platform>_<arch>
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 4820555..54efa56 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/files/file.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/time/time.h"
@@ -18,6 +19,7 @@
 #include "media/base/cdm_key_information.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
+#include "media/cdm/api/content_decryption_module_ext.h"
 #include "media/cdm/json_web_key.h"
 #include "media/cdm/ppapi/cdm_file_io_test.h"
 #include "media/cdm/ppapi/external_clear_key/cdm_video_decoder.h"
@@ -64,6 +66,8 @@
     "org.chromium.externalclearkey.platformverificationtest";
 const char kExternalClearKeyCrashKeySystem[] =
     "org.chromium.externalclearkey.crash";
+const char kExternalClearKeyVerifyCdmHostTestKeySystem[] =
+    "org.chromium.externalclearkey.verifycdmhosttest";
 
 // Constants for the enumalted session that can be loaded by LoadSession().
 // These constants need to be in sync with
@@ -234,7 +238,8 @@
       key_system_string != kExternalClearKeyFileIOTestKeySystem &&
       key_system_string != kExternalClearKeyOutputProtectionTestKeySystem &&
       key_system_string != kExternalClearKeyPlatformVerificationTestKeySystem &&
-      key_system_string != kExternalClearKeyCrashKeySystem) {
+      key_system_string != kExternalClearKeyCrashKeySystem &&
+      key_system_string != kExternalClearKeyVerifyCdmHostTestKeySystem) {
     DVLOG(1) << "Unsupported key system:" << key_system_string;
     return NULL;
   }
@@ -256,6 +261,42 @@
   return kClearKeyCdmVersion;
 }
 
+static bool g_verify_host_files_result = false;
+
+// Makes sure files and corresponding signature files are readable but not
+// writable.
+bool VerifyCdmHost_0(const cdm::HostFile* host_files, uint32_t num_files) {
+  DVLOG(1) << __func__;
+
+  // We should always have the CDM and CDM adapter.
+  // We might not have any common CDM host file (e.g. chrome) since we are
+  // running in browser_tests.
+  if (num_files < 2) {
+    LOG(ERROR) << "Too few host files: " << num_files;
+    g_verify_host_files_result = false;
+    return true;
+  }
+
+  for (uint32_t i = 0; i < num_files; ++i) {
+    const int kBytesToRead = 10;
+    std::vector<char> buffer(kBytesToRead);
+
+    base::File file(static_cast<base::PlatformFile>(host_files[i].file));
+    int bytes_read = file.Read(0, buffer.data(), buffer.size());
+    if (bytes_read != kBytesToRead) {
+      LOG(ERROR) << "File bytes read: " << bytes_read;
+      g_verify_host_files_result = false;
+      return true;
+    }
+
+    // TODO(xhwang): Check that the files are not writable.
+    // TODO(xhwang): Also verify the signature file when it's available.
+  }
+
+  g_verify_host_files_result = true;
+  return true;
+}
+
 namespace media {
 
 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host,
@@ -317,6 +358,8 @@
   } else if (key_system_ ==
              kExternalClearKeyPlatformVerificationTestKeySystem) {
     StartPlatformVerificationTest();
+  } else if (key_system_ == kExternalClearKeyVerifyCdmHostTestKeySystem) {
+    VerifyCdmHostTest();
   }
 }
 
@@ -982,4 +1025,10 @@
                                challenge.data(), challenge.size());
 }
 
+void ClearKeyCdm::VerifyCdmHostTest() {
+  // VerifyCdmHost() should have already been called and test result stored
+  // in |g_verify_host_files_result|.
+  OnUnitTestComplete(g_verify_host_files_result);
+}
+
 }  // namespace media
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
index a16559d..a410aee 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -153,6 +153,8 @@
   // Keep track of the last session created.
   void SetSessionId(const std::string& session_id);
 
+  void VerifyCdmHostTest();
+
   scoped_refptr<AesDecryptor> decryptor_;
 
   ClearKeyCdmHost* host_;
diff --git a/media/test/data/eme_player_js/globals.js b/media/test/data/eme_player_js/globals.js
index 2d80031..81e344e1 100644
--- a/media/test/data/eme_player_js/globals.js
+++ b/media/test/data/eme_player_js/globals.js
@@ -45,6 +45,8 @@
 var PLATFORM_VERIFICATION_TEST_KEYSYSTEM =
     'org.chromium.externalclearkey.platformverificationtest';
 var CRASH_TEST_KEYSYSTEM = 'org.chromium.externalclearkey.crash';
+var VERIFY_HOST_FILES_TEST_KEYSYSTEM =
+    'org.chromium.externalclearkey.verifycdmhosttest';
 
 // Key system name:value map to show on the document page.
 var KEY_SYSTEMS = {
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js
index f1dfb4e5..d5897364 100644
--- a/media/test/data/eme_player_js/player_utils.js
+++ b/media/test/data/eme_player_js/player_utils.js
@@ -213,6 +213,7 @@
       case FILE_IO_TEST_KEYSYSTEM:
       case OUTPUT_PROTECTION_TEST_KEYSYSTEM:
       case PLATFORM_VERIFICATION_TEST_KEYSYSTEM:
+      case VERIFY_HOST_FILES_TEST_KEYSYSTEM:
         return UnitTestPlayer;
       default:
         Utils.timeLog(keySystem + ' is not a known key system');
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 2df02d38..218d34b 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2514,7 +2514,7 @@
   }
 }
 
-if (use_v8_in_net && !is_android) {
+if (!is_ios && !is_android) {
   source_set("net_browser_services") {
     sources = [
       "dns/mojo_host_resolver_impl.cc",
@@ -2527,7 +2527,7 @@
     ]
 
     public_deps = [
-      ":net_with_v8",
+      ":net",
       "//base",
       "//mojo/public/cpp/bindings",
       "//net/interfaces",
diff --git a/net/proxy/proxy_resolver_v8.h b/net/proxy/proxy_resolver_v8.h
index ce22407..bebfa15 100644
--- a/net/proxy/proxy_resolver_v8.h
+++ b/net/proxy/proxy_resolver_v8.h
@@ -65,7 +65,7 @@
 
   int GetProxyForURL(const GURL& url, ProxyInfo* results, JSBindings* bindings);
 
-  // Get total/ued heap memory usage of all v8 instances used by the proxy
+  // Get total/used heap memory usage of all v8 instances used by the proxy
   // resolver.
   static size_t GetTotalHeapSize();
   static size_t GetUsedHeapSize();
diff --git a/net/proxy/proxy_service_mojo.cc b/net/proxy/proxy_service_mojo.cc
index 4c8d41e4..394bcf7 100644
--- a/net/proxy/proxy_service_mojo.cc
+++ b/net/proxy/proxy_service_mojo.cc
@@ -16,7 +16,6 @@
 #include "net/proxy/network_delegate_error_observer.h"
 #include "net/proxy/proxy_resolver_factory.h"
 #include "net/proxy/proxy_resolver_factory_mojo.h"
-#include "net/proxy/proxy_resolver_v8_tracing.h"
 #include "net/proxy/proxy_service.h"
 
 namespace net {
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index c993fa8f..4be80d7 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -993,12 +993,24 @@
   SSL_clear_mode(ssl_.get(), mode.clear_mask);
 
   // Use BoringSSL defaults, but disable HMAC-SHA256 and HMAC-SHA384 ciphers
-  // (note that SHA256 and SHA384 only select legacy CBC ciphers).
-  std::string command("ALL:!SHA256:!SHA384:!kDHE:!aPSK:!RC4");
+  // (note that SHA256 and SHA384 only select legacy CBC ciphers). Also disable
+  // DHE_RSA_WITH_AES_256_GCM_SHA384. Historically, AES_256_GCM was not
+  // supported. As DHE is being deprecated, don't add a cipher only to remove
+  // it immediately.
+  //
+  // TODO(davidben): Remove the DHE_RSA_WITH_AES_256_GCM_SHA384 exclusion when
+  // the DHEEnabled administrative policy expires.
+  std::string command(
+      "ALL:!SHA256:!SHA384:!DHE-RSA-AES256-GCM-SHA384:!aPSK:!RC4");
 
   if (ssl_config_.require_ecdhe)
     command.append(":!kRSA:!kDHE");
 
+  if (!ssl_config_.deprecated_cipher_suites_enabled) {
+    // Only offer DHE on the second handshake. https://crbug.com/538690
+    command.append(":!kDHE");
+  }
+
   // Additionally disable HMAC-SHA1 ciphers in ECDSA. These are the remaining
   // CBC-mode ECDSA ciphers.
   if (!AreLegacyECDSACiphersEnabled())
@@ -1149,6 +1161,16 @@
                                ssl_session_cache_lookup_count_, 20);
   }
 
+  // DHE is offered on the deprecated cipher fallback and then rejected
+  // afterwards. This is to aid in diagnosing connection failures because a
+  // server requires DHE ciphers.
+  //
+  // TODO(davidben): A few releases after DHE's removal, remove this logic.
+  if (!ssl_config_.dhe_enabled &&
+      SSL_CIPHER_is_DHE(SSL_get_current_cipher(ssl_.get()))) {
+    return ERR_SSL_OBSOLETE_CIPHER;
+  }
+
   // Check that if token binding was negotiated, then extended master secret
   // and renegotiation indication must also be negotiated.
   if (tb_was_negotiated_ &&
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index ec24dcb..58c7fa8 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -2596,17 +2596,34 @@
   EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
 }
 
-// Test that DHE is removed.
-TEST_F(SSLClientSocketTest, NoDHE) {
+// Test that DHE is removed but gives a dedicated error. Also test that the
+// dhe_enabled option can restore it.
+TEST_F(SSLClientSocketTest, DHE) {
   SpawnedTestServer::SSLOptions ssl_options;
   ssl_options.key_exchanges =
       SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
   ASSERT_TRUE(StartTestServer(ssl_options));
 
+  // Normal handshakes with DHE do not work, with or without DHE enabled.
   SSLConfig ssl_config;
   int rv;
   ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
   EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
+
+  ssl_config.dhe_enabled = true;
+  ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+  EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_OR_CIPHER_MISMATCH));
+
+  // Enabling deprecated ciphers gives DHE a dedicated error code.
+  ssl_config.dhe_enabled = false;
+  ssl_config.deprecated_cipher_suites_enabled = true;
+  ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+  EXPECT_THAT(rv, IsError(ERR_SSL_OBSOLETE_CIPHER));
+
+  // Enabling both deprecated ciphers and DHE restores it.
+  ssl_config.dhe_enabled = true;
+  ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+  EXPECT_THAT(rv, IsOk());
 }
 
 // Tests that enabling deprecated ciphers shards the session cache.
@@ -2759,6 +2776,21 @@
       TestFalseStart(server_options, client_config, false));
 }
 
+// Test that False Start is disabled with DHE_RSA ciphers.
+TEST_F(SSLClientSocketFalseStartTest, DHE_RSA) {
+  SpawnedTestServer::SSLOptions server_options;
+  server_options.key_exchanges =
+      SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+  server_options.bulk_ciphers =
+      SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
+  server_options.alpn_protocols.push_back("http/1.1");
+  SSLConfig client_config;
+  client_config.alpn_protos.push_back(kProtoHTTP11);
+  // DHE is only advertised when deprecated ciphers are enabled.
+  client_config.deprecated_cipher_suites_enabled = true;
+  ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, false));
+}
+
 // Test that False Start is disabled without an AEAD.
 TEST_F(SSLClientSocketFalseStartTest, NoAEAD) {
   SpawnedTestServer::SSLOptions server_options;
diff --git a/net/ssl/ssl_config.cc b/net/ssl/ssl_config.cc
index 62e192e1..3275ac4 100644
--- a/net/ssl/ssl_config.cc
+++ b/net/ssl/ssl_config.cc
@@ -27,6 +27,7 @@
       version_min(kDefaultSSLVersionMin),
       version_max(kDefaultSSLVersionMax),
       deprecated_cipher_suites_enabled(false),
+      dhe_enabled(false),
       channel_id_enabled(true),
       false_start_enabled(true),
       signed_cert_timestamps_enabled(true),
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index 1188a0d..0cc7f552 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -103,11 +103,11 @@
   // to them as far as downgrades are concerned, so this should only be used for
   // measurement of ciphers not to be carried long-term. It is no fix for
   // servers with bad configurations without full removal.
-  //
-  // TODO(davidben): This is no longer used. Remove
-  // it. https://crbug.com/684730.
   bool deprecated_cipher_suites_enabled;
 
+  // Enables DHE cipher suites.
+  bool dhe_enabled;
+
   bool channel_id_enabled;   // True if TLS channel ID extension is enabled.
 
   // List of Token Binding key parameters supported by the client. If empty,
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index ebebfac..58076877 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -8875,6 +8875,31 @@
   EXPECT_EQ(kOriginHeaderValue, received_cors_header);
 }
 
+// Test that DHE-only servers fail with the expected dedicated error code.
+TEST_F(HTTPSRequestTest, DHE) {
+  SpawnedTestServer::SSLOptions ssl_options;
+  ssl_options.key_exchanges =
+      SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS, ssl_options,
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  ASSERT_TRUE(test_server.Start());
+
+  TestDelegate d;
+  {
+    std::unique_ptr<URLRequest> r(default_context_.CreateRequest(
+        test_server.GetURL("/defaultresponse"), DEFAULT_PRIORITY, &d));
+
+    r->Start();
+    EXPECT_TRUE(r->is_pending());
+
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.response_started_count());
+    EXPECT_EQ(ERR_SSL_OBSOLETE_CIPHER, d.request_status());
+  }
+}
+
 namespace {
 
 class SSLClientAuthTestDelegate : public TestDelegate {
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index aa796a76..89ee890 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -761,6 +761,8 @@
 
 crbug.com/636239 [ Win7 ] media/video-zoom-controls.html [ Failure ]
 
+crbug.com/684923 inspector/sources/debugger-async/async-callstack-promises.html [ NeedsManualRebaseline ]
+
 crbug.com/432129 fast/html/marquee-scroll.html [ Failure Pass ]
 crbug.com/326139 crbug.com/390125 media/video-frame-accurate-seek.html [ Failure Pass ]
 crbug.com/248938 virtual/threaded/animations/animation-iteration-event-destroy-renderer.html [ Pass Timeout ]
@@ -1914,7 +1916,6 @@
 crbug.com/626703 external/wpt/workers/opaque-origin.html [ Failure Crash ]
 
 # Other untriaged test failures, timeouts and crashes from newly-imported WPT tests.
-crbug.com/626703 external/wpt/dom/events/Event-dispatch-click.html [ Timeout Crash ]
 crbug.com/666703 external/wpt/html/browsers/sandboxing/sandbox-disallow-same-origin.html [ Timeout ]
 crbug.com/626703 external/wpt/fullscreen/api/element-request-fullscreen-two-iframes-manual.html [ Timeout ]
 crbug.com/626703 external/wpt/html/dom/documents/dom-tree-accessors/Document.currentScript.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/floating-self-painting-frame-complex-expected.html b/third_party/WebKit/LayoutTests/compositing/iframes/floating-self-painting-frame-complex-expected.html
new file mode 100644
index 0000000..5ab2433
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/floating-self-painting-frame-complex-expected.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<iframe style="width: 400px; height: 500px"
+  srcdoc="<div style='width: 300px; height:400px; background: blue'></div>"></iframe>
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/floating-self-painting-frame-complex.html b/third_party/WebKit/LayoutTests/compositing/iframes/floating-self-painting-frame-complex.html
new file mode 100644
index 0000000..2a32bc7c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/floating-self-painting-frame-complex.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="../../resources/run-after-layout-and-paint.js"></script>
+<!-- This is similar to floating-self-painting-frame.html, but contains multiple
+containing blocks and sibling blocks in which the floating objects overhangs
+and intrudes. Tests shouldPaint flag is set on at most one ancestor containing
+block. Passes if no crash (on display items with duplicated ids because the
+iframe would be painted multiple times). -->
+<style>div {height: 100px; background-color: white;}</style>
+<div>
+  <div>
+    <div>
+      <iframe id="target" style="float: left; width: 400px; height: 100px"
+         srcdoc="<div style='width: 300px; height:400px; background: blue'></div>"></iframe>
+      <div></div>
+      <div></div>
+    </div>
+  </div>
+</div>
+<script>
+if (window.internals)
+  window.internals.settings.setPreferCompositingToLCDTextEnabled(true);
+runAfterLayoutAndPaint(function() {
+  target.style.height = "500px";
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-dispatch-click-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-dispatch-click-expected.txt
new file mode 100644
index 0000000..5928c6a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/dom/events/Event-dispatch-click-expected.txt
@@ -0,0 +1,17 @@
+This is a testharness.js-based test.
+PASS basic with click() 
+PASS basic with dispatchEvent() 
+PASS basic with wrong event class 
+PASS look at parents only when event bubbles 
+FAIL look at parents when event bubbles assert_true: expected true got false
+FAIL pick the first with activation behavior <input type=checkbox> assert_true: child pre-click must be triggered expected true got false
+PASS pick the first with activation behavior <a href> 
+PASS event state during post-click handling 
+PASS redispatch during post-click handling 
+PASS disabled checkbox still has activation behavior 
+PASS disabled checkbox still has activation behavior, part 2 
+PASS disconnected checkbox should be checked 
+PASS disconnected radio should be checked 
+FAIL disconnected form should not submit assert_false: expected false got true
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
index 51857652..5765c5d 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/debugger-test.js
@@ -104,12 +104,14 @@
 
 InspectorTest.runAsyncCallStacksTest = function(totalDebuggerStatements, maxAsyncCallStackDepth)
 {
+    var defaultMaxAsyncCallStackDepth = 8;
+
     InspectorTest.setQuiet(true);
     InspectorTest.startDebuggerTest(step1);
 
     function step1()
     {
-        InspectorTest.DebuggerAgent.setAsyncCallStackDepth(maxAsyncCallStackDepth, step2);
+        InspectorTest.DebuggerAgent.setAsyncCallStackDepth(maxAsyncCallStackDepth || defaultMaxAsyncCallStackDepth, step2);
     }
 
     function step2()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html
index 5482979..b0247c5 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html
@@ -23,8 +23,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 2;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-network-initiator.html b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-network-initiator.html
index e7bd3abca..227ea8c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-network-initiator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-network-initiator.html
@@ -31,7 +31,7 @@
 
 var test = function()
 {
-    var maxAsyncCallStackDepth = 4;
+    var maxAsyncCallStackDepth = 8;
     var numberOfConsoleMessages = 2;
 
     InspectorTest.setQuiet(true);
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check-expected.txt b/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check-expected.txt
index bdb496b..ae83a282 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check-expected.txt
@@ -13,7 +13,7 @@
 frontend: {"id":<number>,"method":"Page.configureOverlay","params":{"suspended":false}}
 frontend: {"id":<number>,"method":"Debugger.enable"}
 frontend: {"id":<number>,"method":"Debugger.setPauseOnExceptions","params":{"state":"none"}}
-frontend: {"id":<number>,"method":"Debugger.setAsyncCallStackDepth","params":{"maxDepth":4}}
+frontend: {"id":<number>,"method":"Debugger.setAsyncCallStackDepth","params":{"maxDepth":8}}
 frontend: {"id":<number>,"method":"DOM.enable"}
 frontend: {"id":<number>,"method":"CSS.enable"}
 frontend: {"id":<number>,"method":"Target.setAutoAttach","params":{"autoAttach":true,"waitForDebuggerOnStart":true}}
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html
index e6b33037..a51fd15 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await1.html
@@ -96,8 +96,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 4;
-    var maxAsyncCallStackDepth = 5;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html
index d87dd494..25a5011c 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await2.html
@@ -92,8 +92,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 6;
-    var maxAsyncCallStackDepth = 5;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html
index 77b73e4..8988715 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-await/async-callstack-async-await3.html
@@ -133,8 +133,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 5;
-    var maxAsyncCallStackDepth = 5;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-events.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-events.html
index 05b1d1d..a67ab99 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-events.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-events.html
@@ -74,8 +74,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 4;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-expected.txt
index adb5d402..a5e235c0 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-expected.txt
@@ -71,5 +71,13 @@
     0) longTail3 (:3)
     [setTimeout]
     0) longTail4 (:4)
+    [setTimeout]
+    0) longTail5 (:5)
+    [setTimeout]
+    0) longTail6 (:6)
+    [setTimeout]
+    0) longTail7 (:7)
+    [setTimeout]
+    0) longTail8 (:8)
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-get-as-string.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-get-as-string.html
index 80bf70b2..c2afce9 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-get-as-string.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-get-as-string.html
@@ -41,8 +41,7 @@
 function test()
 {
     var totalDebuggerStatements = 2;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-in-console.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-in-console.html
index 70acff1..42841ad 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-in-console.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-in-console.html
@@ -42,7 +42,7 @@
 
 var test = function()
 {
-    var maxAsyncCallStackDepth = 4;
+    var maxAsyncCallStackDepth = 8;
     var numberOfConsoleMessages = 5;
 
     InspectorTest.setQuiet(true);
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db-expected.txt
index d433bb0..7186848 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db-expected.txt
@@ -15,6 +15,9 @@
     0) openDB (async-callstack-indexed-db.html:23)
     [setTimeout]
     0) testFunction (async-callstack-indexed-db.html:12)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) onSuccessDeleteDatabase (async-callstack-indexed-db.html:104)
@@ -30,6 +33,13 @@
     [IndexedDB]
     0) populateDB (async-callstack-indexed-db.html:52)
     1) onSuccessOpenDB (async-callstack-indexed-db.html:45)
+    [IndexedDB]
+    0) openDB (async-callstack-indexed-db.html:23)
+    [setTimeout]
+    0) testFunction (async-callstack-indexed-db.html:12)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) onSuccessDeleteItem (async-callstack-indexed-db.html:90)
@@ -44,6 +54,11 @@
     1) onSuccessOpenDB (async-callstack-indexed-db.html:45)
     [IndexedDB]
     0) openDB (async-callstack-indexed-db.html:23)
+    [setTimeout]
+    0) testFunction (async-callstack-indexed-db.html:12)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) onSuccessOpenDB (async-callstack-indexed-db.html:43)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db.html
index d6aceadd..6bd9cfe8 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-indexed-db.html
@@ -107,8 +107,7 @@
 function test()
 {
     var totalDebuggerStatements = 6;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-middle-run.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-middle-run.html
index 257b114f..a974c9b8 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-middle-run.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-middle-run.html
@@ -29,7 +29,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 3;
-    var maxAsyncCallStackDepth = 4;
+    var maxAsyncCallStackDepth = 8;
 
     InspectorTest.setQuiet(true);
     InspectorTest.startDebuggerTest(step1);
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer-expected.txt
index bc2f27c..784212e 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer-expected.txt
@@ -53,6 +53,11 @@
     [attributes]
     0) doMutations1 (async-callstack-mutation-observer.html:50)
     1) timeout1 (async-callstack-mutation-observer.html:44)
+    [setTimeout]
+    0) testFunction (async-callstack-mutation-observer.html:35)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) timeoutFromMutation (async-callstack-mutation-observer.html:70)
@@ -79,5 +84,8 @@
     1) timeout1 (async-callstack-mutation-observer.html:44)
     [setTimeout]
     0) testFunction (async-callstack-mutation-observer.html:35)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer.html
index e74b27d..4b0a23c 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-mutation-observer.html
@@ -79,8 +79,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 6;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message-expected.txt
index e0d340c9..e4c36eab 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message-expected.txt
@@ -16,6 +16,9 @@
     1) timeout (async-callstack-post-message.html:16)
     [setTimeout]
     0) testFunction (async-callstack-post-message.html:9)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) onMessageReceivedInFrame (post-message-listener.html:7)
@@ -42,6 +45,11 @@
     [postMessage]
     0) postMessageToFrame (async-callstack-post-message.html:35)
     1) timeout (async-callstack-post-message.html:16)
+    [setTimeout]
+    0) testFunction (async-callstack-post-message.html:9)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) onMessageReceivedInParent (async-callstack-post-message.html:21)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message.html
index a372623..6a9d073 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-post-message.html
@@ -38,8 +38,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 5;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises-expected.txt
index d979d19..d6fc299 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises-expected.txt
@@ -31,6 +31,13 @@
     2) chained1 (async-callstack-promises.html:110)
     [Promise.resolve]
     0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestThrowFromChain (async-callstack-promises.html:109)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
 
 Call stack:
     0) catchCallback (async-callstack-promises.html:130)
@@ -46,6 +53,14 @@
     0) promiseCallback (async-callstack-promises.html:21)
     1) timeoutPromise (async-callstack-promises.html:9)
     2) chained2 (async-callstack-promises.html:124)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:122)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
 
 Call stack:
     0) chained1 (async-callstack-promises.html:80)
@@ -77,6 +92,11 @@
     1) timeoutPromise (async-callstack-promises.html:9)
     2) doTestChainedPromises (async-callstack-promises.html:79)
     3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) chained3 (async-callstack-promises.html:86)
@@ -93,6 +113,11 @@
     1) timeoutPromise (async-callstack-promises.html:9)
     2) doTestChainedPromises (async-callstack-promises.html:79)
     3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) chained4 (async-callstack-promises.html:89)
@@ -108,6 +133,16 @@
     2) chained1 (async-callstack-promises.html:81)
     [Promise.resolve]
     0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
+    [setTimeout]
+    0) testFunction (async-callstack-promises.html:43)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Call stack:
     0) errorCallback (async-callstack-promises.html:60)
@@ -181,6 +216,17 @@
     2) chained3 (async-callstack-promises.html:87)
     [Promise.resolve]
     0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) chained1 (async-callstack-promises.html:81)
+    [Promise.resolve]
+    0) resolvePromise (async-callstack-promises.html:12)
+    [setTimeout]
+    0) promiseCallback (async-callstack-promises.html:21)
+    1) timeoutPromise (async-callstack-promises.html:9)
+    2) doTestChainedPromises (async-callstack-promises.html:79)
+    3) testFunctionTimeout (async-callstack-promises.html:50)
 
 Call stack:
     0) thenCallback (async-callstack-promises.html:55)
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises.html
index cc0120bd..e6ccf64 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-promises.html
@@ -140,8 +140,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 14;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-reload-no-crash.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-reload-no-crash.html
index 16068a07..9e22c73d 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-reload-no-crash.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-reload-no-crash.html
@@ -17,7 +17,7 @@
 
 function test()
 {
-    var maxAsyncCallStackDepth = 4;
+    var maxAsyncCallStackDepth = 8;
     InspectorTest.startDebuggerTest(step1, true);
 
     function step1()
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-scripted-scroll.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-scripted-scroll.html
index e011c61f..c7961ec 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-scripted-scroll.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-scripted-scroll.html
@@ -36,8 +36,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 2;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-set-interval.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-set-interval.html
index bca5e64..9f0cbe5 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-set-interval.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-set-interval.html
@@ -27,8 +27,7 @@
 function test()
 {
     var totalDebuggerStatements = 3;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-web-sql.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-web-sql.html
index 2b282e3..69a319b 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-web-sql.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-web-sql.html
@@ -50,8 +50,7 @@
 function test()
 {
     var totalDebuggerStatements = 5;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-xhrs.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-xhrs.html
index 34e2baf2..5efe39d 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-xhrs.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack-xhrs.html
@@ -23,7 +23,7 @@
 function sendXHR(async)
 {
     var xhr = new XMLHttpRequest();
-    xhr.onreadystatechange = function() 
+    xhr.onreadystatechange = function()
     {
         if (xhr.readyState == 4) {
             xhr.onreadystatechange = null;
@@ -69,8 +69,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 9;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack.html
index bfbdeb6..05308e27 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-async/async-callstack.html
@@ -64,8 +64,7 @@
 var test = function()
 {
     var totalDebuggerStatements = 6;
-    var maxAsyncCallStackDepth = 4;
-    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth);
+    InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements);
 }
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt
index a2c49c48..5980b95 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack-expected.txt
@@ -22,6 +22,9 @@
     5) timeout1 (frameworks-with-async-callstack.html:20)
     [setTimeout]
     0) testFunction (frameworks-with-async-callstack.html:15)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
 Printing visible call stack:
 Call stack:
@@ -33,4 +36,7 @@
     1) timeout1 (frameworks-with-async-callstack.html:20)
     [setTimeout]
     0) testFunction (frameworks-with-async-callstack.html:15)
+    [setTimeout]
+    0) scheduleTestFunction (debugger-test.js:3)
+    <... skipped remaining frames ...>
 
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack.html
index aca7f6bf..54f5403 100644
--- a/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack.html
+++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger-frameworks/frameworks-with-async-callstack.html
@@ -33,7 +33,7 @@
 function test()
 {
     var frameworkRegexString = "/framework\\.js$";
-    var maxAsyncCallStackDepth = 4;
+    var maxAsyncCallStackDepth = 8;
 
     Common.settingForTest("skipStackFramesPattern").set(frameworkRegexString);
 
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index 19c6471a..0b634d1 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -81,7 +81,7 @@
 
 }  // namespace
 
-bool needsLayoutTreeUpdate(const Node& node) {
+static bool needsLayoutTreeUpdate(const Node& node) {
   const Document& document = node.document();
   if (document.needsLayoutTreeUpdate())
     return true;
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.h b/third_party/WebKit/Source/core/editing/EditingUtilities.h
index 563e02d..4958da65 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.h
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.h
@@ -67,7 +67,6 @@
 
 // This file contains a set of helper functions used by the editing commands
 
-CORE_EXPORT bool needsLayoutTreeUpdate(const Node&);
 CORE_EXPORT bool needsLayoutTreeUpdate(const Position&);
 CORE_EXPORT bool needsLayoutTreeUpdate(const PositionInFlatTree&);
 
diff --git a/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp b/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp
index d3652e7..0b9056a2 100644
--- a/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionTemplate.cpp
@@ -285,6 +285,13 @@
   return *this;
 }
 
+template <typename Strategy>
+typename SelectionTemplate<Strategy>::Builder&
+SelectionTemplate<Strategy>::Builder::setIsHandleVisible(bool isHandleVisible) {
+  m_selection.m_isHandleVisible = isHandleVisible;
+  return *this;
+}
+
 template class CORE_TEMPLATE_EXPORT SelectionTemplate<EditingStrategy>;
 template class CORE_TEMPLATE_EXPORT
     SelectionTemplate<EditingInFlatTreeStrategy>;
diff --git a/third_party/WebKit/Source/core/editing/SelectionTemplate.h b/third_party/WebKit/Source/core/editing/SelectionTemplate.h
index 1d48c2d..78dd1843a 100644
--- a/third_party/WebKit/Source/core/editing/SelectionTemplate.h
+++ b/third_party/WebKit/Source/core/editing/SelectionTemplate.h
@@ -66,6 +66,7 @@
     Builder& setGranularity(TextGranularity);
     Builder& setHasTrailingWhitespace(bool);
     Builder& setIsDirectional(bool);
+    Builder& setIsHandleVisible(bool);
 
    private:
     SelectionTemplate m_selection;
@@ -87,6 +88,7 @@
   TextGranularity granularity() const { return m_granularity; }
   bool hasTrailingWhitespace() const { return m_hasTrailingWhitespace; }
   bool isDirectional() const { return m_isDirectional; }
+  bool isHandleVisible() const { return m_isHandleVisible; }
   bool isNone() const { return m_base.isNull(); }
 
   // Returns true if |this| selection holds valid values otherwise it causes
@@ -115,6 +117,7 @@
   TextGranularity m_granularity = CharacterGranularity;
   bool m_hasTrailingWhitespace = false;
   bool m_isDirectional = false;
+  bool m_isHandleVisible = false;
 #if DCHECK_IS_ON()
   uint64_t m_domTreeVersion;
 #endif
diff --git a/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp b/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp
index e1f9864..63abb12 100644
--- a/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionTemplateTest.cpp
@@ -18,6 +18,7 @@
   EXPECT_EQ(CharacterGranularity, selection.granularity());
   EXPECT_FALSE(selection.hasTrailingWhitespace());
   EXPECT_FALSE(selection.isDirectional());
+  EXPECT_FALSE(selection.isHandleVisible());
   EXPECT_TRUE(selection.isNone());
   EXPECT_EQ(Position(), selection.base());
   EXPECT_EQ(Position(), selection.extent());
@@ -36,6 +37,7 @@
   EXPECT_EQ(CharacterGranularity, selection.granularity());
   EXPECT_FALSE(selection.hasTrailingWhitespace());
   EXPECT_FALSE(selection.isDirectional());
+  EXPECT_FALSE(selection.isHandleVisible());
   EXPECT_FALSE(selection.isNone());
   EXPECT_EQ(position, selection.base());
   EXPECT_EQ(position, selection.extent());
@@ -56,6 +58,7 @@
   EXPECT_EQ(CharacterGranularity, selection.granularity());
   EXPECT_FALSE(selection.hasTrailingWhitespace());
   EXPECT_FALSE(selection.isDirectional());
+  EXPECT_FALSE(selection.isHandleVisible());
   EXPECT_FALSE(selection.isNone());
   EXPECT_EQ(base, selection.base());
   EXPECT_EQ(extent, selection.extent());
diff --git a/third_party/WebKit/Source/core/events/EventDispatcher.cpp b/third_party/WebKit/Source/core/events/EventDispatcher.cpp
index b2c2126..6b6592a 100644
--- a/third_party/WebKit/Source/core/events/EventDispatcher.cpp
+++ b/third_party/WebKit/Source/core/events/EventDispatcher.cpp
@@ -243,11 +243,6 @@
   // 16. Set event’s currentTarget attribute to null.
   m_event->setCurrentTarget(nullptr);
 
-  // Pass the data from the preDispatchEventHandler to the
-  // postDispatchEventHandler.
-  m_node->postDispatchEventHandler(m_event.get(),
-                                   preDispatchEventHandlerResult);
-
   bool isClick = m_event->isMouseEvent() &&
                  toMouseEvent(*m_event).type() == EventTypeNames::click;
   if (isClick) {
@@ -257,6 +252,14 @@
       cache->handleClicked(m_event->target()->toNode());
   }
 
+  // Pass the data from the preDispatchEventHandler to the
+  // postDispatchEventHandler.
+  // This may dispatch an event, and m_node and m_event might be altered.
+  m_node->postDispatchEventHandler(m_event.get(),
+                                   preDispatchEventHandlerResult);
+  // TODO(tkent): Is it safe to kick defaultEventHandler() with such altered
+  // m_event?
+
   // The DOM Events spec says that events dispatched by JS (other than "click")
   // should not have their default handlers invoked.
   bool isTrustedOrClick =
diff --git a/third_party/WebKit/Source/core/layout/FloatingObjects.cpp b/third_party/WebKit/Source/core/layout/FloatingObjects.cpp
index 27b7106..f443714 100644
--- a/third_party/WebKit/Source/core/layout/FloatingObjects.cpp
+++ b/third_party/WebKit/Source/core/layout/FloatingObjects.cpp
@@ -29,8 +29,6 @@
 #include "core/layout/LayoutView.h"
 #include "core/layout/api/LineLayoutBlockFlow.h"
 #include "core/layout/shapes/ShapeOutsideInfo.h"
-#include "core/paint/PaintLayer.h"
-#include "platform/RuntimeEnabledFeatures.h"
 #include "wtf/PtrUtil.h"
 #include <algorithm>
 #include <memory>
@@ -78,6 +76,7 @@
       m_originatingLine(nullptr),
       m_frameRect(frameRect),
       m_type(type),
+      m_shouldPaint(shouldPaint),
       m_isDescendant(isDescendant),
       m_isPlaced(true),
       m_isLowestNonOverhangingFloatInChild(isLowestNonOverhangingFloatInChild)
@@ -86,22 +85,6 @@
       m_isInPlacedTree(false)
 #endif
 {
-  m_shouldPaint = shouldPaint || shouldPaintForCompositedLayoutPart();
-}
-
-bool FloatingObject::shouldPaintForCompositedLayoutPart() {
-  // HACK: only non-self-painting floats should paint. However, due to the
-  // fundamental compositing bug, some LayoutPart objects may become
-  // self-painting due to being composited. This leads to a chicken-egg issue
-  // because layout may not depend on compositing.
-  // If this is the case, set shouldPaint() to true even if the layer is
-  // technically self-painting. This lets the float which contains a LayoutPart
-  // start painting as soon as it stops being composited, without having to
-  // re-layout the float.
-  // This hack can be removed after SPv2.
-  return m_layoutObject->layer() &&
-         m_layoutObject->layer()->isSelfPaintingOnlyBecauseIsCompositedPart() &&
-         !RuntimeEnabledFeatures::slimmingPaintV2Enabled();
 }
 
 std::unique_ptr<FloatingObject> FloatingObject::create(
@@ -111,18 +94,13 @@
 
   // If a layer exists, the float will paint itself. Otherwise someone else
   // will.
-  newObj->setShouldPaint(!layoutObject->hasSelfPaintingLayer() ||
-                         newObj->shouldPaintForCompositedLayoutPart());
+  newObj->setShouldPaint(!layoutObject->hasSelfPaintingLayer());
 
   newObj->setIsDescendant(true);
 
   return newObj;
 }
 
-bool FloatingObject::shouldPaint() const {
-  return m_shouldPaint && !m_layoutObject->hasSelfPaintingLayer();
-}
-
 std::unique_ptr<FloatingObject> FloatingObject::copyToNewContainer(
     LayoutSize offset,
     bool shouldPaint,
diff --git a/third_party/WebKit/Source/core/layout/FloatingObjects.h b/third_party/WebKit/Source/core/layout/FloatingObjects.h
index c838dd1..fb83563 100644
--- a/third_party/WebKit/Source/core/layout/FloatingObjects.h
+++ b/third_party/WebKit/Source/core/layout/FloatingObjects.h
@@ -113,7 +113,7 @@
   void setIsInPlacedTree(bool value) { m_isInPlacedTree = value; }
 #endif
 
-  bool shouldPaint() const;
+  bool shouldPaint() const { return m_shouldPaint; }
   void setShouldPaint(bool shouldPaint) { m_shouldPaint = shouldPaint; }
   bool isDescendant() const { return m_isDescendant; }
   void setIsDescendant(bool isDescendant) { m_isDescendant = isDescendant; }
@@ -139,8 +139,6 @@
                  bool isDescendant,
                  bool isLowestNonOverhangingFloatInChild);
 
-  bool shouldPaintForCompositedLayoutPart();
-
   LayoutBox* m_layoutObject;
   RootInlineBox* m_originatingLine;
   LayoutRect m_frameRect;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index f2f945d..359acb05 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -3998,7 +3998,9 @@
   for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) {
     --it;
     const FloatingObject& floatingObject = *it->get();
-    if (floatingObject.shouldPaint()) {
+    if (floatingObject.shouldPaint() &&
+        // TODO(wangxianzhu): Should this be a DCHECK?
+        !floatingObject.layoutObject()->hasSelfPaintingLayer()) {
       LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) -
                            floatingObject.layoutObject()->location().x();
       LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) -
@@ -4051,7 +4053,7 @@
   return fixedOffset;
 }
 
-void LayoutBlockFlow::setAncestorShouldPaintFloatingObject(
+void LayoutBlockFlow::updateAncestorShouldPaintFloatingObject(
     const LayoutBox& floatBox) {
   ASSERT(floatBox.isFloating());
   bool floatBoxIsSelfPaintingLayer =
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index d45ad3a0..0267305 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -718,7 +718,8 @@
     return m_floatingObjects.get();
   }
 
-  static void setAncestorShouldPaintFloatingObject(const LayoutBox& floatBox);
+  static void updateAncestorShouldPaintFloatingObject(
+      const LayoutBox& floatBox);
 
  protected:
   LayoutUnit maxPositiveMarginBefore() const {
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
index 2c1b53b..dbfd4cf 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
@@ -247,6 +247,17 @@
   layer->didUpdateCompositingInputs();
 
   m_geometryMap.popMappingsToAncestor(layer->parent());
+
+  if (layer->selfPaintingStatusChanged()) {
+    layer->clearSelfPaintingStatusChanged();
+    // If the floating object becomes non-self-painting, so some ancestor should
+    // paint it; if it becomes self-painting, it should paint itself and no
+    // ancestor should paint it.
+    if (layer->layoutObject()->isFloating()) {
+      LayoutBlockFlow::updateAncestorShouldPaintFloatingObject(
+          *layer->layoutBox());
+    }
+  }
 }
 
 #if DCHECK_IS_ON()
diff --git a/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp b/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp
index 816eaf5..0ac6dd65 100644
--- a/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/BlockFlowPainter.cpp
@@ -53,6 +53,10 @@
       continue;
 
     const LayoutBox* floatingLayoutObject = floatingObject->layoutObject();
+    // TODO(wangxianzhu): Should this be a DCHECK?
+    if (floatingLayoutObject->hasSelfPaintingLayer())
+      continue;
+
     // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make
     // this much cleaner.
     LayoutPoint childPoint = m_layoutBlockFlow.flipFloatForWritingModeForChild(
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 168383e4..8ee0faf 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -157,6 +157,7 @@
       m_hasNonIsolatedDescendantWithBlendMode(false),
       m_hasAncestorWithClipPath(false),
       m_hasRootScrollerAsDescendant(false),
+      m_selfPaintingStatusChanged(false),
       m_layoutObject(layoutObject),
       m_parent(0),
       m_previous(0),
@@ -1516,15 +1517,7 @@
 }
 
 void PaintLayer::didUpdateNeedsCompositedScrolling() {
-  bool wasSelfPaintingLayer = isSelfPaintingLayer();
   updateSelfPaintingLayer();
-
-  // If the floating object becomes non-self-painting, so some ancestor should
-  // paint it; if it becomes self-painting, it should paint itself and no
-  // ancestor should paint it.
-  if (wasSelfPaintingLayer != isSelfPaintingLayer() &&
-      m_layoutObject->isFloating())
-    LayoutBlockFlow::setAncestorShouldPaintFloatingObject(*layoutBox());
 }
 
 void PaintLayer::updateStackingNode() {
@@ -2793,22 +2786,14 @@
   return false;
 }
 
-bool PaintLayer::isSelfPaintingLayerForIntrinsicOrScrollingReasons() const {
-  return layoutObject()->layerTypeRequired() == NormalPaintLayer ||
-         (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars()) ||
-         needsCompositedScrolling();
-}
-
 bool PaintLayer::shouldBeSelfPaintingLayer() const {
   if (layoutObject()->isLayoutPart() &&
       toLayoutPart(layoutObject())->requiresAcceleratedCompositing())
     return true;
-  return isSelfPaintingLayerForIntrinsicOrScrollingReasons();
-}
 
-bool PaintLayer::isSelfPaintingOnlyBecauseIsCompositedPart() const {
-  return shouldBeSelfPaintingLayer() &&
-         !isSelfPaintingLayerForIntrinsicOrScrollingReasons();
+  return layoutObject()->layerTypeRequired() == NormalPaintLayer ||
+         (m_scrollableArea && m_scrollableArea->hasOverlayScrollbars()) ||
+         needsCompositedScrolling();
 }
 
 void PaintLayer::updateSelfPaintingLayer() {
@@ -2817,6 +2802,7 @@
     return;
 
   m_isSelfPaintingLayer = isSelfPaintingLayer;
+  m_selfPaintingStatusChanged = true;
 
   if (PaintLayer* parent = this->parent()) {
     parent->dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index f57327c..75eb3c31 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -250,10 +250,6 @@
   // FIXME: Many people call this function while it has out-of-date information.
   bool isSelfPaintingLayer() const { return m_isSelfPaintingLayer; }
 
-  // PaintLayers which represent LayoutParts may become self-painting due to
-  // being composited.  If this is the case, this method returns true.
-  bool isSelfPaintingOnlyBecauseIsCompositedPart() const;
-
   bool isTransparent() const {
     return layoutObject()->isTransparent() ||
            layoutObject()->style()->hasBlendMode() || layoutObject()->hasMask();
@@ -988,6 +984,17 @@
     return m_has3DTransformedDescendant;
   }
 
+  // Whether the value of isSelfPaintingLayer() changed since the last clearing
+  // (which happens after the flag is chedked during compositing update).
+  bool selfPaintingStatusChanged() const {
+    DCHECK(!RuntimeEnabledFeatures::slimmingPaintV2Enabled());
+    return m_selfPaintingStatusChanged;
+  }
+  void clearSelfPaintingStatusChanged() {
+    DCHECK(!RuntimeEnabledFeatures::slimmingPaintV2Enabled());
+    m_selfPaintingStatusChanged = false;
+  }
+
 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS
   void endShouldKeepAliveAllClientsRecursive();
 #endif
@@ -1115,8 +1122,6 @@
         layer.m_needsPaintPhaseDescendantBlockBackgrounds;
   }
 
-  bool isSelfPaintingLayerForIntrinsicOrScrollingReasons() const;
-
   bool shouldFragmentCompositedBounds(const PaintLayer* compositingLayer) const;
 
   void expandRectForStackingChildren(const PaintLayer& compositedLayer,
@@ -1199,6 +1204,8 @@
   unsigned m_hasAncestorWithClipPath : 1;
   unsigned m_hasRootScrollerAsDescendant : 1;
 
+  unsigned m_selfPaintingStatusChanged : 1;
+
   LayoutBoxModelObject* m_layoutObject;
 
   PaintLayer* m_parent;
diff --git a/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js
index 2aa6691..b432803 100644
--- a/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/perf_ui/FlameChart.js
@@ -249,11 +249,11 @@
   }
 
   _updateHighlight() {
-    const inDividersBar = this._lastMouseOffsetY < PerfUI.FlameChart.HeaderHeight;
+    var inDividersBar = this._lastMouseOffsetY < PerfUI.FlameChart.HeaderHeight;
     this._highlightedMarkerIndex = inDividersBar ? this._markerIndexAtPosition(this._lastMouseOffsetX) : -1;
     this._updateMarkerHighlight();
 
-    const entryIndex = this._highlightedMarkerIndex === -1 ?
+    var entryIndex = this._highlightedMarkerIndex === -1 ?
         this._coordinatesToEntryIndex(this._lastMouseOffsetX, this._lastMouseOffsetY) :
         -1;
     if (entryIndex === -1) {
@@ -320,7 +320,7 @@
     // onClick comes after dragStart and dragEnd events.
     // So if there was drag (mouse move) in the middle of that events
     // we skip the click. Otherwise we jump to the sources.
-    const clickThreshold = 5;
+    var /** @const */ clickThreshold = 5;
     if (this.maxDragOffset() > clickThreshold)
       return;
     var groupIndex = this._coordinatesToGroupIndex(event.offsetX, event.offsetY);
@@ -534,18 +534,18 @@
    * @return {number}
    */
   _markerIndexAtPosition(x) {
-    const markers = this._timelineData().markers;
+    var markers = this._timelineData().markers;
     if (!markers)
       return -1;
-    const accurracyOffsetPx = 4;
-    const time = this._cursorTime(x);
-    const leftTime = this._cursorTime(x - accurracyOffsetPx);
-    const rightTime = this._cursorTime(x + accurracyOffsetPx);
-    const left = this._markerIndexBeforeTime(leftTime);
+    var /** @const */ accurracyOffsetPx = 4;
+    var time = this._cursorTime(x);
+    var leftTime = this._cursorTime(x - accurracyOffsetPx);
+    var rightTime = this._cursorTime(x + accurracyOffsetPx);
+    var left = this._markerIndexBeforeTime(leftTime);
     var markerIndex = -1;
     var distance = Infinity;
     for (var i = left; i < markers.length && markers[i].startTime() < rightTime; i++) {
-      const nextDistance = Math.abs(markers[i].startTime() - time);
+      var nextDistance = Math.abs(markers[i].startTime() - time);
       if (nextDistance < distance) {
         markerIndex = i;
         distance = nextDistance;
@@ -701,7 +701,7 @@
 
     this._drawGroupHeaders(width, height);
     this._drawMarkers();
-    const headerHeight = this._rulerEnabled ? PerfUI.FlameChart.HeaderHeight : 0;
+    var headerHeight = this._rulerEnabled ? PerfUI.FlameChart.HeaderHeight : 0;
     PerfUI.TimelineGrid.drawCanvasGrid(context, this._calculator, 3, headerHeight);
 
     this._updateElementPosition(this._highlightElement, this._highlightedEntryIndex);
@@ -774,7 +774,7 @@
     forEachGroup.call(this, (offset, index, group) => {
       context.font = group.style.font;
       if (this._isGroupCollapsible(index) && !group.expanded || group.style.shareHeaderLine) {
-        const width = this._labelWidthForGroup(context, group) + 2;
+        var width = this._labelWidthForGroup(context, group) + 2;
         context.fillStyle = Common.Color.parse(group.style.backgroundColor).setAlpha(0.8).asString(null);
         context.fillRect(
             this._headerLeftPadding - this._headerLabelXPadding, offset + this._headerLabelYPadding, width,
@@ -888,20 +888,20 @@
       var lastDrawOffset = Infinity;
 
       for (var entryIndexOnLevel = rightIndexOnLevel; entryIndexOnLevel >= 0; --entryIndexOnLevel) {
-        const entryIndex = levelIndexes[entryIndexOnLevel];
-        const entryStartTime = entryStartTimes[entryIndex];
-        const barX = this._timeToPositionClipped(entryStartTime);
-        const entryEndTime = entryStartTime + entryTotalTimes[entryIndex];
+        var entryIndex = levelIndexes[entryIndexOnLevel];
+        var entryStartTime = entryStartTimes[entryIndex];
+        var barX = this._timeToPositionClipped(entryStartTime);
+        var entryEndTime = entryStartTime + entryTotalTimes[entryIndex];
         if (isNaN(entryEndTime) || barX >= lastDrawOffset)
           continue;
         if (entryEndTime <= timeWindowLeft)
           break;
         lastDrawOffset = barX;
-        const color = this._dataProvider.entryColor(entryIndex);
-        const endBarX = this._timeToPositionClipped(entryEndTime);
+        var color = this._dataProvider.entryColor(entryIndex);
+        var endBarX = this._timeToPositionClipped(entryEndTime);
         if (group.style.useDecoratorsForOverview && this._dataProvider.forceDecoration(entryIndex)) {
-          const unclippedBarX = this._timeToPosition(entryStartTime);
-          const barWidth = endBarX - barX;
+          var unclippedBarX = this._timeToPosition(entryStartTime);
+          var barWidth = endBarX - barX;
           context.beginPath();
           context.fillStyle = color;
           context.fillRect(barX, y, barWidth, barHeight);
@@ -1095,7 +1095,7 @@
    * @param {number} entryIndex
    */
   _updateElementPosition(element, entryIndex) {
-    const elementMinWidthPx = 2;
+    var /** @const */ elementMinWidthPx = 2;
     if (element.parentElement)
       element.remove();
     if (entryIndex === -1)
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
index 512b6f8..dd7b378 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/DebuggerModel.js
@@ -165,7 +165,7 @@
   }
 
   asyncStackTracesStateChanged() {
-    const maxAsyncStackChainDepth = 4;
+    const maxAsyncStackChainDepth = 8;
     var enabled = Common.moduleSetting('enableAsyncStackTraces').get() && this._debuggerEnabled;
     this._agent.setAsyncCallStackDepth(enabled ? maxAsyncStackChainDepth : 0);
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js b/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
index 1bc8b2fc..bfc38df 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/AdvancedSearchView.js
@@ -29,10 +29,14 @@
     this._search.setAttribute('results', '0');
     this._search.setAttribute('size', 42);
 
-    this._searchPanelElement.createChild('div', 'search-icon');
-    this._searchInputClearElement = this._searchPanelElement.createChild('div', 'search-cancel-button');
-    this._searchInputClearElement.hidden = true;
+    var searchIcon = UI.Icon.create('smallicon-search', 'search-icon');
+    this._searchPanelElement.appendChild(searchIcon);
+
+    this._searchInputClearElement = UI.Icon.create('smallicon-clear-input', 'search-cancel-button');
+    this._searchInputClearElement.classList.add('hidden');
     this._searchInputClearElement.addEventListener('click', this._onSearchInputClear.bind(this), false);
+    var cancelButtonContainer = this._searchPanelElement.createChild('div', 'search-cancel-button-container');
+    cancelButtonContainer.appendChild(this._searchInputClearElement);
 
     this._ignoreCaseLabel = UI.createCheckboxLabel(Common.UIString('Ignore case'));
     this._ignoreCaseLabel.classList.add('search-config-label');
@@ -132,7 +136,7 @@
   _onSearchInputClear() {
     this._search.value = '';
     this.focus();
-    this._searchInputClearElement.hidden = true;
+    this._searchInputClearElement.classList.add('hidden');
   }
 
   /**
@@ -319,10 +323,8 @@
   }
 
   _onInput() {
-    if (this._search.value && this._search.value.length)
-      this._searchInputClearElement.hidden = false;
-    else
-      this._searchInputClearElement.hidden = true;
+    var hasText = this._search.value && this._search.value.length;
+    this._searchInputClearElement.classList.toggle('hidden', !hasText);
   }
 
   _save() {
@@ -335,7 +337,7 @@
     this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase();
     this._regexCheckbox.checked = searchConfig.isRegex();
     if (this._search.value && this._search.value.length)
-      this._searchInputClearElement.hidden = false;
+      this._searchInputClearElement.classList.remove('hidden');
   }
 
   _onAction() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js b/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js
index 7d674651..defb82e1 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/FilePathScoreFunction.js
@@ -79,7 +79,7 @@
     }
     if (matchIndexes)
       this._restoreMatchIndexes(sequence, n, m, matchIndexes);
-    const maxDataLength = 256;
+    var maxDataLength = 256;
     return score[n * m - 1] * maxDataLength + (maxDataLength - data.length);
   }
 
@@ -89,8 +89,11 @@
    * @return {boolean}
    */
   _testWordStart(data, j) {
+    if (j === 0)
+      return true;
+
     var prevChar = data.charAt(j - 1);
-    return j === 0 || prevChar === '_' || prevChar === '-' || prevChar === '/' ||
+    return prevChar === '_' || prevChar === '-' || prevChar === '/' ||
         (data[j - 1] !== this._dataUpperCase[j - 1] && data[j] === this._dataUpperCase[j]);
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js
index 8286ee1..c8f9474 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/FilteredUISourceCodeListDelegate.js
@@ -106,8 +106,8 @@
       this._scorer = new Sources.FilePathScoreFunction(query);
     }
 
-    var url = uiSourceCode.url();
-    return score + 10 * this._scorer.score(url, null);
+    var fullDisplayName = uiSourceCode.fullDisplayName();
+    return score + 10 * this._scorer.score(fullDisplayName, null);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css b/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css
index 35eaca7b..17aad8e0 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css
+++ b/third_party/WebKit/Source/devtools/front_end/sources/sourcesSearch.css
@@ -23,13 +23,8 @@
 }
 
 .search-drawer-header .search-icon {
-    background-image: url(Images/toolbarButtonGlyphs.png);
-    background-size: 352px 168px;
-    background-position: -234px 138px;
     left: 10px;
     top: 10px;
-    width: 12px;
-    height: 12px;
     position: absolute;
 }
 
@@ -37,22 +32,14 @@
     -webkit-appearance: none;
 }
 
-.search-drawer-header .search-cancel-button {
+.search-drawer-header .search-cancel-button-container {
     position: relative;
-    left: -22px;
-    top: 9px;
 }
 
-.search-drawer-header .search-cancel-button::before {
-    content: '';
-    background-image: url(Images/toolbarButtonGlyphs.png);
-    background-size: 352px 168px;
-    left: 0;
-    top: 0;
-    width: 13px;
-    height: 13px;
-    background-position: -143px -96px;
+.search-drawer-header .search-cancel-button {
     position: absolute;
+    right: 9px;
+    top: 9px;
 }
 
 :host-context(.platform-mac) .search-drawer-header input.search-config-search {
@@ -89,16 +76,6 @@
     overflow: hidden;
 }
 
-@media (-webkit-min-device-pixel-ratio: 1.1) {
-.search-drawer-header .search-icon {
-    background-image: url(Images/toolbarButtonGlyphs_2x.png);
-}
-
-.search-drawer-header .search-cancel-button::before {
-    background-image: url(Images/toolbarButtonGlyphs_2x.png);
-}
-} /* media */
-
 .search-view .search-results {
     overflow-y: auto;
     display: flex;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
index 756c2b5..3b1cc91 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineFlameChart.js
@@ -54,7 +54,7 @@
     this._extensionColorGenerator =
         new PerfUI.FlameChart.ColorGenerator({min: 210, max: 300}, {min: 70, max: 100, count: 6}, 70, 0.7);
 
-    const defaultGroupStyle = {
+    var defaultGroupStyle = {
       padding: 4,
       height: 17,
       collapsible: true,
@@ -85,7 +85,7 @@
   entryTitle(entryIndex) {
     var entryType = this._entryType(entryIndex);
     if (entryType === Timeline.TimelineFlameChartEntryType.Event) {
-      const event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
+      var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
       if (event.phase === SDK.TracingModel.Phase.AsyncStepInto || event.phase === SDK.TracingModel.Phase.AsyncStepPast)
         return event.name + ':' + event.args['step'];
       if (event._blackboxRoot)
@@ -98,7 +98,7 @@
       return detailsText ? Common.UIString('%s (%s)', name, detailsText) : name;
     }
     if (entryType === Timeline.TimelineFlameChartEntryType.ExtensionEvent) {
-      const event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
+      var event = /** @type {!SDK.TracingModel.Event} */ (this._entryData[entryIndex]);
       return event.name;
     }
     var title = this._entryIndexToTitle[entryIndex];
@@ -401,8 +401,8 @@
   }
 
   _appendGPUEvents() {
-    const eventType = Timeline.TimelineFlameChartEntryType.Event;
-    const gpuEvents = this._model.gpuEvents();
+    var eventType = Timeline.TimelineFlameChartEntryType.Event;
+    var gpuEvents = this._model.gpuEvents();
     if (this._appendSyncEvents(gpuEvents, Common.UIString('GPU'), this._headerLevel1, eventType, false))
       ++this._currentLevel;
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js
index 4d79488..edc7062 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineNetworkFlameChart.js
@@ -153,8 +153,8 @@
    * @return {?string}
    */
   entryTitle(index) {
-    const request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (this._requests[index]);
-    const parsedURL = new Common.ParsedURL(request.url || '');
+    var request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (this._requests[index]);
+    var parsedURL = new Common.ParsedURL(request.url || '');
     return parsedURL.isValid ? `${parsedURL.displayName} (${parsedURL.host})` : request.url || null;
   }
 
@@ -181,7 +181,7 @@
    * @return {boolean}
    */
   decorateEntry(index, context, text, barX, barY, barWidth, barHeight, unclippedBarX, timeToPixelRatio) {
-    const request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (this._requests[index]);
+    var request = /** @type {!TimelineModel.TimelineModel.NetworkRequest} */ (this._requests[index]);
     if (!request.timing)
       return false;
 
@@ -193,14 +193,14 @@
       return Math.floor(unclippedBarX + (time - startTime) * timeToPixelRatio);
     }
 
-    const minBarWidthPx = 2;
-    const startTime = request.startTime;
-    const endTime = request.endTime;
-    const requestTime = request.timing.requestTime * 1000;
-    const sendStart = Math.max(timeToPixel(requestTime + request.timing.sendStart), unclippedBarX);
-    const headersEnd = Math.max(timeToPixel(requestTime + request.timing.receiveHeadersEnd), sendStart);
-    const finish = Math.max(timeToPixel(request.finishTime || endTime), headersEnd + minBarWidthPx);
-    const end = Math.max(timeToPixel(endTime), finish);
+    var /** @const */ minBarWidthPx = 2;
+    var startTime = request.startTime;
+    var endTime = request.endTime;
+    var requestTime = request.timing.requestTime * 1000;
+    var sendStart = Math.max(timeToPixel(requestTime + request.timing.sendStart), unclippedBarX);
+    var headersEnd = Math.max(timeToPixel(requestTime + request.timing.receiveHeadersEnd), sendStart);
+    var finish = Math.max(timeToPixel(request.finishTime || endTime), headersEnd + minBarWidthPx);
+    var end = Math.max(timeToPixel(endTime), finish);
 
     context.fillStyle = 'hsla(0, 100%, 100%, 0.8)';
     context.fillRect(sendStart + 0.5, barY + 0.5, headersEnd - sendStart - 0.5, barHeight - 2);
@@ -214,7 +214,7 @@
      * @param {number} y
      */
     function drawTick(begin, end, y) {
-      const tickHeightPx = 6;
+      var /** @const */ tickHeightPx = 6;
       context.moveTo(begin, y - tickHeightPx / 2);
       context.lineTo(begin, y + tickHeightPx / 2);
       context.moveTo(begin, y);
@@ -223,33 +223,33 @@
 
     context.lineWidth = 1;
     context.strokeStyle = '#ccc';
-    const lineY = Math.floor(barY + barHeight / 2) + 0.5;
-    const leftTick = Math.floor(unclippedBarX) + 0.5;
-    const rightTick = end - 0.5;
+    var lineY = Math.floor(barY + barHeight / 2) + 0.5;
+    var leftTick = Math.floor(unclippedBarX) + 0.5;
+    var rightTick = end - 0.5;
     drawTick(leftTick, sendStart, lineY);
     drawTick(rightTick, finish, lineY);
     context.stroke();
 
     if (typeof request.priority === 'string') {
-      const color = this._colorForPriority(request.priority);
+      var color = this._colorForPriority(request.priority);
       if (color) {
         context.fillStyle = color;
         context.fillRect(sendStart + 0.5, barY + 0.5, 3.5, 3.5);
       }
     }
 
-    const textStart = Math.max(sendStart, 0);
-    const textWidth = finish - textStart;
-    const minTextWidthPx = 20;
+    var textStart = Math.max(sendStart, 0);
+    var textWidth = finish - textStart;
+    var /** @const */ minTextWidthPx = 20;
     if (textWidth >= minTextWidthPx) {
       text = this.entryTitle(index) || '';
       if (request.fromServiceWorker)
         text = 'âš™ ' + text;
       if (text) {
-        const textPadding = 4;
-        const textBaseline = 5;
-        const textBaseHeight = barHeight - textBaseline;
-        const trimmedText = UI.trimTextEnd(context, text, textWidth - 2 * textPadding);
+        var /** @const */ textPadding = 4;
+        var /** @const */ textBaseline = 5;
+        var textBaseHeight = barHeight - textBaseline;
+        var trimmedText = UI.trimTextEnd(context, text, textWidth - 2 * textPadding);
         context.fillStyle = '#333';
         context.fillText(trimmedText, textStart + textPadding, barY + textBaseHeight);
       }
@@ -330,8 +330,8 @@
     var lastTimeByLevel = [];
     var maxLevel = 0;
     for (var i = 0; i < this._requests.length; ++i) {
-      const r = this._requests[i];
-      const visible = r.startTime < this._endTime && r.endTime > this._startTime;
+      var r = this._requests[i];
+      var visible = r.startTime < this._endTime && r.endTime > this._startTime;
       if (!visible) {
         this._timelineData.entryLevels[i] = -1;
         continue;
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Icon.js b/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
index ed9fda13..3d5098c 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Icon.js
@@ -116,6 +116,8 @@
   'smallicon-inline-breakpoint-conditional': {x: -160, y: -20, width: 10, height: 10, spritesheet: 'smallicons'},
   'smallicon-file': {x: -64, y: -24, width: 12, height: 14, spritesheet: 'largeicons'},
   'smallicon-file-sync': {x: -76, y: -24, width: 12, height: 14, spritesheet: 'largeicons'},
+  'smallicon-search': {x: -234, y: -30, width: 12, height: 12, spritesheet: 'largeicons'},
+  'smallicon-clear-input': {x: -143, y: -96, width: 13, height: 13, spritesheet: 'largeicons'},
 
   'largeicon-longclick-triangle': {x: -290, y: -46, width: 28, height: 24, spritesheet: 'largeicons', isMask: true},
   'largeicon-menu': {x: -192, y: -24, width: 28, height: 24, spritesheet: 'largeicons', isMask: true},
@@ -218,4 +220,6 @@
   'largeicon-navigator-frame': {x: -256, y: -144, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
   'largeicon-navigator-worker': {x: -320, y: -144, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
   'largeicon-navigator-snippet': {x: -224, y: -96, width: 32, height: 24, spritesheet: 'largeicons', isMask: true},
+  'largeicon-edit': {x: -160, y: -0, width: 28, height: 24, spritesheet: 'largeicons'},
+
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js b/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js
index 0832723..8593e998 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/ListWidget.js
@@ -117,11 +117,13 @@
     controls.createChild('div', 'controls-gradient');
     var buttons = controls.createChild('div', 'controls-buttons');
 
-    var editButton = buttons.createChild('div', 'edit-button');
+    var editButton = UI.Icon.create('largeicon-edit', 'edit-button');
+    buttons.appendChild(editButton);
     editButton.title = Common.UIString('Edit');
     editButton.addEventListener('click', onEditClicked.bind(this), false);
 
-    var removeButton = buttons.createChild('div', 'remove-button');
+    var removeButton = UI.Icon.create('largeicon-trash-bin', 'remove-button');
+    buttons.appendChild(removeButton);
     removeButton.title = Common.UIString('Remove');
     removeButton.addEventListener('click', onRemoveClicked.bind(this), false);
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css b/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css
index 6062ab7..5051019 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/listWidget.css
@@ -58,23 +58,12 @@
 
 .remove-button,
 .edit-button {
-    background-image: url(Images/toolbarButtonGlyphs.png);
-    background-size: 352px 168px;
-    width: 32px;
-    height: 24px;
     opacity: 0.5;
     cursor: pointer;
     flex: none;
     visibility: hidden;
 }
 
-@media (-webkit-min-device-pixel-ratio: 1.1) {
-.remove-button,
-.edit-button {
-    background-image: url(Images/toolbarButtonGlyphs_2x.png);
-}
-} /* media */
-
 .list-item:hover .remove-button,
 .list-item:hover .edit-button {
     visibility: visible;
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
index 46f28d6..e992b4b 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
+++ b/third_party/WebKit/Source/modules/encryptedmedia/MediaKeySession.cpp
@@ -959,9 +959,7 @@
 
   // 3. If the new expiration time is not NaN, let expiration time be the
   //    new expiration time in milliseconds since 01 January 1970 UTC.
-  //    (Note that Chromium actually passes 0 to indicate no expiry.)
-  // FIXME: Get Chromium to pass NaN.
-  if (!std::isnan(updatedExpiryTimeInMS) && updatedExpiryTimeInMS != 0.0)
+  if (!std::isnan(updatedExpiryTimeInMS))
     expirationTime = updatedExpiryTimeInMS;
 
   // 4. Set the session's expiration attribute to expiration time.
diff --git a/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations b/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations
deleted file mode 100755
index 4977505..0000000
--- a/third_party/WebKit/Tools/Scripts/update-w3c-test-expectations
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import sys
-
-from webkitpy.common import host
-from webkitpy.w3c.update_w3c_test_expectations import W3CExpectationsLineAdder
-
-if __name__ == "__main__":
-    line_adder = W3CExpectationsLineAdder(host.Host())
-    sys.exit(line_adder.run(sys.argv[1:]))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
index e4da1f0..8a1401aa 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
@@ -58,11 +58,11 @@
             _log.error('Aborting: there are unstaged baselines:')
             for path in unstaged_baselines:
                 _log.error('  %s', path)
-            return
+            return 1
 
         issue_number = self._get_issue_number(options)
         if not issue_number:
-            return
+            return 1
 
         # TODO(qyearsley): Replace this with git cl try-results to remove
         # dependency on Rietveld. See crbug.com/671684.
@@ -71,14 +71,14 @@
         if options.trigger_jobs:
             if self.trigger_jobs_for_missing_builds(builds):
                 _log.info('Please re-run webkit-patch rebaseline-cl once all pending try jobs have finished.')
-                return
+                return 1
         if not builds:
             _log.info('No builds to download baselines from.')
 
         _log.debug('Getting results for Rietveld issue %d.', issue_number)
         builds_to_results = self._fetch_results(builds)
         if builds_to_results is None:
-            return
+            return 1
 
         test_prefix_list = {}
         if args:
@@ -92,9 +92,10 @@
 
         self._log_test_prefix_list(test_prefix_list)
 
-        if options.dry_run:
-            return
-        self.rebaseline(options, test_prefix_list)
+        if not options.dry_run:
+            self.rebaseline(options, test_prefix_list)
+        return 0
+
 
     def _get_issue_number(self, options):
         """Gets the Rietveld CL number from either |options| or from the current local branch."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
index bba5489..e31cb07 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl_unittest.py
@@ -156,7 +156,8 @@
         return optparse.Values(dict(**options))
 
     def test_execute_with_issue_number_given(self):
-        self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        self.assertEqual(return_code, 0)
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
@@ -166,7 +167,8 @@
         ])
 
     def test_execute_with_no_issue_number(self):
-        self.command.execute(self.command_options(), [], self.tool)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
+        self.assertEqual(return_code, 1)
         self.assertLog(['ERROR: No issue number given and no issue for current branch. This tool requires a CL\n'
                         'to operate on; please run `git cl upload` on this branch first, or use the --issue\n'
                         'option to download baselines for another existing CL.\n'])
@@ -175,7 +177,8 @@
         git_cl = GitCL(self.tool)
         git_cl.get_issue_number = lambda: '11112222'
         self.command.git_cl = lambda: git_cl
-        self.command.execute(self.command_options(), [], self.tool)
+        return_code = self.command.execute(self.command_options(), [], self.tool)
+        self.assertEqual(return_code, 0)
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-newtest.html\n',
@@ -185,7 +188,8 @@
         ])
 
     def test_execute_with_only_changed_tests_option(self):
-        self.command.execute(self.command_options(issue=11112222, only_changed_tests=True), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222, only_changed_tests=True), [], self.tool)
+        self.assertEqual(return_code, 0)
         # svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html
         # is in the list of failed tests, but not in the list of files modified
         # in the given CL; it should be included because all_tests is set to True.
@@ -206,7 +210,8 @@
             ],
             'ignored': ['svg/dynamic-updates/SVGFEDropShadowElement-dom-stdDeviation-attr.html'],
         }))
-        self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        self.assertEqual(return_code, 0)
         self.assertLog([
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
             'INFO: Rebaselining fast/dom/prototype-taco.html\n',
@@ -219,7 +224,8 @@
         # rebaselined.
         self.tool.buildbot.set_retry_sumary_json(
             Build('MOCK Try Win', 5000), None)
-        self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        self.assertEqual(return_code, 0)
         self.assertLog([
             'WARNING: No retry summary available for build Build(builder_name=u\'MOCK Try Win\', build_number=5000).\n',
             'INFO: Rebaselining fast/dom/prototype-inheritance.html\n',
@@ -230,7 +236,8 @@
         ])
 
     def test_execute_with_trigger_jobs_option(self):
-        self.command.execute(self.command_options(issue=11112222, trigger_jobs=True), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222, trigger_jobs=True), [], self.tool)
+        self.assertEqual(return_code, 1)
         self.assertLog([
             'INFO: Triggering try jobs for:\n',
             'INFO:   MOCK Try Linux\n',
@@ -301,7 +308,8 @@
 
     def test_bails_when_one_build_is_missing_results(self):
         self.tool.buildbot.set_results(Build("MOCK Try Win", 5000), None)
-        self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        self.assertEqual(return_code, 1)
         self.assertLog([
             'ERROR: Failed to fetch results from '
             '"https://storage.googleapis.com/chromium-layout-test-archives/MOCK_Try_Win/5000/layout-test-results".\n'
@@ -312,7 +320,8 @@
     def test_bails_when_there_are_unstaged_baselines(self):
         scm = self.tool.scm()
         scm.unstaged_changes = lambda: {'third_party/WebKit/LayoutTests/my-test-expected.txt': '?'}
-        self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        return_code = self.command.execute(self.command_options(issue=11112222), [], self.tool)
+        self.assertEqual(return_code, 1)
         self.assertLog([
             'ERROR: Aborting: there are unstaged baselines:\n',
             'ERROR:   /mock-checkout/third_party/WebKit/LayoutTests/my-test-expected.txt\n',
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
index 1011896..b7cbe26 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -23,9 +23,10 @@
 from webkitpy.common.net.git_cl import GitCL
 from webkitpy.common.webkit_finder import WebKitFinder
 from webkitpy.layout_tests.models.test_expectations import TestExpectations, TestExpectationParser
-from webkitpy.w3c.update_w3c_test_expectations import W3CExpectationsLineAdder
-from webkitpy.w3c.test_copier import TestCopier
 from webkitpy.w3c.common import WPT_REPO_URL, CSS_REPO_URL, WPT_DEST_NAME, CSS_DEST_NAME
+from webkitpy.w3c.directory_owners_extractor import DirectoryOwnersExtractor
+from webkitpy.w3c.test_copier import TestCopier
+from webkitpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater
 
 # Settings for how often to check try job results and how long to wait.
 POLL_DELAY_SECONDS = 2 * 60
@@ -324,7 +325,7 @@
 
     def _upload_cl(self):
         _log.info('Uploading change list.')
-        cc_list = self.get_directory_owners_to_cc()
+        cc_list = self.get_directory_owners()
         description = self._cl_description()
         self.git_cl.run([
             'upload',
@@ -334,6 +335,14 @@
             description,
         ] + ['--cc=' + email for email in cc_list])
 
+    def get_directory_owners(self):
+        """Returns a list of email addresses of owners of changed tests."""
+        _log.info('Gathering directory owners emails to CC.')
+        changed_files = self.host.cwd().changed_files()
+        extractor = DirectoryOwnersExtractor(self.fs)
+        extractor.read_owner_map()
+        return extractor.list_owners(changed_files)
+
     def _cl_description(self):
         description = self.check_run(['git', 'log', '-1', '--format=%B'])
         build_link = self._build_link()
@@ -355,54 +364,10 @@
             return None
         return 'https://build.chromium.org/p/%s/builders/%s/builds/%s' % (master_name, builder_name, build_number)
 
-    def get_directory_owners_to_cc(self):
-        """Returns a list of email addresses to CC for the current import."""
-        _log.info('Gathering directory owners emails to CC.')
-        directory_owners_file_path = self.finder.path_from_webkit_base(
-            'Tools', 'Scripts', 'webkitpy', 'w3c', 'directory_owners.json')
-        with open(directory_owners_file_path) as data_file:
-            directory_to_owner = self.parse_directory_owners(json.load(data_file))
-        out = self.check_run(['git', 'diff', 'origin/master', '--name-only'])
-        changed_files = out.splitlines()
-        return self.generate_email_list(changed_files, directory_to_owner)
-
-    @staticmethod
-    def parse_directory_owners(decoded_data_file):
-        directory_dict = {}
-        for dict_set in decoded_data_file:
-            if dict_set['notification-email']:
-                directory_dict[dict_set['directory']] = dict_set['notification-email']
-        return directory_dict
-
-    def generate_email_list(self, changed_files, directory_to_owner):
-        """Returns a list of email addresses based on the given file list and
-        directory-to-owner mapping.
-
-        Args:
-            changed_files: A list of file paths relative to the repository root.
-            directory_to_owner: A dict mapping layout test directories to emails.
-
-        Returns:
-            A list of the email addresses to be notified for the current import.
-        """
-        email_addresses = set()
-        for file_path in changed_files:
-            test_path = self.finder.layout_test_name(file_path)
-            if test_path is None:
-                continue
-            test_dir = self.fs.dirname(test_path)
-            if test_dir in directory_to_owner:
-                address = directory_to_owner[test_dir]
-                if not re.match(r'\S+@\S+', address):
-                    _log.warning('%s appears not be an email address, skipping.', address)
-                    continue
-                email_addresses.add(address)
-        return sorted(email_addresses)
-
     def fetch_new_expectations_and_baselines(self):
         """Adds new expectations and downloads baselines based on try job results, then commits and uploads the change."""
         _log.info('Adding test expectations lines to LayoutTests/TestExpectations.')
-        line_adder = W3CExpectationsLineAdder(self.host)
+        line_adder = WPTExpectationsUpdater(self.host)
         line_adder.run()
         message = 'Update test expectations and baselines.'
         self.check_run(['git', 'commit', '-a', '-m', message])
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
index 9e5fc35..f567ad98 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer_unittest.py
@@ -11,34 +11,6 @@
 
 class TestImporterTest(unittest.TestCase):
 
-    def test_generate_email_list(self):
-        importer = TestImporter(MockHost())
-        changed_files = [
-            'third_party/WebKit/LayoutTests/foo/bar/file.html',
-            'third_party/WebKit/LayoutTests/foo/bar/otherfile.html',
-            'third_party/WebKit/LayoutTests/foo/baz/files.html',
-            'some/non-test.file',
-        ]
-        directory_to_owner = {
-            'foo/bar': 'someone@gmail.com',
-            'foo/baz': 'not an email address',
-            'foo/bat': 'noone@gmail.com',
-        }
-        self.assertEqual(
-            importer.generate_email_list(changed_files, directory_to_owner),
-            ['someone@gmail.com'])
-
-    def test_parse_directory_owners(self):
-        importer = TestImporter(MockHost())
-        data_file = [
-            {'notification-email': 'charizard@gmail.com', 'directory': 'foo/bar'},
-            {'notification-email': 'blastoise@gmail.com', 'directory': 'foo/baz'},
-            {'notification-email': '', 'directory': 'gol/bat'},
-        ]
-        self.assertEqual(
-            importer.parse_directory_owners(data_file),
-            {'foo/bar': 'charizard@gmail.com', 'foo/baz': 'blastoise@gmail.com'})
-
     def test_update_test_expectations(self):
         host = MockHost()
         host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'] = (
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
similarity index 97%
rename from third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
rename to third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
index f3ba461..3444b17 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater.py
@@ -2,13 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""A class for updating layout test expectations when updating w3c tests.
+"""Updates layout test expectations and baselines when updating w3c tests.
 
-Specifically, this class fetches results from try bots for the current CL, and:
-  1. Downloads new baseline files for any tests that can be rebaselined.
-  2. Updates the generic TestExpectations file for any other failing tests.
-
-This is used as part of the w3c test auto-import process.
+Specifically, this class fetches results from try bots for the current CL, then
+(1) downloads new baseline files for any tests that can be rebaselined, and
+(2) updates the generic TestExpectations file for any other failing tests.
 """
 
 import argparse
@@ -26,7 +24,7 @@
 MARKER_COMMENT = '# ====== New tests from w3c-test-autoroller added here ======'
 
 
-class W3CExpectationsLineAdder(object):
+class WPTExpectationsUpdater(object):
 
     def __init__(self, host):
         self.host = host
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
similarity index 77%
rename from third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py
rename to third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
index e3c1409..72cd63a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/update_w3c_test_expectations_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_expectations_updater_unittest.py
@@ -10,16 +10,15 @@
 from webkitpy.common.net.buildbot_mock import MockBuildBot
 from webkitpy.common.net.layout_test_results import LayoutTestResult, LayoutTestResults
 from webkitpy.common.net.web_mock import MockWeb
-from webkitpy.common.system.executive_mock import MockExecutive
 from webkitpy.common.system.log_testing import LoggingTestCase
 from webkitpy.layout_tests.builder_list import BuilderList
-from webkitpy.w3c.update_w3c_test_expectations import W3CExpectationsLineAdder, MARKER_COMMENT
+from webkitpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater, MARKER_COMMENT
 
 
-class UpdateW3CTestExpectationsTest(LoggingTestCase):
+class WPTExpectationsUpdaterTest(LoggingTestCase):
 
     def setUp(self):
-        super(UpdateW3CTestExpectationsTest, self).setUp()
+        super(WPTExpectationsUpdaterTest, self).setUp()
         self.host = MockHost()
         self.host.builders = BuilderList({
             'mac': {'port_name': 'test-mac'},
@@ -36,14 +35,14 @@
                 },
             },
         }))
-        line_adder = W3CExpectationsLineAdder(self.host)
-        self.assertEqual(line_adder.get_failing_results_dict(Build('mac', 123)), {})
+        updater = WPTExpectationsUpdater(self.host)
+        self.assertEqual(updater.get_failing_results_dict(Build('mac', 123)), {})
 
     def test_get_failing_results_dict_no_results(self):
         self.host.buildbot = MockBuildBot()
         self.host.buildbot.set_results(Build('mac', 123), None)
-        line_adder = W3CExpectationsLineAdder(self.host)
-        self.assertEqual(line_adder.get_failing_results_dict(Build('mac', 123)), {})
+        updater = WPTExpectationsUpdater(self.host)
+        self.assertEqual(updater.get_failing_results_dict(Build('mac', 123)), {})
 
     def test_get_failing_results_dict_some_failing_results(self):
         self.host.buildbot.set_results(Build('mac', 123), LayoutTestResults({
@@ -57,8 +56,8 @@
                 },
             },
         }))
-        line_adder = W3CExpectationsLineAdder(self.host)
-        self.assertEqual(line_adder.get_failing_results_dict(Build('mac', 123)), {
+        updater = WPTExpectationsUpdater(self.host)
+        self.assertEqual(updater.get_failing_results_dict(Build('mac', 123)), {
             'x/failing-test.html': {
                 'Mac': {
                     'actual': 'IMAGE',
@@ -69,18 +68,18 @@
         })
 
     def test_merge_same_valued_keys_all_match(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         self.assertEqual(
-            line_adder.merge_same_valued_keys({
+            updater.merge_same_valued_keys({
                 'one': {'expected': 'FAIL', 'actual': 'PASS'},
                 'two': {'expected': 'FAIL', 'actual': 'PASS'},
             }),
             {('two', 'one'): {'expected': 'FAIL', 'actual': 'PASS'}})
 
     def test_merge_same_valued_keys_one_mismatch(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         self.assertEqual(
-            line_adder.merge_same_valued_keys({
+            updater.merge_same_valued_keys({
                 'one': {'expected': 'FAIL', 'actual': 'PASS'},
                 'two': {'expected': 'FAIL', 'actual': 'TIMEOUT'},
                 'three': {'expected': 'FAIL', 'actual': 'PASS'},
@@ -91,37 +90,37 @@
             })
 
     def test_get_expectations(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         self.assertEqual(
-            line_adder.get_expectations({'expected': 'FAIL', 'actual': 'PASS'}),
+            updater.get_expectations({'expected': 'FAIL', 'actual': 'PASS'}),
             {'Pass'})
         self.assertEqual(
-            line_adder.get_expectations({'expected': 'FAIL', 'actual': 'TIMEOUT'}),
+            updater.get_expectations({'expected': 'FAIL', 'actual': 'TIMEOUT'}),
             {'Timeout'})
         self.assertEqual(
-            line_adder.get_expectations({'expected': 'TIMEOUT', 'actual': 'PASS'}),
+            updater.get_expectations({'expected': 'TIMEOUT', 'actual': 'PASS'}),
             {'Pass'})
         self.assertEqual(
-            line_adder.get_expectations({'expected': 'PASS', 'actual': 'TIMEOUT CRASH FAIL'}),
+            updater.get_expectations({'expected': 'PASS', 'actual': 'TIMEOUT CRASH FAIL'}),
             {'Crash', 'Failure', 'Timeout'})
         self.assertEqual(
-            line_adder.get_expectations({'expected': 'SLOW CRASH FAIL TIMEOUT', 'actual': 'PASS'}),
+            updater.get_expectations({'expected': 'SLOW CRASH FAIL TIMEOUT', 'actual': 'PASS'}),
             {'Pass'})
 
     def test_create_line_list_old_tests(self):
         # In this example, there are two failures that are not in w3c tests.
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         results = {
             'fake/test/path.html': {
                 'one': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
                 'two': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
             }
         }
-        self.assertEqual(line_adder.create_line_list(results), [])
+        self.assertEqual(updater.create_line_list(results), [])
 
     def test_create_line_list_new_tests(self):
         # In this example, there are unexpected non-fail results in w3c tests.
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         results = {
             'external/fake/test/path.html': {
                 'one': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
@@ -130,7 +129,7 @@
             }
         }
         self.assertEqual(
-            line_adder.create_line_list(results),
+            updater.create_line_list(results),
             [
                 'crbug.com/test [ three ] external/fake/test/path.html [ Pass ]',
                 'crbug.com/test [ two ] external/fake/test/path.html [ Timeout ]',
@@ -138,10 +137,10 @@
             ])
 
     def test_merge_dicts_with_conflict_raise_exception(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         # Both dicts here have the key "one", and the value is not equal.
         with self.assertRaises(ValueError):
-            line_adder.merge_dicts(
+            updater.merge_dicts(
                 {
                     'external/fake/test/path.html': {
                         'one': {'expected': 'FAIL', 'actual': 'PASS'},
@@ -156,7 +155,7 @@
                 })
 
     def test_merge_dicts_merges_second_dict_into_first(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         one = {
             'fake/test/path.html': {
                 'one': {'expected': 'FAIL', 'actual': 'PASS'},
@@ -176,13 +175,13 @@
             }
         }
 
-        output = line_adder.merge_dicts(one, three)
+        output = updater.merge_dicts(one, three)
         self.assertEqual(output, one)
-        output = line_adder.merge_dicts(two, three)
+        output = updater.merge_dicts(two, three)
         self.assertEqual(output, two)
 
     def test_generate_results_dict(self):
-        line_adder = W3CExpectationsLineAdder(MockHost())
+        updater = WPTExpectationsUpdater(MockHost())
         layout_test_list = [
             LayoutTestResult(
                 'test/name.html', {
@@ -192,7 +191,7 @@
                     'has_stderr': True,
                 }
             )]
-        self.assertEqual(line_adder.generate_results_dict('dummy_platform', layout_test_list), {
+        self.assertEqual(updater.generate_results_dict('dummy_platform', layout_test_list), {
             'test/name.html': {
                 'dummy_platform': {
                     'expected': 'bar',
@@ -205,10 +204,10 @@
     def test_write_to_test_expectations_with_marker_comment(self):
         expectations_path = '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'
         self.host.filesystem.files[expectations_path] = MARKER_COMMENT + '\n'
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         line_list = ['crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]']
-        line_adder.write_to_test_expectations(line_list)
-        value = line_adder.host.filesystem.read_text_file(expectations_path)
+        updater.write_to_test_expectations(line_list)
+        value = updater.host.filesystem.read_text_file(expectations_path)
         self.assertMultiLineEqual(
             value,
             (MARKER_COMMENT + '\n'
@@ -217,9 +216,9 @@
     def test_write_to_test_expectations_with_no_marker_comment(self):
         expectations_path = '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'
         self.host.filesystem.files[expectations_path] = 'crbug.com/111 [ FakePlatform ]\n'
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         line_list = ['crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]']
-        line_adder.write_to_test_expectations(line_list)
+        updater.write_to_test_expectations(line_list)
         value = self.host.filesystem.read_text_file(expectations_path)
         self.assertMultiLineEqual(
             value,
@@ -230,12 +229,12 @@
     def test_write_to_test_expectations_skips_existing_lines(self):
         expectations_path = '/mock-checkout/third_party/WebKit/LayoutTests/TestExpectations'
         self.host.filesystem.files[expectations_path] = 'crbug.com/111 dont/copy/me.html [ Failure ]\n'
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         line_list = [
             'crbug.com/111 dont/copy/me.html [ Failure ]',
             'crbug.com/222 do/copy/me.html [ Failure ]'
         ]
-        line_adder.write_to_test_expectations(line_list)
+        updater.write_to_test_expectations(line_list)
         value = self.host.filesystem.read_text_file(expectations_path)
         self.assertEqual(
             value,
@@ -248,9 +247,9 @@
         self.host.filesystem.files[expectations_path] = (
             MARKER_COMMENT + '\n'
             'crbug.com/123 [ FakePlatform ] fake/file/path.html [ Pass ]\n')
-        line_adder = W3CExpectationsLineAdder(self.host)
-        line_adder.write_to_test_expectations([])
-        value = line_adder.host.filesystem.read_text_file(expectations_path)
+        updater = WPTExpectationsUpdater(self.host)
+        updater.write_to_test_expectations([])
+        value = updater.host.filesystem.read_text_file(expectations_path)
         self.assertMultiLineEqual(
             value,
             (MARKER_COMMENT + '\n'
@@ -259,25 +258,25 @@
     def test_is_js_test_true(self):
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/foo/bar.html'] = (
             '<script src="/resources/testharness.js"></script>')
-        line_adder = W3CExpectationsLineAdder(self.host)
-        self.assertTrue(line_adder.is_js_test('foo/bar.html'))
+        updater = WPTExpectationsUpdater(self.host)
+        self.assertTrue(updater.is_js_test('foo/bar.html'))
 
     def test_is_js_test_false(self):
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/foo/bar.html'] = (
             '<script src="ref-test.html"></script>')
-        line_adder = W3CExpectationsLineAdder(self.host)
-        self.assertFalse(line_adder.is_js_test('foo/bar.html'))
+        updater = WPTExpectationsUpdater(self.host)
+        self.assertFalse(updater.is_js_test('foo/bar.html'))
 
     def test_is_js_test_non_existent_file(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
-        self.assertFalse(line_adder.is_js_test('foo/bar.html'))
+        updater = WPTExpectationsUpdater(self.host)
+        self.assertFalse(updater.is_js_test('foo/bar.html'))
 
     def test_get_test_to_rebaseline_returns_only_tests_with_failures(self):
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/external/fake/test/path.html'] = (
             '<script src="/resources/testharness.js"></script>')
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/external/other/test/path.html'] = (
             '<script src="/resources/testharness.js"></script>')
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         two = {
             'external/fake/test/path.html': {
                 'one': {'expected': 'FAIL', 'actual': 'PASS'},
@@ -285,14 +284,14 @@
                 'three': {'expected': 'FAIL', 'actual': 'PASS'},
             }
         }
-        tests_to_rebaseline, _ = line_adder.get_tests_to_rebaseline(two)
+        tests_to_rebaseline, _ = updater.get_tests_to_rebaseline(two)
         # The other test doesn't have an entry in the test results dict, so it is not listed as a test to rebaseline.
         self.assertEqual(tests_to_rebaseline, ['external/fake/test/path.html'])
 
     def test_get_test_to_rebaseline_returns_only_js_tests(self):
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/external/fake/test/path.html'] = (
             'this file does not look like a testharness JS test.')
-        line_adder = W3CExpectationsLineAdder(self.host)
+        updater = WPTExpectationsUpdater(self.host)
         two = {
             'external/fake/test/path.html': {
                 'one': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
@@ -300,7 +299,7 @@
                 'three': {'expected': 'FAIL', 'actual': 'PASS', 'bug': 'crbug.com/test'},
             }
         }
-        tests_to_rebaseline, _ = line_adder.get_tests_to_rebaseline(two)
+        tests_to_rebaseline, _ = updater.get_tests_to_rebaseline(two)
         self.assertEqual(tests_to_rebaseline, [])
 
     def test_get_tests_to_rebaseline_returns_updated_dict(self):
@@ -313,8 +312,8 @@
         test_results_dict_copy = copy.deepcopy(test_results_dict)
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/external/fake/test/path.html'] = (
             '<script src="/resources/testharness.js"></script>')
-        line_adder = W3CExpectationsLineAdder(self.host)
-        tests_to_rebaseline, modified_test_results = line_adder.get_tests_to_rebaseline(
+        updater = WPTExpectationsUpdater(self.host)
+        tests_to_rebaseline, modified_test_results = updater.get_tests_to_rebaseline(
             test_results_dict)
         self.assertEqual(tests_to_rebaseline, ['external/fake/test/path.html'])
         # The record for the builder with a timeout is kept, but not with a text mismatch,
@@ -337,8 +336,8 @@
         test_results_dict_copy = copy.deepcopy(test_results_dict)
         self.host.filesystem.files['/mock-checkout/third_party/WebKit/LayoutTests/external/fake/test/path.html'] = (
             '<script src="/resources/testharness.js"></script>')
-        line_adder = W3CExpectationsLineAdder(self.host)
-        tests_to_rebaseline, modified_test_results = line_adder.get_tests_to_rebaseline(
+        updater = WPTExpectationsUpdater(self.host)
+        tests_to_rebaseline, modified_test_results = updater.get_tests_to_rebaseline(
             test_results_dict)
         self.assertEqual(tests_to_rebaseline, ['external/fake/test/path.html'])
         # The record for the builder with a timeout is kept, but not with a text mismatch,
@@ -352,9 +351,9 @@
         self.assertEqual(test_results_dict, test_results_dict_copy)
 
     def test_run_no_issue_number(self):
-        line_adder = W3CExpectationsLineAdder(self.host)
-        line_adder.get_issue_number = lambda: 'None'
-        self.assertEqual(1, line_adder.run(args=[]))
+        updater = WPTExpectationsUpdater(self.host)
+        updater.get_issue_number = lambda: 'None'
+        self.assertEqual(1, updater.run(args=[]))
         self.assertLog(['ERROR: No issue on current branch.\n'])
 
     def test_run_no_try_results(self):
@@ -366,10 +365,10 @@
                 'try_job_results': []
             })
         })
-        line_adder = W3CExpectationsLineAdder(self.host)
-        line_adder.get_issue_number = lambda: '11112222'
-        line_adder.get_try_bots = lambda: ['test-builder-name']
-        self.assertEqual(1, line_adder.run(args=[]))
+        updater = WPTExpectationsUpdater(self.host)
+        updater.get_issue_number = lambda: '11112222'
+        updater.get_try_bots = lambda: ['test-builder-name']
+        self.assertEqual(1, updater.run(args=[]))
         self.assertEqual(
             self.host.web.urls_fetched,
             [
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
index 4cc6fb8..0f6d715 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_github.py
@@ -87,7 +87,9 @@
 
     def merge_pull_request(self, pull_request_number):
         path = '/repos/w3c/web-platform-tests/pulls/%d/merge' % pull_request_number
-        body = {}
+        body = {
+            'merge_method': 'rebase',
+        }
         data, status_code = self.request(path, method='PUT', body=body)
 
         if status_code == 200:
diff --git a/third_party/WebKit/Tools/Scripts/wpt-update-expectations b/third_party/WebKit/Tools/Scripts/wpt-update-expectations
new file mode 100755
index 0000000..82c0548
--- /dev/null
+++ b/third_party/WebKit/Tools/Scripts/wpt-update-expectations
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import sys
+
+from webkitpy.common import host
+from webkitpy.w3c.wpt_expectations_updater import WPTExpectationsUpdater
+
+
+if __name__ == "__main__":
+    updater = WPTExpectationsUpdater(host.Host())
+    sys.exit(updater.run(sys.argv[1:]))
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index c976db80..9b24ca7 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -108,6 +108,7 @@
       'CFI Linux Full': 'cfi_full_release_static',
       'Chromium Linux Goma Canary': 'release_bot',
       'Chromium Linux Goma Canary (clobber)': 'release_bot',
+      'Chromium Linux Goma Canary LocalOutputCache': 'release_bot',
       'Chromium Linux Precise Goma LinkTest': 'release_bot',
       'Chromium Linux32 Goma Canary (clobber)': 'release_bot_x86',
       'Chromium Mac 10.10 MacViews': 'mac_views_browser_release_bot',
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index 943f3f7c..8cc2d3f 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -164,7 +164,8 @@
   subdir = 'CSS'
 
 
-@benchmark.Disabled('android-webview', # http://crbug.com/593200
+@benchmark.Disabled('android', # http://crbug.com/685320
+                    'android-webview', # http://crbug.com/593200
                     'reference')  # http://crbug.com/576779
 class BlinkPerfCanvas(_BlinkPerfBenchmark):
   tag = 'canvas'
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index aaa7463..faec5d8a 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -451,6 +451,13 @@
   def Name(cls):
     return 'smoothness.pathological_mobile_sites'
 
+  @classmethod
+  def ShouldDisable(cls, possible_browser):
+    # http://crbug.com/685342
+    if possible_browser.platform.GetDeviceTypeName() == 'Nexus 7':
+      return True
+    return False
+
 
 class SmoothnessToughTextureUploadCases(_Smoothness):
   page_set = page_sets.ToughTextureUploadCasesPageSet
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index 4720a32..c568ec3 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -120,7 +120,6 @@
 
   deps = [
     ":mus",
-    ":views_mus_tests_catalog_source",
     "//base",
     "//base/test:test_support",
     "//mojo/edk/system",
@@ -139,6 +138,7 @@
   ]
 
   data_deps = [
+    ":views_mus_tests_catalog",
     "//ui/resources:ui_test_pak_data",
   ]
 }
@@ -191,6 +191,7 @@
   ]
 
   data_deps = [
+    ":views_mus_tests_catalog_copy",
     "//services/ui/ime/test_ime_driver",
     "//services/ui/test_wm",
   ]
@@ -251,6 +252,7 @@
   ]
 
   data_deps = [
+    ":views_mus_tests_catalog_copy",
     "//services/ui/test_wm",
   ]
 
@@ -291,8 +293,13 @@
   catalog_deps = [ "//mash:catalog" ]
 }
 
-catalog_cpp_source("views_mus_tests_catalog_source") {
+copy("views_mus_tests_catalog_copy") {
   testonly = true
-  catalog = ":views_mus_tests_catalog"
-  output_symbol_name = "kViewsMusTestCatalog"
+  sources = get_target_outputs(":views_mus_tests_catalog")
+  outputs = [
+    "${root_out_dir}/views_mus_tests_catalog.json",
+  ]
+  deps = [
+    ":views_mus_tests_catalog",
+  ]
 }
diff --git a/ui/views/mus/views_mus_test_suite.cc b/ui/views/mus/views_mus_test_suite.cc
index 50c0c92..57776440 100644
--- a/ui/views/mus/views_mus_test_suite.cc
+++ b/ui/views/mus/views_mus_test_suite.cc
@@ -9,7 +9,6 @@
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
-#include "base/json/json_reader.h"
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/synchronization/waitable_event.h"
@@ -36,12 +35,12 @@
 #include "ui/views/views_delegate.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 
-// Generated within the ":views_mus_tests_catalog_source" target.
-extern const char kViewsMusTestCatalog[];
-
 namespace views {
 namespace {
 
+const base::FilePath::CharType kCatalogFilename[] =
+    FILE_PATH_LITERAL("views_mus_tests_catalog.json");
+
 void EnsureCommandLineSwitch(const std::string& name) {
   base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
   if (!cmd_line->HasSwitch(name))
@@ -108,8 +107,8 @@
   ServiceManagerConnection()
       : thread_("Persistent service_manager connections"),
         ipc_thread_("IPC thread") {
-    catalog::Catalog::SetDefaultCatalogManifest(
-        base::JSONReader::Read(kViewsMusTestCatalog));
+    catalog::Catalog::LoadDefaultCatalogManifest(
+        base::FilePath(kCatalogFilename));
     mojo::edk::Init();
     ipc_thread_.StartWithOptions(
         base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
diff --git a/ui/webui/resources/html/action_link_css.html b/ui/webui/resources/html/action_link_css.html
new file mode 100644
index 0000000..94ba00e
--- /dev/null
+++ b/ui/webui/resources/html/action_link_css.html
@@ -0,0 +1,28 @@
+<!-- "action_link_css.html" replaces "action_link.css" for MD pages. -->
+<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+
+<dom-module id="action-link">
+  <template>
+    <style>
+      [is='action-link'] {
+        @apply(--cr-actionable);
+        text-decoration: none;
+      }
+
+      [is='action-link'],
+      [is='action-link']:active,
+      [is='action-link']:hover,
+      [is='action-link']:visited {
+        color: var(--google-blue-700);
+      }
+
+      [is='action-link'][disabled] {
+        color: var(--paper-grey-600);
+        cursor: default;
+        opacity: 0.65;
+        pointer-events: none;
+      }
+    </style>
+  </template>
+</dom-module>
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd
index 642e5af..9a6617c 100644
--- a/ui/webui/resources/webui_resources.grd
+++ b/ui/webui/resources/webui_resources.grd
@@ -265,6 +265,8 @@
 
       <structure name="IDR_WEBUI_HTML_ACTION_LINK"
                  file="html/action_link.html" type="chrome_html" />
+      <structure name="IDR_WEBUI_HTML_ACTION_LINK_CSS"
+                 file="html/action_link_css.html" type="chrome_html" />
       <structure name="IDR_WEBUI_HTML_ASSERT"
                  file="html/assert.html" type="chrome_html" />
       <structure name="IDR_WEBUI_HTML_PROMISE_RESOLVER"