diff --git a/DEPS b/DEPS
index 1fc4361b..865f2b3 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,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': '063ece71848fadc963cbac5c978cd48262138131',
+  'skia_revision': '802acec1876bb647aaab1bbcfd97748bba54da8f',
   # 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': '9e87a245fce674a540231fba9a5ebba64269cd42',
+  'v8_revision': 'cfa497128c3c4bf3c554010438eef876bc9bdbc0',
   # 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.
@@ -83,7 +83,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling NaCl
   # and whatever else without interference from each other.
-  'nacl_revision': '8d49f6b628879a41bac93660f27bf694e6bc7143',
+  'nacl_revision': '2eeb54c6995817a39e5c5cc0b40e26518396335f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling freetype-android
   # and whatever else without interference from each other.
@@ -454,9 +454,6 @@
     'src/third_party/httpcomponents-core':
      Var('chromium_git') + '/chromium/deps/httpcomponents-core.git' + '@' + '9f7180a96f8fa5cab23f793c14b413356d419e62',
 
-    'src/third_party/jarjar':
-     Var('chromium_git') + '/chromium/deps/jarjar.git' + '@' + '2e1ead4c68c450e0b77fe49e3f9137842b8b6920',
-
     'src/third_party/jsr-305/src':
       Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919',
 
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 3d6f6c6..d002084 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -443,6 +443,8 @@
     "browser/browser_view_renderer_client.h",
     "browser/child_frame.cc",
     "browser/child_frame.h",
+    "browser/compositor_id.cc",
+    "browser/compositor_id.h",
     "browser/deferred_gpu_command_service.cc",
     "browser/deferred_gpu_command_service.h",
     "browser/find_helper.cc",
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index 6fba589..f1b25bd3 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -334,6 +334,8 @@
         'browser/browser_view_renderer_client.h',
         'browser/child_frame.cc',
         'browser/child_frame.h',
+        'browser/compositor_id.cc',
+        'browser/compositor_id.h',
         'browser/deferred_gpu_command_service.cc',
         'browser/deferred_gpu_command_service.h',
         'browser/find_helper.cc',
diff --git a/android_webview/browser/browser_view_renderer.cc b/android_webview/browser/browser_view_renderer.cc
index a1d981e..121512c 100644
--- a/android_webview/browser/browser_view_renderer.cc
+++ b/android_webview/browser/browser_view_renderer.cc
@@ -19,6 +19,8 @@
 #include "base/trace_event/trace_event_argument.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/compositor_frame_ack.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
@@ -93,7 +95,7 @@
     : client_(client),
       ui_task_runner_(ui_task_runner),
       current_compositor_frame_consumer_(nullptr),
-      compositor_(NULL),
+      compositor_(nullptr),
       is_paused_(false),
       view_visible_(false),
       window_visible_(false),
@@ -105,8 +107,7 @@
       max_page_scale_factor_(0.f),
       on_new_picture_enable_(false),
       clear_view_(false),
-      offscreen_pre_raster_(false),
-      next_compositor_id_(1) {}
+      offscreen_pre_raster_(false) {}
 
 BrowserViewRenderer::~BrowserViewRenderer() {
   DCHECK(compositor_map_.empty());
@@ -247,10 +248,9 @@
   }
 
   std::unique_ptr<ChildFrame> child_frame = base::WrapUnique(new ChildFrame(
-      frame.output_surface_id, std::move(frame.frame),
-      GetCompositorID(compositor_), viewport_rect_for_tile_priority.IsEmpty(),
-      transform_for_tile_priority, offscreen_pre_raster_,
-      external_draw_constraints_.is_layer));
+      frame.output_surface_id, std::move(frame.frame), compositor_id_,
+      viewport_rect_for_tile_priority.IsEmpty(), transform_for_tile_priority,
+      offscreen_pre_raster_, external_draw_constraints_.is_layer));
 
   ReturnUnusedResource(
       current_compositor_frame_consumer_->PassUncommittedFrameOnUI());
@@ -304,16 +304,14 @@
     CompositorFrameConsumer* compositor_frame_consumer) {
   CompositorFrameConsumer::ReturnedResourcesMap returned_resource_map;
   compositor_frame_consumer->SwapReturnedResourcesOnUI(&returned_resource_map);
-  for (auto iterator = returned_resource_map.begin();
-       iterator != returned_resource_map.end(); iterator++) {
-    uint32_t compositor_id = iterator->first;
+  for (auto& pair : returned_resource_map) {
+    CompositorID compositor_id = pair.first;
     content::SynchronousCompositor* compositor = compositor_map_[compositor_id];
     cc::CompositorFrameAck frame_ack;
-    frame_ack.resources.swap(iterator->second.resources);
+    frame_ack.resources.swap(pair.second.resources);
 
     if (compositor && !frame_ack.resources.empty()) {
-      compositor->ReturnResources(iterator->second.output_surface_id,
-                                  frame_ack);
+      compositor->ReturnResources(pair.second.output_surface_id, frame_ack);
     }
   }
 }
@@ -467,54 +465,54 @@
   return gfx::Rect(client_->GetLocationOnScreen(), size_);
 }
 
-uint32_t BrowserViewRenderer::GetCompositorID(
-    content::SynchronousCompositor* compositor) {
-  for (auto iterator = compositor_map_.begin();
-       iterator != compositor_map_.end(); iterator++) {
-    if (iterator->second == compositor) {
-      return iterator->first;
-    }
-  }
-
-  DCHECK(false);
-  // Return an invalid ID (0), because ID starts with 1.
-  return 0;
-}
-
 void BrowserViewRenderer::DidInitializeCompositor(
-    content::SynchronousCompositor* compositor) {
+    content::SynchronousCompositor* compositor,
+    int process_id,
+    int routing_id) {
   TRACE_EVENT_INSTANT0("android_webview",
                        "BrowserViewRenderer::DidInitializeCompositor",
                        TRACE_EVENT_SCOPE_THREAD);
   DCHECK(compositor);
-  // This happens when id overflows to 0, unlikely in practice.
-  if (next_compositor_id_ == 0)
-    ++next_compositor_id_;
+  CompositorID compositor_id(process_id, routing_id);
+  // This assumes that a RenderViewHost has at most 1 synchronous compositor
+  // througout its lifetime.
+  DCHECK(compositor_map_.count(compositor_id) == 0);
+  compositor_map_[compositor_id] = compositor;
 
-  DCHECK(compositor_map_.find(next_compositor_id_) == compositor_map_.end());
-  compositor_map_[next_compositor_id_] = compositor;
-  next_compositor_id_++;
+  // At this point, the RVHChanged event for the new RVH that contains the
+  // |compositor| might have been fired already, in which case just set the
+  // current compositor with the new compositor.
+  if (!compositor_ && compositor_id.Equals(compositor_id_))
+    compositor_ = compositor;
 }
 
 void BrowserViewRenderer::DidDestroyCompositor(
-    content::SynchronousCompositor* compositor) {
+    content::SynchronousCompositor* compositor,
+    int process_id,
+    int routing_id) {
   TRACE_EVENT_INSTANT0("android_webview",
                        "BrowserViewRenderer::DidDestroyCompositor",
                        TRACE_EVENT_SCOPE_THREAD);
-  DCHECK(compositor_);
-  if (compositor_ == compositor)
+  CompositorID compositor_id(process_id, routing_id);
+  DCHECK(compositor_map_.count(compositor_id));
+  if (compositor_ == compositor) {
     compositor_ = nullptr;
-  compositor_map_.erase(GetCompositorID(compositor));
+  }
+
+  compositor_map_.erase(compositor_id);
 }
 
-void BrowserViewRenderer::DidBecomeCurrent(
-    content::SynchronousCompositor* compositor) {
-  TRACE_EVENT_INSTANT0("android_webview",
-                       "BrowserViewRenderer::DidBecomeCurrent",
-                       TRACE_EVENT_SCOPE_THREAD);
-  DCHECK(compositor);
-  DCHECK(GetCompositorID(compositor));
-  compositor_ = compositor;
+void BrowserViewRenderer::SetActiveCompositorID(
+    const CompositorID& compositor_id) {
+  if (compositor_map_.count(compositor_id)) {
+    compositor_ = compositor_map_[compositor_id];
+    UpdateMemoryPolicy();
+    compositor_->DidChangeRootLayerScrollOffset(
+        gfx::ScrollOffset(scroll_offset_dip_));
+  } else {
+    compositor_ = nullptr;
+  }
+  compositor_id_ = compositor_id;
 }
 
 void BrowserViewRenderer::SetDipScale(float dip_scale) {
diff --git a/android_webview/browser/browser_view_renderer.h b/android_webview/browser/browser_view_renderer.h
index 56874d79..f7574e8e 100644
--- a/android_webview/browser/browser_view_renderer.h
+++ b/android_webview/browser/browser_view_renderer.h
@@ -11,6 +11,7 @@
 #include <set>
 
 #include "android_webview/browser/compositor_frame_producer.h"
+#include "android_webview/browser/compositor_id.h"
 #include "android_webview/browser/parent_compositor_draw_constraints.h"
 #include "base/callback.h"
 #include "base/cancelable_callback.h"
@@ -27,6 +28,7 @@
 class SkPicture;
 
 namespace content {
+class RenderViewHost;
 class WebContents;
 }
 
@@ -108,11 +110,12 @@
   void TrimMemory();
 
   // SynchronousCompositorClient overrides.
-  void DidInitializeCompositor(
-      content::SynchronousCompositor* compositor) override;
-  void DidDestroyCompositor(
-      content::SynchronousCompositor* compositor) override;
-  void DidBecomeCurrent(content::SynchronousCompositor* compositor) override;
+  void DidInitializeCompositor(content::SynchronousCompositor* compositor,
+                               int process_id,
+                               int routing_id) override;
+  void DidDestroyCompositor(content::SynchronousCompositor* compositor,
+                            int process_id,
+                            int routing_id) override;
   void PostInvalidate() override;
   void DidUpdateContent() override;
   void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset_dip,
@@ -131,6 +134,8 @@
   void RemoveCompositorFrameConsumer(
       CompositorFrameConsumer* compositor_frame_consumer) override;
 
+  void SetActiveCompositorID(const CompositorID& compositor_id);
+
  private:
   void SetTotalRootLayerScrollOffset(const gfx::Vector2dF& new_value_dip);
   bool CanOnDraw();
@@ -160,10 +165,16 @@
 
   // The current compositor that's owned by the current RVH.
   content::SynchronousCompositor* compositor_;
+  // The process id and routing id of the most recent RVH according to
+  // RVHChanged.
+  CompositorID compositor_id_;
   // A map from compositor's per-WebView unique ID to the compositor's raw
   // pointer. A raw pointer here is fine because the entry will be erased when
   // a compositor is destroyed.
-  std::map<size_t, content::SynchronousCompositor*> compositor_map_;
+  std::map<CompositorID,
+           content::SynchronousCompositor*,
+           CompositorIDComparator>
+      compositor_map_;
 
   bool is_paused_;
   bool view_visible_;
@@ -200,8 +211,6 @@
   // TODO(miletus): Make overscroll_rounding_error_ a gfx::ScrollOffset.
   gfx::Vector2dF overscroll_rounding_error_;
 
-  uint32_t next_compositor_id_;
-
   ParentCompositorDrawConstraints external_draw_constraints_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserViewRenderer);
diff --git a/android_webview/browser/child_frame.cc b/android_webview/browser/child_frame.cc
index 752371a..6b695f8f 100644
--- a/android_webview/browser/child_frame.cc
+++ b/android_webview/browser/child_frame.cc
@@ -4,15 +4,13 @@
 
 #include "android_webview/browser/child_frame.h"
 
-#include <utility>
-
 #include "cc/output/compositor_frame.h"
 
 namespace android_webview {
 
 ChildFrame::ChildFrame(uint32_t output_surface_id,
                        std::unique_ptr<cc::CompositorFrame> frame,
-                       uint32_t compositor_id,
+                       const CompositorID& compositor_id,
                        bool viewport_rect_for_tile_priority_empty,
                        const gfx::Transform& transform_for_tile_priority,
                        bool offscreen_pre_raster,
diff --git a/android_webview/browser/child_frame.h b/android_webview/browser/child_frame.h
index 68c4bd5..2cc3a464 100644
--- a/android_webview/browser/child_frame.h
+++ b/android_webview/browser/child_frame.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "android_webview/browser/compositor_id.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/size.h"
@@ -22,7 +23,7 @@
  public:
   ChildFrame(uint32_t output_surface_id,
              std::unique_ptr<cc::CompositorFrame> frame,
-             uint32_t compositor_id,
+             const CompositorID& compositor_id,
              bool viewport_rect_for_tile_priority_empty,
              const gfx::Transform& transform_for_tile_priority,
              bool offscreen_pre_raster,
@@ -32,7 +33,7 @@
   const uint32_t output_surface_id;
   std::unique_ptr<cc::CompositorFrame> frame;
   // The id of the compositor this |frame| comes from.
-  const uint32_t compositor_id;
+  const CompositorID compositor_id;
   const bool viewport_rect_for_tile_priority_empty;
   const gfx::Transform transform_for_tile_priority;
   const bool offscreen_pre_raster;
diff --git a/android_webview/browser/compositor_frame_consumer.h b/android_webview/browser/compositor_frame_consumer.h
index 31118680..8341402 100644
--- a/android_webview/browser/compositor_frame_consumer.h
+++ b/android_webview/browser/compositor_frame_consumer.h
@@ -7,6 +7,7 @@
 
 #include <map>
 
+#include "android_webview/browser/compositor_id.h"
 #include "android_webview/browser/parent_compositor_draw_constraints.h"
 #include "cc/resources/returned_resource.h"
 #include "ui/gfx/geometry/vector2d.h"
@@ -25,7 +26,8 @@
     uint32_t output_surface_id;
     cc::ReturnedResourceArray resources;
   };
-  using ReturnedResourcesMap = std::map<uint32_t, ReturnedResources>;
+  using ReturnedResourcesMap =
+      std::map<CompositorID, ReturnedResources, CompositorIDComparator>;
 
   // A CompositorFrameConsumer may be registered with at most one
   // CompositorFrameProducer.
diff --git a/android_webview/browser/compositor_id.cc b/android_webview/browser/compositor_id.cc
new file mode 100644
index 0000000..7b199fb
--- /dev/null
+++ b/android_webview/browser/compositor_id.cc
@@ -0,0 +1,37 @@
+// 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 "android_webview/browser/compositor_id.h"
+#include "content/public/common/child_process_host.h"
+
+namespace android_webview {
+
+CompositorID::CompositorID()
+    : process_id(content::ChildProcessHost::kInvalidUniqueID),
+      routing_id(content::ChildProcessHost::kInvalidUniqueID) {}
+
+CompositorID::CompositorID(int process_id, int routing_id)
+    : process_id(process_id), routing_id(routing_id) {}
+
+CompositorID::CompositorID(const CompositorID& other) = default;
+
+CompositorID& CompositorID::operator=(const CompositorID& other) {
+  process_id = other.process_id;
+  routing_id = other.routing_id;
+  return *this;
+}
+
+bool CompositorID::Equals(const CompositorID& other) const {
+  return process_id == other.process_id && routing_id == other.routing_id;
+}
+
+bool CompositorIDComparator::operator()(const CompositorID& a,
+                                        const CompositorID& b) const {
+  if (a.process_id == b.process_id) {
+    return a.routing_id < b.routing_id;
+  }
+  return a.process_id < b.process_id;
+}
+
+}  // namespace android_webview
diff --git a/android_webview/browser/compositor_id.h b/android_webview/browser/compositor_id.h
new file mode 100644
index 0000000..0afe3d7
--- /dev/null
+++ b/android_webview/browser/compositor_id.h
@@ -0,0 +1,27 @@
+// 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 ANDROID_WEBVIEW_BROWSER_COMPOSITOR_ID_H_
+#define ANDROID_WEBVIEW_BROWSER_COMPOSITOR_ID_H_
+
+namespace android_webview {
+
+struct CompositorID {
+  CompositorID();
+  CompositorID(int process_id, int routing_id);
+  CompositorID(const CompositorID& other);
+  CompositorID& operator=(const CompositorID& other);
+  bool Equals(const CompositorID& other) const;
+
+  int process_id;
+  int routing_id;
+};
+
+struct CompositorIDComparator {
+  bool operator()(const CompositorID& a, const CompositorID& b) const;
+};
+
+}  // namespace android_webview
+
+#endif  // ANDROID_WEBVIEW_BROWSER_COMPOSITOR_ID_H_
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index a739c83f..acac292 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -20,9 +20,12 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/output_surface.h"
 #include "cc/output/renderer_settings.h"
+#include "cc/output/texture_mailbox_deleter.h"
 #include "cc/quads/shared_quad_state.h"
 #include "cc/quads/surface_draw_quad.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface_factory.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "gpu/command_buffer/client/gl_in_process_context.h"
@@ -38,7 +41,6 @@
     : render_thread_manager_(state),
       last_egl_context_(eglGetCurrentContext()),
       gl_surface_(new AwGLSurface),
-      compositor_id_(0u),  // Valid compositor id starts at 1.
       last_committed_output_surface_id_(0u),
       last_submitted_output_surface_id_(0u),
       output_surface_(NULL) {
@@ -59,15 +61,23 @@
   surface_manager_->RegisterSurfaceFactoryClient(
       surface_id_allocator_->id_namespace(), this);
 
+  std::unique_ptr<cc::BeginFrameSource> begin_frame_source(
+      new cc::StubBeginFrameSource);
+  std::unique_ptr<cc::TextureMailboxDeleter> texture_mailbox_deleter(
+      new cc::TextureMailboxDeleter(nullptr));
   std::unique_ptr<ParentOutputSurface> output_surface_holder(
       new ParentOutputSurface(AwRenderThreadContextProvider::Create(
           gl_surface_, DeferredGpuCommandService::GetInstance())));
   output_surface_ = output_surface_holder.get();
+  std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
+      begin_frame_source.get(), nullptr,
+      output_surface_holder->capabilities().max_frames_pending));
   display_.reset(new cc::Display(
       surface_manager_.get(), nullptr /* shared_bitmap_manager */,
       nullptr /* gpu_memory_buffer_manager */, settings,
-      surface_id_allocator_->id_namespace(), nullptr /* task_runner */,
-      std::move(output_surface_holder)));
+      surface_id_allocator_->id_namespace(), std::move(begin_frame_source),
+      std::move(output_surface_holder), std::move(scheduler),
+      std::move(texture_mailbox_deleter)));
   display_->Initialize(this);
 }
 
@@ -122,7 +132,7 @@
   // kModeProcess. Instead, submit the frame in "kModeDraw" stage to avoid
   // unnecessary kModeProcess.
   if (child_frame_.get() && child_frame_->frame.get()) {
-    if (compositor_id_ != child_frame_->compositor_id ||
+    if (!compositor_id_.Equals(child_frame_->compositor_id) ||
         last_submitted_output_surface_id_ != child_frame_->output_surface_id) {
       if (!root_id_.is_null())
         surface_factory_->Destroy(root_id_);
@@ -260,7 +270,7 @@
 
 void HardwareRenderer::ReturnResourcesToCompositor(
     const cc::ReturnedResourceArray& resources,
-    uint32_t compositor_id,
+    const CompositorID& compositor_id,
     uint32_t output_surface_id) {
   if (output_surface_id != last_committed_output_surface_id_)
     return;
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index ae54a40f3..f6d0d43 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "android_webview/browser/compositor_id.h"
 #include "android_webview/browser/render_thread_manager.h"
 #include "base/macros.h"
 #include "cc/surfaces/display_client.h"
@@ -51,7 +52,7 @@
 
   void ReturnResourcesInChildFrame();
   void ReturnResourcesToCompositor(const cc::ReturnedResourceArray& resources,
-                                   uint32_t compositor_routing_id,
+                                   const CompositorID& compositor_id,
                                    uint32_t output_surface_id);
 
   RenderThreadManager* render_thread_manager_;
@@ -78,7 +79,7 @@
   std::unique_ptr<cc::SurfaceIdAllocator> surface_id_allocator_;
   cc::SurfaceId child_id_;
   cc::SurfaceId root_id_;
-  uint32_t compositor_id_;
+  CompositorID compositor_id_;
   // HardwareRenderer guarantees resources are returned in the order of
   // output_surface_id, and resources for old output surfaces are dropped.
   uint32_t last_committed_output_surface_id_;
diff --git a/android_webview/browser/render_thread_manager.cc b/android_webview/browser/render_thread_manager.cc
index 4a11df24e..9ffaec25 100644
--- a/android_webview/browser/render_thread_manager.cc
+++ b/android_webview/browser/render_thread_manager.cc
@@ -8,6 +8,7 @@
 
 #include "android_webview/browser/child_frame.h"
 #include "android_webview/browser/compositor_frame_producer.h"
+#include "android_webview/browser/compositor_id.h"
 #include "android_webview/browser/deferred_gpu_command_service.h"
 #include "android_webview/browser/hardware_renderer.h"
 #include "android_webview/browser/render_thread_manager_client.h"
@@ -227,7 +228,7 @@
 
 void RenderThreadManager::InsertReturnedResourcesOnRT(
     const cc::ReturnedResourceArray& resources,
-    uint32_t compositor_id,
+    const CompositorID& compositor_id,
     uint32_t output_surface_id) {
   base::AutoLock lock(lock_);
   ReturnedResources& returned_resources =
diff --git a/android_webview/browser/render_thread_manager.h b/android_webview/browser/render_thread_manager.h
index 375734a..0d9eb4f2 100644
--- a/android_webview/browser/render_thread_manager.h
+++ b/android_webview/browser/render_thread_manager.h
@@ -27,10 +27,11 @@
 }
 
 class RenderThreadManagerClient;
-class CompositorFrameProducer;
 class ChildFrame;
+class CompositorFrameProducer;
 class HardwareRenderer;
 class InsideHardwareReleaseReset;
+struct CompositorID;
 
 // This class is used to pass data between UI thread and RenderThread.
 class RenderThreadManager : public CompositorFrameConsumer {
@@ -64,7 +65,7 @@
   void PostExternalDrawConstraintsToChildCompositorOnRT(
       const ParentCompositorDrawConstraints& parent_draw_constraints);
   void InsertReturnedResourcesOnRT(const cc::ReturnedResourceArray& resources,
-                                   uint32_t compositor_id,
+                                   const CompositorID& compositor_id,
                                    uint32_t output_surface_id);
 
  private:
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
index d27a1f4..3e7c1618 100644
--- a/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
+++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.cc
@@ -30,7 +30,9 @@
   DCHECK(client_);
 }
 
-AwRenderViewHostExt::~AwRenderViewHostExt() {}
+AwRenderViewHostExt::~AwRenderViewHostExt() {
+  ClearImageRequests();
+}
 
 void AwRenderViewHostExt::DocumentHasImages(DocumentHasImagesResult result) {
   DCHECK(CalledOnValidThread());
@@ -44,7 +46,7 @@
   // because it only makes sense on the main frame.
   if (Send(new AwViewMsg_DocumentHasImages(
           web_contents()->GetMainFrame()->GetRoutingID(), this_id))) {
-    pending_document_has_images_requests_[this_id] = result;
+    image_requests_callback_map_[this_id] = result;
   } else {
     // Still have to respond to the API call WebView#docuemntHasImages.
     // Otherwise the listener of the response may be starved.
@@ -127,14 +129,18 @@
       web_contents()->GetMainFrame()->GetRoutingID(), background_color_));
 }
 
-void AwRenderViewHostExt::RenderProcessGone(base::TerminationStatus status) {
-  DCHECK(CalledOnValidThread());
-  for (std::map<int, DocumentHasImagesResult>::iterator pending_req =
-           pending_document_has_images_requests_.begin();
-       pending_req != pending_document_has_images_requests_.end();
-      ++pending_req) {
-    pending_req->second.Run(false);
+void AwRenderViewHostExt::RenderViewHostChanged(
+    content::RenderViewHost* old_host,
+    content::RenderViewHost* new_host) {
+  ClearImageRequests();
+}
+
+void AwRenderViewHostExt::ClearImageRequests() {
+  for (const auto& pair : image_requests_callback_map_) {
+    pair.second.Run(false);
   }
+
+  image_requests_callback_map_.clear();
 }
 
 void AwRenderViewHostExt::DidNavigateAnyFrame(
@@ -182,12 +188,12 @@
 
   DCHECK(CalledOnValidThread());
   std::map<int, DocumentHasImagesResult>::iterator pending_req =
-      pending_document_has_images_requests_.find(msg_id);
-  if (pending_req == pending_document_has_images_requests_.end()) {
+      image_requests_callback_map_.find(msg_id);
+  if (pending_req == image_requests_callback_map_.end()) {
     DLOG(WARNING) << "unexpected DocumentHasImages Response: " << msg_id;
   } else {
     pending_req->second.Run(has_images);
-    pending_document_has_images_requests_.erase(pending_req);
+    image_requests_callback_map_.erase(pending_req);
   }
 }
 
diff --git a/android_webview/browser/renderer_host/aw_render_view_host_ext.h b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
index f57d3415..3872503 100644
--- a/android_webview/browser/renderer_host/aw_render_view_host_ext.h
+++ b/android_webview/browser/renderer_host/aw_render_view_host_ext.h
@@ -86,7 +86,8 @@
  private:
   // content::WebContentsObserver implementation.
   void RenderViewCreated(content::RenderViewHost* view_host) override;
-  void RenderProcessGone(base::TerminationStatus status) override;
+  void RenderViewHostChanged(content::RenderViewHost* old_host,
+                             content::RenderViewHost* new_host) override;
   void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host,
                            const content::LoadCommittedDetails& details,
                            const content::FrameNavigateParams& params) override;
@@ -103,12 +104,15 @@
                              const gfx::Size& contents_size);
 
   bool IsRenderViewReady() const;
+  void ClearImageRequests();
 
   AwRenderViewHostExtClient* client_;
 
   SkColor background_color_;
 
-  std::map<int, DocumentHasImagesResult> pending_document_has_images_requests_;
+  // A map from message id to result callback. Messages here are all for the
+  // *current* RVH.
+  std::map<int, DocumentHasImagesResult> image_requests_callback_map_;
 
   // Master copy of hit test data on the browser side. This is updated
   // as a result of DoHitTest called explicitly or when the FocusedNodeChanged
diff --git a/android_webview/browser/test/rendering_test.cc b/android_webview/browser/test/rendering_test.cc
index 1c92f34e..18b4629 100644
--- a/android_webview/browser/test/rendering_test.cc
+++ b/android_webview/browser/test/rendering_test.cc
@@ -56,6 +56,7 @@
   DCHECK(!functor_.get());
   browser_view_renderer_.reset(
       new TestBrowserViewRenderer(this, base::ThreadTaskRunnerHandle::Get()));
+  browser_view_renderer_->SetActiveCompositorID(CompositorID(0, 0));
   InitializeCompositor();
   std::unique_ptr<FakeWindow> window(
       new FakeWindow(browser_view_renderer_.get(), this, gfx::Rect(100, 100)));
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 44738a3..fb43e963 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -172,7 +172,8 @@
 }
 
 AwContents::AwContents(std::unique_ptr<WebContents> web_contents)
-    : functor_(nullptr),
+    : content::WebContentsObserver(web_contents.get()),
+      functor_(nullptr),
       browser_view_renderer_(
           this,
           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)),
@@ -184,6 +185,15 @@
   web_contents_->SetUserData(android_webview::kAwContentsUserDataKey,
                              new AwContentsUserData(this));
   browser_view_renderer_.RegisterWithWebContents(web_contents_.get());
+
+  CompositorID compositor_id;
+  if (web_contents_->GetRenderProcessHost() &&
+      web_contents_->GetRenderViewHost()) {
+    compositor_id.process_id = web_contents_->GetRenderProcessHost()->GetID();
+    compositor_id.routing_id = web_contents_->GetRoutingID();
+  }
+
+  browser_view_renderer_.SetActiveCompositorID(compositor_id);
   render_view_host_ext_.reset(
       new AwRenderViewHostExt(this, web_contents_.get()));
 
@@ -1288,4 +1298,18 @@
   g_should_download_favicons = true;
 }
 
+void AwContents::RenderViewHostChanged(content::RenderViewHost* old_host,
+                                       content::RenderViewHost* new_host) {
+  DCHECK(new_host);
+
+  int process_id = new_host->GetProcess()->GetID();
+  int routing_id = new_host->GetRoutingID();
+  // At this point, the current RVH may or may not contain a compositor. So
+  // compositor_ may be nullptr, in which case
+  // BrowserViewRenderer::DidInitializeCompositor() callback is time when the
+  // new compositor is constructed.
+  browser_view_renderer_.SetActiveCompositorID(
+      CompositorID(process_id, routing_id));
+}
+
 }  // namespace android_webview
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 5062eb8..12ff238 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -27,6 +27,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
 
 class SkBitmap;
 class TabContents;
@@ -64,7 +65,8 @@
                    public AwRenderViewHostExtClient,
                    public BrowserViewRendererClient,
                    public PermissionRequestHandlerClient,
-                   public AwBrowserPermissionRequestDelegate {
+                   public AwBrowserPermissionRequestDelegate,
+                   public content::WebContentsObserver {
  public:
   // Returns the AwContents instance associated with |web_contents|, or NULL.
   static AwContents* FromWebContents(content::WebContents* web_contents);
@@ -333,6 +335,10 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
 
+  // content::WebContentsObserver overrides
+  void RenderViewHostChanged(content::RenderViewHost* old_host,
+                             content::RenderViewHost* new_host) override;
+
  private:
   void InitAutofillIfNecessary(bool enabled);
 
@@ -347,9 +353,9 @@
   JavaObjectWeakGlobalRef java_ref_;
   AwGLFunctor* functor_;
   BrowserViewRenderer browser_view_renderer_;  // Must outlive |web_contents_|.
+  std::unique_ptr<content::WebContents> web_contents_;
   std::unique_ptr<AwWebContentsDelegate> web_contents_delegate_;
   std::unique_ptr<AwContentsClientBridge> contents_client_bridge_;
-  std::unique_ptr<content::WebContents> web_contents_;
   std::unique_ptr<AwRenderViewHostExt> render_view_host_ext_;
   std::unique_ptr<FindHelper> find_helper_;
   std::unique_ptr<IconHelper> icon_helper_;
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index 6b29ad4..2aa4ceb 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -11,7 +11,7 @@
 
 #include "ash/accelerators/accelerator_commands.h"
 #include "ash/accelerators/debug_commands.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/focus_cycler.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_model.h"
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index df6ec6b..78df54b 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -5,9 +5,9 @@
 #include "ash/accelerators/accelerator_controller.h"
 
 #include "ash/accelerators/accelerator_table.h"
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/volume_control_delegate.h"
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc
index 4e7a4e8..7e238992 100644
--- a/ash/accelerators/debug_commands.cc
+++ b/ash/accelerators/debug_commands.cc
@@ -5,7 +5,7 @@
 #include "ash/accelerators/debug_commands.h"
 
 #include "ash/accelerators/accelerator_commands.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/debug.h"
 #include "ash/desktop_background/desktop_background_controller.h"
 #include "ash/desktop_background/user_wallpaper_delegate.h"
diff --git a/ash/accelerators/magnifier_key_scroller.cc b/ash/accelerators/magnifier_key_scroller.cc
index 96a569e..04604a9 100644
--- a/ash/accelerators/magnifier_key_scroller.cc
+++ b/ash/accelerators/magnifier_key_scroller.cc
@@ -7,7 +7,7 @@
 #include <utility>
 
 #include "ash/accelerators/key_hold_detector.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
diff --git a/ash/app_list/app_list_presenter_delegate.cc b/ash/app_list/app_list_presenter_delegate.cc
index 415e57fa..6df95ae7 100644
--- a/ash/app_list/app_list_presenter_delegate.cc
+++ b/ash/app_list/app_list_presenter_delegate.cc
@@ -4,7 +4,7 @@
 
 #include "ash/app_list/app_list_presenter_delegate.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm_shell.h"
diff --git a/ash/ash.gyp b/ash/ash.gyp
index 988ed0d9..6c734fdc 100644
--- a/ash/ash.gyp
+++ b/ash/ash.gyp
@@ -32,8 +32,6 @@
       'app_list/app_list_presenter_delegate_factory.cc',
       'app_list/app_list_presenter_delegate_factory.h',
       'ash_export.h',
-      'ash_switches.cc',
-      'ash_switches.h',
       'ash_touch_exploration_manager_chromeos.cc',
       'ash_touch_exploration_manager_chromeos.h',
       'audio/sounds.cc',
@@ -61,6 +59,8 @@
       'common/ash_constants.h',
       'common/ash_layout_constants.cc',
       'common/ash_layout_constants.h',
+      'common/ash_switches.cc',
+      'common/ash_switches.h',
       'common/default_accessibility_delegate.cc',
       'common/default_accessibility_delegate.h',
       'common/focus_cycler.cc',
diff --git a/ash/audio/sounds.cc b/ash/audio/sounds.cc
index 1df3897..b9110ba2 100644
--- a/ash/audio/sounds.cc
+++ b/ash/audio/sounds.cc
@@ -4,8 +4,8 @@
 
 #include "ash/audio/sounds.h"
 
-#include "ash/ash_switches.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "ash/shell.h"
 #include "base/command_line.h"
 
diff --git a/ash/aura/wm_shelf_aura.cc b/ash/aura/wm_shelf_aura.cc
index fc9f583..1effb10a 100644
--- a/ash/aura/wm_shelf_aura.cc
+++ b/ash/aura/wm_shelf_aura.cc
@@ -9,6 +9,7 @@
 #include "ash/common/wm_window.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shell.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
@@ -79,10 +80,22 @@
   return shelf_layout_manager_->auto_hide_state();
 }
 
+void WmShelfAura::UpdateAutoHideState() {
+  shelf_layout_manager_->UpdateAutoHideState();
+}
+
 ShelfBackgroundType WmShelfAura::GetBackgroundType() const {
   return shelf_layout_manager_->shelf_widget()->GetBackgroundType();
 }
 
+bool WmShelfAura::IsDimmed() const {
+  return shelf_layout_manager_->shelf_widget()->GetDimsShelf();
+}
+
+bool WmShelfAura::IsVisible() const {
+  return shelf_->IsVisible();
+}
+
 void WmShelfAura::UpdateVisibilityState() {
   shelf_layout_manager_->UpdateVisibilityState();
 }
@@ -92,6 +105,10 @@
                                : SHELF_HIDDEN;
 }
 
+gfx::Rect WmShelfAura::GetIdealBounds() {
+  return shelf_layout_manager_->GetIdealBounds();
+}
+
 gfx::Rect WmShelfAura::GetUserWorkAreaBounds() const {
   return shelf_layout_manager_ ? shelf_layout_manager_->user_work_area_bounds()
                                : gfx::Rect();
@@ -106,6 +123,18 @@
       WmWindowAura::GetAuraWindow(window));
 }
 
+void WmShelfAura::UpdateAutoHideForMouseEvent(ui::MouseEvent* event) {
+  // Auto-hide support for ash_sysui.
+  if (Shell::GetInstance()->in_mus() && shelf_layout_manager_)
+    shelf_layout_manager_->UpdateAutoHideForMouseEvent(event);
+}
+
+void WmShelfAura::UpdateAutoHideForGestureEvent(ui::GestureEvent* event) {
+  // Auto-hide support for ash_sysui.
+  if (Shell::GetInstance()->in_mus() && shelf_layout_manager_)
+    shelf_layout_manager_->UpdateAutoHideForGestureEvent(event);
+}
+
 void WmShelfAura::AddObserver(WmShelfObserver* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/ash/aura/wm_shelf_aura.h b/ash/aura/wm_shelf_aura.h
index d796f465..33bf58c 100644
--- a/ash/aura/wm_shelf_aura.h
+++ b/ash/aura/wm_shelf_aura.h
@@ -44,12 +44,18 @@
   ShelfAutoHideBehavior GetAutoHideBehavior() const override;
   void SetAutoHideBehavior(ShelfAutoHideBehavior behavior) override;
   ShelfAutoHideState GetAutoHideState() const override;
+  void UpdateAutoHideState() override;
   ShelfBackgroundType GetBackgroundType() const override;
+  bool IsDimmed() const override;
+  bool IsVisible() const override;
   void UpdateVisibilityState() override;
   ShelfVisibilityState GetVisibilityState() const override;
+  gfx::Rect GetIdealBounds() override;
   gfx::Rect GetUserWorkAreaBounds() const override;
   void UpdateIconPositionForWindow(WmWindow* window) override;
   gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window) override;
+  void UpdateAutoHideForMouseEvent(ui::MouseEvent* event) override;
+  void UpdateAutoHideForGestureEvent(ui::GestureEvent* event) override;
   void AddObserver(WmShelfObserver* observer) override;
   void RemoveObserver(WmShelfObserver* observer) override;
 
diff --git a/ash/common/DEPS b/ash/common/DEPS
index 8d45fdc..1412c1f7 100644
--- a/ash/common/DEPS
+++ b/ash/common/DEPS
@@ -1,7 +1,6 @@
 include_rules = [
   "-ash",
   "+ash/ash_export.h",
-  "+ash/ash_switches.h",
   "+ash/common",
   "+ui",
   "-ui/aura",
diff --git a/ash/ash_switches.cc b/ash/common/ash_switches.cc
similarity index 98%
rename from ash/ash_switches.cc
rename to ash/common/ash_switches.cc
index 15ab1b11..ef0fb1c 100644
--- a/ash/ash_switches.cc
+++ b/ash/common/ash_switches.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 
 #include "base/command_line.h"
 #include "base/sys_info.h"
diff --git a/ash/ash_switches.h b/ash/common/ash_switches.h
similarity index 95%
rename from ash/ash_switches.h
rename to ash/common/ash_switches.h
index ad89838..d798e3e5 100644
--- a/ash/ash_switches.h
+++ b/ash/common/ash_switches.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef ASH_ASH_SWITCHES_H_
-#define ASH_ASH_SWITCHES_H_
+#ifndef ASH_COMMON_ASH_SWITCHES_H_
+#define ASH_COMMON_ASH_SWITCHES_H_
 
 #include "ash/ash_export.h"
 
@@ -60,4 +60,4 @@
 }  // namespace switches
 }  // namespace ash
 
-#endif  // ASH_ASH_SWITCHES_H_
+#endif  // ASH_COMMON_ASH_SWITCHES_H_
diff --git a/ash/common/material_design/material_design_controller.cc b/ash/common/material_design/material_design_controller.cc
index 711aafa2..0c2bc55 100644
--- a/ash/common/material_design/material_design_controller.cc
+++ b/ash/common/material_design/material_design_controller.cc
@@ -4,7 +4,7 @@
 
 #include <string>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "base/command_line.h"
 #include "base/logging.h"
diff --git a/ash/common/material_design/material_design_controller_unittest.cc b/ash/common/material_design/material_design_controller_unittest.cc
index 5935b264..6e2c88c 100644
--- a/ash/common/material_design/material_design_controller_unittest.cc
+++ b/ash/common/material_design/material_design_controller_unittest.cc
@@ -5,7 +5,7 @@
 #include <memory>
 #include <string>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/material_design_controller_test_api.h"
diff --git a/ash/common/shelf/wm_shelf.h b/ash/common/shelf/wm_shelf.h
index 834b494..ac63988 100644
--- a/ash/common/shelf/wm_shelf.h
+++ b/ash/common/shelf/wm_shelf.h
@@ -12,6 +12,11 @@
 class Rect;
 }
 
+namespace ui {
+class GestureEvent;
+class MouseEvent;
+}
+
 namespace ash {
 
 class WmShelfObserver;
@@ -31,12 +36,26 @@
 
   virtual ShelfAutoHideState GetAutoHideState() const = 0;
 
+  // Invoke when the auto-hide state may have changed (for example, when the
+  // system tray bubble opens it should force the shelf to be visible).
+  virtual void UpdateAutoHideState() = 0;
+
   virtual ShelfBackgroundType GetBackgroundType() const = 0;
 
+  // Shelf items are slightly dimmed (e.g. when a window is maximized).
+  virtual bool IsDimmed() const = 0;
+
+  // Whether the shelf view is visible.
+  // TODO(jamescook): Consolidate this with GetVisibilityState().
+  virtual bool IsVisible() const = 0;
+
   virtual void UpdateVisibilityState() = 0;
 
   virtual ShelfVisibilityState GetVisibilityState() const = 0;
 
+  // Returns the ideal bounds of the shelf assuming it is visible.
+  virtual gfx::Rect GetIdealBounds() = 0;
+
   virtual gfx::Rect GetUserWorkAreaBounds() const = 0;
 
   virtual void UpdateIconPositionForWindow(WmWindow* window) = 0;
@@ -45,6 +64,10 @@
   // no item for the specified window an empty rect is returned.
   virtual gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window) = 0;
 
+  // TODO(jamescook): Nuke when ash_sysui is removed. http://crbug.com/621112
+  virtual void UpdateAutoHideForMouseEvent(ui::MouseEvent* event) = 0;
+  virtual void UpdateAutoHideForGestureEvent(ui::GestureEvent* event) = 0;
+
   virtual void AddObserver(WmShelfObserver* observer) = 0;
   virtual void RemoveObserver(WmShelfObserver* observer) = 0;
 
diff --git a/ash/common/system/chromeos/power/tray_power.cc b/ash/common/system/chromeos/power/tray_power.cc
index 22e8ec1..fe82b93 100644
--- a/ash/common/system/chromeos/power/tray_power.cc
+++ b/ash/common/system/chromeos/power/tray_power.cc
@@ -6,8 +6,8 @@
 
 #include <utility>
 
-#include "ash/ash_switches.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/system/chromeos/devicetype_utils.h"
 #include "ash/common/system/chromeos/power/battery_notification.h"
 #include "ash/common/system/chromeos/power/dual_role_notification.h"
diff --git a/ash/common/system/chromeos/power/tray_power_unittest.cc b/ash/common/system/chromeos/power/tray_power_unittest.cc
index d2d102f..d60be55 100644
--- a/ash/common/system/chromeos/power/tray_power_unittest.cc
+++ b/ash/common/system/chromeos/power/tray_power_unittest.cc
@@ -8,7 +8,7 @@
 #include <memory>
 #include <string>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/test/ash_test_base.h"
 #include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
 #include "ui/message_center/fake_message_center.h"
diff --git a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
index f2b1a66..c13eb2f1 100644
--- a/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
+++ b/ash/content/display/screen_orientation_controller_chromeos_unittest.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/content/shell_content_state.h"
 #include "ash/display/display_info.h"
 #include "ash/display/display_manager.h"
diff --git a/ash/desktop_background/desktop_background_controller.cc b/ash/desktop_background/desktop_background_controller.cc
index a9444835..228b549 100644
--- a/ash/desktop_background/desktop_background_controller.cc
+++ b/ash/desktop_background/desktop_background_controller.cc
@@ -4,8 +4,8 @@
 
 #include "ash/desktop_background/desktop_background_controller.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/root_window_layout_manager.h"
 #include "ash/common/wm_shell.h"
diff --git a/ash/desktop_background/desktop_background_controller_unittest.cc b/ash/desktop_background/desktop_background_controller_unittest.cc
index c10641ec..6dab6243 100644
--- a/ash/desktop_background/desktop_background_controller_unittest.cc
+++ b/ash/desktop_background/desktop_background_controller_unittest.cc
@@ -7,7 +7,7 @@
 #include <cmath>
 #include <cstdlib>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/desktop_background/desktop_background_view.h"
 #include "ash/desktop_background/desktop_background_widget_controller.h"
diff --git a/ash/dip_unittest.cc b/ash/dip_unittest.cc
index 048fa50..c99632e 100644
--- a/ash/dip_unittest.cc
+++ b/ash/dip_unittest.cc
@@ -5,7 +5,7 @@
 #include <algorithm>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_manager.h"
 #include "ash/shelf/shelf.h"
 #include "ash/shelf/shelf_widget.h"
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc
index 437f899..b32a0482 100644
--- a/ash/display/display_change_observer_chromeos.cc
+++ b/ash/display/display_change_observer_chromeos.cc
@@ -11,7 +11,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm_shell.h"
 #include "ash/display/display_info.h"
 #include "ash/display/display_layout_store.h"
diff --git a/ash/display/display_layout_store.cc b/ash/display/display_layout_store.cc
index 3f91817a..2533c4d 100644
--- a/ash/display/display_layout_store.cc
+++ b/ash/display/display_layout_store.cc
@@ -4,7 +4,7 @@
 
 #include <stdio.h>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_layout_store.h"
 #include "ash/display/display_manager.h"
 #include "ash/display/display_util.h"
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc
index 0fbe4ff8..01f33ff 100644
--- a/ash/display/display_manager.cc
+++ b/ash/display/display_manager.cc
@@ -13,7 +13,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_layout_store.h"
 #include "ash/display/display_util.h"
 #include "ash/display/extended_mouse_warp_controller.h"
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc
index f14b909..b0cca7a8 100644
--- a/ash/display/display_manager_unittest.cc
+++ b/ash/display/display_manager_unittest.cc
@@ -5,7 +5,7 @@
 #include "ash/display/display_manager.h"
 
 #include "ash/accelerators/accelerator_commands.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/display_info.h"
diff --git a/ash/display/mirror_window_controller_unittest.cc b/ash/display/mirror_window_controller_unittest.cc
index 97e1608d..54779ce0 100644
--- a/ash/display/mirror_window_controller_unittest.cc
+++ b/ash/display/mirror_window_controller_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "ash/display/mirror_window_controller.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_manager.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/screen_util.h"
diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc
index 0be573b..7ceb7055 100644
--- a/ash/display/root_window_transformers.cc
+++ b/ash/display/root_window_transformers.cc
@@ -6,7 +6,7 @@
 
 #include <cmath>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_info.h"
 #include "ash/display/display_manager.h"
 #include "ash/host/root_window_transformer.h"
diff --git a/ash/display/screen_orientation_controller_chromeos.cc b/ash/display/screen_orientation_controller_chromeos.cc
index b643f09..0f793ef 100644
--- a/ash/display/screen_orientation_controller_chromeos.cc
+++ b/ash/display/screen_orientation_controller_chromeos.cc
@@ -4,7 +4,7 @@
 
 #include "ash/display/screen_orientation_controller_chromeos.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm_shell.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/display_info.h"
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc
index 2e26869..966a33b9 100644
--- a/ash/display/window_tree_host_manager.cc
+++ b/ash/display/window_tree_host_manager.cc
@@ -10,7 +10,7 @@
 #include <memory>
 #include <utility>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/cursor_window_controller.h"
 #include "ash/display/display_layout_store.h"
 #include "ash/display/display_manager.h"
diff --git a/ash/display/window_tree_host_manager_unittest.cc b/ash/display/window_tree_host_manager_unittest.cc
index 8cb8fa3..c2850e0 100644
--- a/ash/display/window_tree_host_manager_unittest.cc
+++ b/ash/display/window_tree_host_manager_unittest.cc
@@ -6,7 +6,7 @@
 
 #include <memory>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm/wm_event.h"
 #include "ash/display/display_info.h"
diff --git a/ash/focus_cycler_unittest.cc b/ash/focus_cycler_unittest.cc
index 7d20988c..664a32f 100644
--- a/ash/focus_cycler_unittest.cc
+++ b/ash/focus_cycler_unittest.cc
@@ -96,7 +96,7 @@
         WmShell::Get()->GetRootWindowForNewWindows()->GetChildByShellWindowId(
             kShellWindowId_StatusContainer);
 
-    StatusAreaWidget* widget = new StatusAreaWidget(parent, shelf_widget());
+    StatusAreaWidget* widget = new StatusAreaWidget(parent, GetPrimaryShelf());
     widget->CreateTrayViews();
     widget->Show();
     tray_.reset(widget->system_tray());
diff --git a/ash/frame/caption_buttons/frame_caption_button_container_view.cc b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
index d500513b..f1a3c43a 100644
--- a/ash/frame/caption_buttons/frame_caption_button_container_view.cc
+++ b/ash/frame/caption_buttons/frame_caption_button_container_view.cc
@@ -7,7 +7,7 @@
 #include <cmath>
 #include <map>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/frame/caption_buttons/frame_caption_button.h"
 #include "ash/frame/caption_buttons/frame_size_button.h"
 #include "ash/metrics/user_metrics_recorder.h"
diff --git a/ash/frame/custom_frame_view_ash.cc b/ash/frame/custom_frame_view_ash.cc
index 545f003..47a9c3f2 100644
--- a/ash/frame/custom_frame_view_ash.cc
+++ b/ash/frame/custom_frame_view_ash.cc
@@ -7,8 +7,8 @@
 #include <algorithm>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_observer.h"
 #include "ash/common/wm/window_state.h"
diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc
index 3f1ff72..da21d7ec71 100644
--- a/ash/magnifier/magnification_controller.cc
+++ b/ash/magnifier/magnification_controller.cc
@@ -8,8 +8,8 @@
 #include <utility>
 
 #include "ash/accelerators/accelerator_controller.h"
-#include "ash/ash_switches.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/display/root_window_transformers.h"
 #include "ash/host/ash_window_tree_host.h"
diff --git a/ash/mus/accelerator_registrar_impl.cc b/ash/mus/accelerator_registrar_impl.cc
index db1ddb3d..0f4502e 100644
--- a/ash/mus/accelerator_registrar_impl.cc
+++ b/ash/mus/accelerator_registrar_impl.cc
@@ -9,7 +9,6 @@
 
 #include "ash/mus/root_window_controller.h"
 #include "ash/mus/window_manager.h"
-#include "ash/mus/window_manager_application.h"
 #include "base/bind.h"
 #include "components/mus/public/cpp/window_manager_delegate.h"
 
@@ -19,7 +18,6 @@
 namespace {
 const int kAcceleratorIdMask = 0xffff;
 
-void OnAcceleratorAdded(bool result) {}
 void CallAddAcceleratorCallback(
     const ::mus::mojom::AcceleratorRegistrar::AddAcceleratorCallback& callback,
     bool result) {
@@ -28,22 +26,15 @@
 
 }  // namespace
 
-struct AcceleratorRegistrarImpl::Accelerator {
-  ::mus::mojom::EventMatcherPtr event_matcher;
-  AddAcceleratorCallback callback;
-  bool callback_used = false;
-};
-
 AcceleratorRegistrarImpl::AcceleratorRegistrarImpl(
-    WindowManagerApplication* wm_app,
+    WindowManager* window_manager,
     uint32_t accelerator_namespace,
     mojo::InterfaceRequest<AcceleratorRegistrar> request,
     const DestroyCallback& destroy_callback)
-    : wm_app_(wm_app),
+    : window_manager_(window_manager),
       binding_(this, std::move(request)),
       accelerator_namespace_(accelerator_namespace & 0xffff),
       destroy_callback_(destroy_callback) {
-  wm_app_->AddRootWindowsObserver(this);
   binding_.set_connection_error_handler(base::Bind(
       &AcceleratorRegistrarImpl::OnBindingGone, base::Unretained(this)));
 }
@@ -66,7 +57,6 @@
 }
 
 AcceleratorRegistrarImpl::~AcceleratorRegistrarImpl() {
-  wm_app_->RemoveRootWindowsObserver(this);
   RemoveAllAccelerators();
   destroy_callback_.Run(this);
 }
@@ -97,27 +87,10 @@
   RemoveAllAccelerators();
 }
 
-void AcceleratorRegistrarImpl::AddAcceleratorToRoot(
-    RootWindowController* root,
-    uint32_t namespaced_accelerator_id) {
-  Accelerator& accelerator = accelerators_[namespaced_accelerator_id];
-  AddAcceleratorCallback callback = accelerator.callback_used
-                                        ? base::Bind(&OnAcceleratorAdded)
-                                        : accelerator.callback;
-  // Ensure we only notify the callback once (as happens with mojoms).
-  accelerator.callback_used = true;
-  root->window_manager()->window_manager_client()->AddAccelerator(
-      namespaced_accelerator_id, accelerator.event_matcher.Clone(),
-      base::Bind(&CallAddAcceleratorCallback, callback));
-}
-
 void AcceleratorRegistrarImpl::RemoveAllAccelerators() {
-  for (const auto& pair : accelerators_) {
-    for (RootWindowController* root : wm_app_->GetRootControllers()) {
-      root->window_manager()->window_manager_client()->RemoveAccelerator(
-          pair.first);
-    }
-  }
+  for (uint32_t accelerator : accelerators_)
+    window_manager_->window_manager_client()->RemoveAccelerator(accelerator);
+
   accelerators_.clear();
 }
 
@@ -139,23 +112,19 @@
     return;
   }
   uint32_t namespaced_accelerator_id = ComputeAcceleratorId(accelerator_id);
-  accelerators_[namespaced_accelerator_id].event_matcher = matcher->Clone();
-  accelerators_[namespaced_accelerator_id].callback = callback;
-  accelerators_[namespaced_accelerator_id].callback_used = false;
-  for (RootWindowController* root : wm_app_->GetRootControllers())
-    AddAcceleratorToRoot(root, namespaced_accelerator_id);
+  accelerators_.insert(namespaced_accelerator_id);
+  window_manager_->window_manager_client()->AddAccelerator(
+      namespaced_accelerator_id, std::move(matcher),
+      base::Bind(&CallAddAcceleratorCallback, callback));
 }
 
 void AcceleratorRegistrarImpl::RemoveAccelerator(uint32_t accelerator_id) {
   uint32_t namespaced_accelerator_id = ComputeAcceleratorId(accelerator_id);
-  auto iter = accelerators_.find(namespaced_accelerator_id);
-  if (iter == accelerators_.end())
+  if (accelerators_.erase(namespaced_accelerator_id) == 0)
     return;
-  for (RootWindowController* root : wm_app_->GetRootControllers()) {
-    root->window_manager()->window_manager_client()->RemoveAccelerator(
-        namespaced_accelerator_id);
-  }
-  accelerators_.erase(iter);
+  window_manager_->window_manager_client()->RemoveAccelerator(
+      namespaced_accelerator_id);
+
   // If the registrar is not bound anymore (i.e. the client can no longer
   // install new accelerators), and the last accelerator has been removed, then
   // there's no point keeping this alive anymore.
@@ -163,11 +132,5 @@
     delete this;
 }
 
-void AcceleratorRegistrarImpl::OnRootWindowControllerAdded(
-    RootWindowController* controller) {
-  for (const auto& pair : accelerators_)
-    AddAcceleratorToRoot(controller, pair.first);
-}
-
 }  // namespace mus
 }  // namespace ash
diff --git a/ash/mus/accelerator_registrar_impl.h b/ash/mus/accelerator_registrar_impl.h
index 695cca7..e720674e 100644
--- a/ash/mus/accelerator_registrar_impl.h
+++ b/ash/mus/accelerator_registrar_impl.h
@@ -9,7 +9,6 @@
 
 #include <map>
 
-#include "ash/mus/root_windows_observer.h"
 #include "base/callback.h"
 #include "base/macros.h"
 #include "components/mus/public/interfaces/accelerator_registrar.mojom.h"
@@ -19,17 +18,16 @@
 namespace ash {
 namespace mus {
 
-class WindowManagerApplication;
+class WindowManager;
 
 // Manages AcceleratorHandlers from a particular AcceleratorRegistrar
 // connection. This manages its own lifetime, and destroys itself when the
 // AcceleratorRegistrar and all its AcceleratorHandlers are disconnected. Upon
 // destruction, it calls the DestroyCallback.
-class AcceleratorRegistrarImpl : public ::mus::mojom::AcceleratorRegistrar,
-                                 public RootWindowsObserver {
+class AcceleratorRegistrarImpl : public ::mus::mojom::AcceleratorRegistrar {
  public:
   using DestroyCallback = base::Callback<void(AcceleratorRegistrarImpl*)>;
-  AcceleratorRegistrarImpl(WindowManagerApplication* wm_app,
+  AcceleratorRegistrarImpl(WindowManager* window_manager,
                            uint32_t accelerator_namespace,
                            mojo::InterfaceRequest<AcceleratorRegistrar> request,
                            const DestroyCallback& destroy_callback);
@@ -43,17 +41,12 @@
   void ProcessAccelerator(uint32_t accelerator_id, const ui::Event& event);
 
  private:
-  struct Accelerator;
-
   ~AcceleratorRegistrarImpl() override;
 
   uint32_t ComputeAcceleratorId(uint32_t accelerator_id) const;
   void OnBindingGone();
   void OnHandlerGone();
 
-  void AddAcceleratorToRoot(RootWindowController* root,
-                            uint32_t namespaced_accelerator_id);
-
   void RemoveAllAccelerators();
 
   // ::mus::mojom::AcceleratorRegistrar:
@@ -63,14 +56,11 @@
                       const AddAcceleratorCallback& callback) override;
   void RemoveAccelerator(uint32_t accelerator_id) override;
 
-  // RootWindowsObserver:
-  void OnRootWindowControllerAdded(RootWindowController* controller) override;
-
-  WindowManagerApplication* wm_app_;
+  WindowManager* window_manager_;
   ::mus::mojom::AcceleratorHandlerPtr accelerator_handler_;
   mojo::Binding<AcceleratorRegistrar> binding_;
   uint32_t accelerator_namespace_;
-  std::map<uint32_t, Accelerator> accelerators_;
+  std::set<uint32_t> accelerators_;
   DestroyCallback destroy_callback_;
 
   DISALLOW_COPY_AND_ASSIGN(AcceleratorRegistrarImpl);
diff --git a/ash/mus/bridge/wm_shelf_mus.cc b/ash/mus/bridge/wm_shelf_mus.cc
index ffee968..5152250 100644
--- a/ash/mus/bridge/wm_shelf_mus.cc
+++ b/ash/mus/bridge/wm_shelf_mus.cc
@@ -55,11 +55,25 @@
   return SHELF_AUTO_HIDE_HIDDEN;
 }
 
+void WmShelfMus::UpdateAutoHideState() {
+  NOTIMPLEMENTED();
+}
+
 ShelfBackgroundType WmShelfMus::GetBackgroundType() const {
   NOTIMPLEMENTED();
   return SHELF_BACKGROUND_DEFAULT;
 }
 
+bool WmShelfMus::IsDimmed() const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool WmShelfMus::IsVisible() const {
+  NOTIMPLEMENTED();
+  return true;
+}
+
 void WmShelfMus::UpdateVisibilityState() {
   NOTIMPLEMENTED();
 }
@@ -78,11 +92,24 @@
   NOTIMPLEMENTED();
 }
 
+gfx::Rect WmShelfMus::GetIdealBounds() {
+  NOTIMPLEMENTED();
+  return gfx::Rect();
+}
+
 gfx::Rect WmShelfMus::GetScreenBoundsOfItemIconForWindow(WmWindow* window) {
   NOTIMPLEMENTED();
   return gfx::Rect();
 }
 
+void WmShelfMus::UpdateAutoHideForMouseEvent(ui::MouseEvent* event) {
+  NOTIMPLEMENTED();
+}
+
+void WmShelfMus::UpdateAutoHideForGestureEvent(ui::GestureEvent* event) {
+  NOTIMPLEMENTED();
+}
+
 void WmShelfMus::AddObserver(WmShelfObserver* observer) {
   observers_.AddObserver(observer);
 }
diff --git a/ash/mus/bridge/wm_shelf_mus.h b/ash/mus/bridge/wm_shelf_mus.h
index 0e1ff4b..329f569 100644
--- a/ash/mus/bridge/wm_shelf_mus.h
+++ b/ash/mus/bridge/wm_shelf_mus.h
@@ -31,12 +31,18 @@
   ShelfAutoHideBehavior GetAutoHideBehavior() const override;
   void SetAutoHideBehavior(ShelfAutoHideBehavior behavior) override;
   ShelfAutoHideState GetAutoHideState() const override;
+  void UpdateAutoHideState() override;
   ShelfBackgroundType GetBackgroundType() const override;
+  bool IsDimmed() const override;
+  bool IsVisible() const override;
   void UpdateVisibilityState() override;
   ShelfVisibilityState GetVisibilityState() const override;
+  gfx::Rect GetIdealBounds() override;
   gfx::Rect GetUserWorkAreaBounds() const override;
   void UpdateIconPositionForWindow(WmWindow* window) override;
   gfx::Rect GetScreenBoundsOfItemIconForWindow(WmWindow* window) override;
+  void UpdateAutoHideForMouseEvent(ui::MouseEvent* event) override;
+  void UpdateAutoHideForGestureEvent(ui::GestureEvent* event) override;
   void AddObserver(WmShelfObserver* observer) override;
   void RemoveObserver(WmShelfObserver* observer) override;
 
diff --git a/ash/mus/bridge/wm_window_mus.cc b/ash/mus/bridge/wm_window_mus.cc
index 09b0c06..c822398 100644
--- a/ash/mus/bridge/wm_window_mus.cc
+++ b/ash/mus/bridge/wm_window_mus.cc
@@ -155,6 +155,10 @@
   return parent && parent->children_use_extended_hit_region_;
 }
 
+bool WmWindowMus::IsContainer() const {
+  return GetShellWindowId() != kShellWindowId_Invalid;
+}
+
 const WmWindow* WmWindowMus::GetRootWindow() const {
   return Get(window_->GetRoot());
 }
diff --git a/ash/mus/bridge/wm_window_mus.h b/ash/mus/bridge/wm_window_mus.h
index c7a907e..2f17ee2 100644
--- a/ash/mus/bridge/wm_window_mus.h
+++ b/ash/mus/bridge/wm_window_mus.h
@@ -97,6 +97,9 @@
   // See description of |children_use_extended_hit_region_|.
   bool ShouldUseExtendedHitRegion() const;
 
+  // Returns true if this window is considered a shell window container.
+  bool IsContainer() const;
+
   // WmWindow:
   const WmWindow* GetRootWindow() const override;
   WmRootWindowController* GetRootWindowController() override;
diff --git a/ash/mus/disconnected_app_handler.cc b/ash/mus/disconnected_app_handler.cc
index 5631a7b..9499bbf 100644
--- a/ash/mus/disconnected_app_handler.cc
+++ b/ash/mus/disconnected_app_handler.cc
@@ -4,16 +4,65 @@
 
 #include "ash/mus/disconnected_app_handler.h"
 
+#include "ash/common/shell_window_ids.h"
+#include "ash/mus/bridge/wm_window_mus.h"
+
 namespace ash {
 namespace mus {
+namespace {
 
-DisconnectedAppHandler::DisconnectedAppHandler() {}
+bool IsContainer(::mus::Window* window) {
+  return WmWindowMus::Get(window)->IsContainer();
+}
+
+}  // namespace
+
+DisconnectedAppHandler::DisconnectedAppHandler(::mus::Window* root_window) {
+  WmWindowMus* root = WmWindowMus::Get(root_window);
+  for (int shell_window_id = kShellWindowId_Min;
+       shell_window_id < kShellWindowId_Max; ++shell_window_id) {
+    // kShellWindowId_VirtualKeyboardContainer is lazily created.
+    // TODO(sky): http://crbug.com/616909 .
+    // kShellWindowId_PhantomWindow is not a container, but a window.
+    if (shell_window_id == kShellWindowId_VirtualKeyboardContainer ||
+        shell_window_id == kShellWindowId_PhantomWindow)
+      continue;
+
+// kShellWindowId_MouseCursorContainer is chromeos specific.
+#if !defined(OS_CHROMEOS)
+    if (shell_window_id == kShellWindowId_MouseCursorContainer)
+      continue;
+#endif
+
+    WmWindowMus* container = WmWindowMus::AsWmWindowMus(
+        root->GetChildByShellWindowId(shell_window_id));
+    Add(container->mus_window());
+
+    // Add any pre-existing windows in the container to
+    // |disconnected_app_handler_|.
+    for (::mus::Window* child : container->mus_window()->children()) {
+      if (!IsContainer(child))
+        Add(child);
+    }
+  }
+}
 
 DisconnectedAppHandler::~DisconnectedAppHandler() {}
 
 void DisconnectedAppHandler::OnWindowEmbeddedAppDisconnected(
     ::mus::Window* window) {
-  window->Destroy();
+  if (!IsContainer(window))
+    window->Destroy();
+}
+
+void DisconnectedAppHandler::OnTreeChanging(const TreeChangeParams& params) {
+  if (params.old_parent == params.receiver && IsContainer(params.old_parent))
+    Remove(params.target);
+
+  if (params.new_parent == params.receiver && IsContainer(params.new_parent))
+    Add(params.target);
+
+  ::mus::WindowTracker::OnTreeChanging(params);
 }
 
 }  // namespace mus
diff --git a/ash/mus/disconnected_app_handler.h b/ash/mus/disconnected_app_handler.h
index dfec2c5..769cddc 100644
--- a/ash/mus/disconnected_app_handler.h
+++ b/ash/mus/disconnected_app_handler.h
@@ -12,15 +12,16 @@
 namespace mus {
 
 // Tracks mus::Windows for when they get disconnected from the embedded app.
-// Currently closes a window upon disconnection.
+// Destroys the window upon disconnection.
 class DisconnectedAppHandler : public ::mus::WindowTracker {
  public:
-  DisconnectedAppHandler();
+  explicit DisconnectedAppHandler(::mus::Window* root_window);
   ~DisconnectedAppHandler() override;
 
  private:
   // mus::WindowObserver:
   void OnWindowEmbeddedAppDisconnected(::mus::Window* window) override;
+  void OnTreeChanging(const TreeChangeParams& params) override;
 
   DISALLOW_COPY_AND_ASSIGN(DisconnectedAppHandler);
 };
diff --git a/ash/mus/manifest.json b/ash/mus/manifest.json
index 06d79fc..db0cad4 100644
--- a/ash/mus/manifest.json
+++ b/ash/mus/manifest.json
@@ -8,7 +8,7 @@
     },
     "required": {
       "*": { "classes": [ "app" ] },
-      "mojo:mus": { "interfaces": [ "mus::mojom::WindowManagerFactoryService" ] }
+      "mojo:mus": { "interfaces": [ "mus::mojom::WindowManagerWindowTreeFactory" ] }
     }
   }
 }
diff --git a/ash/mus/root_window_controller.cc b/ash/mus/root_window_controller.cc
index 32814fd..967ae72 100644
--- a/ash/mus/root_window_controller.cc
+++ b/ash/mus/root_window_controller.cc
@@ -12,6 +12,7 @@
 #include "ash/common/root_window_controller_common.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/always_on_top_controller.h"
+#include "ash/common/wm/container_finder.h"
 #include "ash/common/wm/dock/docked_window_layout_manager.h"
 #include "ash/common/wm/panels/panel_layout_manager.h"
 #include "ash/common/wm/root_window_layout_manager.h"
@@ -22,24 +23,22 @@
 #include "ash/mus/bridge/wm_shell_mus.h"
 #include "ash/mus/bridge/wm_window_mus.h"
 #include "ash/mus/container_ids.h"
+#include "ash/mus/non_client_frame_controller.h"
+#include "ash/mus/property_util.h"
 #include "ash/mus/screenlock_layout.h"
-#include "ash/mus/shadow_controller.h"
 #include "ash/mus/shelf_layout_manager.h"
 #include "ash/mus/status_layout_manager.h"
 #include "ash/mus/window_manager.h"
-#include "ash/mus/window_manager_application.h"
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
-#include "components/mus/common/event_matcher_util.h"
 #include "components/mus/common/switches.h"
 #include "components/mus/common/util.h"
 #include "components/mus/public/cpp/property_type_converters.h"
 #include "components/mus/public/cpp/window.h"
+#include "components/mus/public/cpp/window_property.h"
 #include "components/mus/public/cpp/window_tree_client.h"
 #include "components/mus/public/cpp/window_tree_host_factory.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "mash/session/public/interfaces/session.mojom.h"
 #include "mojo/public/cpp/bindings/type_converter.h"
 #include "services/shell/public/cpp/connector.h"
 #include "ui/display/mojo/display_type_converters.h"
@@ -50,12 +49,6 @@
 namespace mus {
 namespace {
 
-const uint32_t kWindowSwitchAccelerator = 1;
-
-void AssertTrue(bool success) {
-  DCHECK(success);
-}
-
 class WorkspaceLayoutManagerDelegateImpl
     : public wm::WorkspaceLayoutManagerDelegate {
  public:
@@ -81,30 +74,79 @@
 
 }  // namespace
 
-// static
-RootWindowController* RootWindowController::CreateFromDisplay(
-    WindowManagerApplication* app,
-    ::mus::mojom::DisplayPtr display,
-    ::mus::mojom::WindowTreeClientRequest client_request) {
-  RootWindowController* controller = new RootWindowController(app);
-  controller->display_ = display.To<display::Display>();
-  new ::mus::WindowTreeClient(controller, controller->window_manager_.get(),
-                              std::move(client_request));
-  return controller;
+RootWindowController::RootWindowController(WindowManager* window_manager,
+                                           ::mus::Window* root,
+                                           const display::Display& display)
+    : window_manager_(window_manager),
+      root_(root),
+      window_count_(0),
+      display_(display) {
+  wm_root_window_controller_.reset(
+      new WmRootWindowControllerMus(window_manager_->shell(), this));
+
+  root_window_controller_common_.reset(
+      new RootWindowControllerCommon(WmWindowMus::Get(root_)));
+  root_window_controller_common_->CreateContainers();
+  root_window_controller_common_->CreateLayoutManagers();
+  CreateLayoutManagers();
+
+  disconnected_app_handler_.reset(new DisconnectedAppHandler(root));
+
+  // Force a layout of the root, and its children, RootWindowLayout handles
+  // both.
+  root_window_controller_common_->root_window_layout()->OnWindowResized();
+
+  for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
+    window_manager_->window_manager_client()->AddActivationParent(
+        GetWindowByShellWindowId(kActivatableShellWindowIds[i])->mus_window());
+  }
+
+  WmWindowMus* always_on_top_container =
+      GetWindowByShellWindowId(kShellWindowId_AlwaysOnTopContainer);
+  always_on_top_controller_.reset(
+      new AlwaysOnTopController(always_on_top_container));
 }
 
-void RootWindowController::Destroy() {
-  // See class description for details on lifetime.
-  if (root_) {
-    delete root_->window_tree();
-  } else {
-    // This case only happens if we're destroyed before OnEmbed().
-    delete this;
-  }
-}
+RootWindowController::~RootWindowController() {}
 
 shell::Connector* RootWindowController::GetConnector() {
-  return app_->connector();
+  return window_manager_->connector();
+}
+
+::mus::Window* RootWindowController::NewTopLevelWindow(
+    std::map<std::string, std::vector<uint8_t>>* properties) {
+  // TODO(sky): panels need a different frame, http:://crbug.com/614362.
+  const bool provide_non_client_frame =
+      GetWindowType(*properties) == ::mus::mojom::WindowType::WINDOW ||
+      GetWindowType(*properties) == ::mus::mojom::WindowType::PANEL;
+  if (provide_non_client_frame)
+    (*properties)[::mus::mojom::kWaitForUnderlay_Property].clear();
+
+  // TODO(sky): constrain and validate properties before passing to server.
+  ::mus::Window* window = root_->window_tree()->NewWindow(properties);
+  window->SetBounds(CalculateDefaultBounds(window));
+
+  ::mus::Window* container_window = nullptr;
+  mojom::Container container;
+  if (GetRequestedContainer(window, &container)) {
+    container_window = GetWindowForContainer(container);
+  } else {
+    // TODO(sky): window->bounds() isn't quite right.
+    container_window = WmWindowMus::GetMusWindow(wm::GetDefaultParent(
+        WmWindowMus::Get(root_), WmWindowMus::Get(window), window->bounds()));
+  }
+  DCHECK(WmWindowMus::Get(container_window)->IsContainer());
+
+  if (provide_non_client_frame) {
+    NonClientFrameController::Create(GetConnector(), container_window, window,
+                                     window_manager_->window_manager_client());
+  } else {
+    container_window->AddChild(window);
+  }
+
+  window_count_++;
+
+  return window;
 }
 
 ::mus::Window* RootWindowController::GetWindowForContainer(
@@ -115,31 +157,11 @@
   return wm_window->mus_window();
 }
 
-bool RootWindowController::WindowIsContainer(::mus::Window* window) {
-  return window &&
-         WmWindowMus::Get(window)->GetShellWindowId() != kShellWindowId_Invalid;
-}
-
 WmWindowMus* RootWindowController::GetWindowByShellWindowId(int id) {
   return WmWindowMus::AsWmWindowMus(
       WmWindowMus::Get(root_)->GetChildByShellWindowId(id));
 }
 
-::mus::WindowManagerClient* RootWindowController::window_manager_client() {
-  return window_manager_->window_manager_client();
-}
-
-void RootWindowController::OnAccelerator(uint32_t id, const ui::Event& event) {
-  switch (id) {
-    case kWindowSwitchAccelerator:
-      window_manager_client()->ActivateNextWindow();
-      break;
-    default:
-      app_->OnAccelerator(id, event);
-      break;
-  }
-}
-
 ShelfLayoutManager* RootWindowController::GetShelfLayoutManager() {
   return static_cast<ShelfLayoutManager*>(
       layout_managers_[GetWindowForContainer(Container::USER_PRIVATE_SHELF)]
@@ -151,78 +173,27 @@
       layout_managers_[GetWindowForContainer(Container::STATUS)].get());
 }
 
-RootWindowController::RootWindowController(WindowManagerApplication* app)
-    : app_(app), root_(nullptr), window_count_(0) {
-  window_manager_.reset(new WindowManager);
-}
-
-RootWindowController::~RootWindowController() {}
-
-void RootWindowController::AddAccelerators() {
-  window_manager_client()->AddAccelerator(
-      kWindowSwitchAccelerator,
-      ::mus::CreateKeyMatcher(ui::mojom::KeyboardCode::TAB,
-                              ui::mojom::kEventFlagControlDown),
-      base::Bind(&AssertTrue));
-}
-
-void RootWindowController::OnEmbed(::mus::Window* root) {
-  root_ = root;
-  root_->AddObserver(this);
-
-  app_->OnRootWindowControllerGotRoot(this);
-
-  wm_root_window_controller_.reset(
-      new WmRootWindowControllerMus(app_->shell(), this));
-
-  root_window_controller_common_.reset(
-      new RootWindowControllerCommon(WmWindowMus::Get(root_)));
-  root_window_controller_common_->CreateContainers();
-  root_window_controller_common_->CreateLayoutManagers();
-  CreateLayoutManagers();
-
-  // Force a layout of the root, and its children, RootWindowLayout handles
-  // both.
-  root_window_controller_common_->root_window_layout()->OnWindowResized();
-
-  for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
-    window_manager_client()->AddActivationParent(
-        GetWindowByShellWindowId(kActivatableShellWindowIds[i])->mus_window());
+gfx::Rect RootWindowController::CalculateDefaultBounds(
+    ::mus::Window* window) const {
+  if (window->HasSharedProperty(
+          ::mus::mojom::WindowManager::kInitialBounds_Property)) {
+    return window->GetSharedProperty<gfx::Rect>(
+        ::mus::mojom::WindowManager::kInitialBounds_Property);
   }
 
-  WmWindowMus* always_on_top_container =
-      GetWindowByShellWindowId(kShellWindowId_AlwaysOnTopContainer);
-  always_on_top_controller_.reset(
-      new AlwaysOnTopController(always_on_top_container));
-
-  AddAccelerators();
-
-  window_manager_->Initialize(this, app_->session());
-
-  shadow_controller_.reset(new ShadowController(root->window_tree()));
-
-  app_->OnRootWindowControllerDoneInit(this);
-}
-
-void RootWindowController::OnWindowTreeClientDestroyed(
-    ::mus::WindowTreeClient* client) {
-  shadow_controller_.reset();
-  delete this;
-}
-
-void RootWindowController::OnEventObserved(const ui::Event& event,
-                                           ::mus::Window* target) {
-  // Does not use EventObservers.
-}
-
-void RootWindowController::OnWindowDestroyed(::mus::Window* window) {
-  DCHECK_EQ(window, root_);
-  app_->OnRootWindowDestroyed(this);
-  root_->RemoveObserver(this);
-  // Delete the |window_manager_| here so that WindowManager doesn't have to
-  // worry about the possibility of |root_| being null.
-  window_manager_.reset();
-  root_ = nullptr;
+  int width, height;
+  const gfx::Size pref = GetWindowPreferredSize(window);
+  if (pref.IsEmpty()) {
+    width = root_->bounds().width() - 240;
+    height = root_->bounds().height() - 240;
+  } else {
+    // TODO(sky): likely want to constrain more than root size.
+    const gfx::Size max_size = root_->bounds().size();
+    width = std::max(0, std::min(max_size.width(), pref.width()));
+    height = std::max(0, std::min(max_size.height(), pref.height()));
+  }
+  return gfx::Rect(40 + (window_count_ % 4) * 40, 40 + (window_count_ % 4) * 40,
+                   width, height);
 }
 
 void RootWindowController::OnShelfWindowAvailable() {
diff --git a/ash/mus/root_window_controller.h b/ash/mus/root_window_controller.h
index d2a96f2..3a45cdbd 100644
--- a/ash/mus/root_window_controller.h
+++ b/ash/mus/root_window_controller.h
@@ -7,28 +7,17 @@
 
 #include <memory>
 
+#include "ash/mus/disconnected_app_handler.h"
 #include "ash/mus/shelf_layout_manager_delegate.h"
 #include "ash/public/interfaces/container.mojom.h"
 #include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_tree_client.h"
-#include "components/mus/public/cpp/window_tree_client_delegate.h"
 #include "components/mus/public/interfaces/window_manager_constants.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
 #include "ui/display/display.h"
 
-namespace mus {
-class WindowManagerClient;
-}
-
 namespace shell {
 class Connector;
 }
 
-namespace ui {
-class Event;
-}
-
 namespace ash {
 
 class AlwaysOnTopController;
@@ -37,11 +26,9 @@
 namespace mus {
 
 class LayoutManager;
-class ShadowController;
 class ShelfLayoutManager;
 class StatusLayoutManager;
 class WindowManager;
-class WindowManagerApplication;
 class WmRootWindowControllerMus;
 class WmShelfMus;
 class WmTestBase;
@@ -49,38 +36,30 @@
 class WmWindowMus;
 
 // RootWindowController manages the windows and state for a single display.
-//
-// RootWindowController deletes itself when the root mus::Window is destroyed.
-// You can trigger deletion explicitly by way of Destroy().
-class RootWindowController : public ::mus::WindowObserver,
-                             public ::mus::WindowTreeClientDelegate,
-                             public ShelfLayoutManagerDelegate {
+// RootWindowController is tied to the lifetime of the ::mus::Window it is
+// created with. It is assumed the RootWindowController is deleted once the
+// associated ::mus::Window is destroyed.
+class RootWindowController : public ShelfLayoutManagerDelegate {
  public:
-  static RootWindowController* CreateFromDisplay(
-      WindowManagerApplication* app,
-      ::mus::mojom::DisplayPtr display,
-      mojo::InterfaceRequest<::mus::mojom::WindowTreeClient> client_request);
-
-  // Deletes this.
-  void Destroy();
+  RootWindowController(WindowManager* window_manager,
+                       ::mus::Window* root,
+                       const display::Display& display);
+  ~RootWindowController() override;
 
   shell::Connector* GetConnector();
 
   ::mus::Window* root() { return root_; }
 
   int window_count() { return window_count_; }
-  void IncrementWindowCount() { ++window_count_; }
+
+  ::mus::Window* NewTopLevelWindow(
+      std::map<std::string, std::vector<uint8_t>>* properties);
 
   ::mus::Window* GetWindowForContainer(mojom::Container container);
-  bool WindowIsContainer(::mus::Window* window);
 
   WmWindowMus* GetWindowByShellWindowId(int id);
 
-  WindowManager* window_manager() { return window_manager_.get(); }
-
-  ::mus::WindowManagerClient* window_manager_client();
-
-  void OnAccelerator(uint32_t id, const ui::Event& event);
+  WindowManager* window_manager() { return window_manager_; }
 
   const display::Display& display() const { return display_; }
 
@@ -97,18 +76,8 @@
   friend class WmTestBase;
   friend class WmTestHelper;
 
-  explicit RootWindowController(WindowManagerApplication* app);
-  ~RootWindowController() override;
-
-  void AddAccelerators();
-
-  // WindowTreeClientDelegate:
-  void OnEmbed(::mus::Window* root) override;
-  void OnWindowTreeClientDestroyed(::mus::WindowTreeClient* client) override;
-  void OnEventObserved(const ui::Event& event, ::mus::Window* target) override;
-
-  // ::mus::WindowObserver:
-  void OnWindowDestroyed(::mus::Window* window) override;
+  gfx::Rect CalculateDefaultBounds(::mus::Window* window) const;
+  gfx::Rect GetMaximizedWindowBounds() const;
 
   // ShelfLayoutManagerDelegate:
   void OnShelfWindowAvailable() override;
@@ -116,25 +85,23 @@
   // Creates the necessary set of layout managers in the shell windows.
   void CreateLayoutManagers();
 
-  WindowManagerApplication* app_;
+  WindowManager* window_manager_;
   ::mus::Window* root_;
-  int window_count_;
+  int window_count_ = 0;
+
+  display::Display display_;
 
   std::unique_ptr<RootWindowControllerCommon> root_window_controller_common_;
 
   std::unique_ptr<WmRootWindowControllerMus> wm_root_window_controller_;
   std::unique_ptr<WmShelfMus> wm_shelf_;
 
-  std::unique_ptr<WindowManager> window_manager_;
-
   std::map<::mus::Window*, std::unique_ptr<LayoutManager>> layout_managers_;
 
-  std::unique_ptr<ShadowController> shadow_controller_;
-
-  display::Display display_;
-
   std::unique_ptr<AlwaysOnTopController> always_on_top_controller_;
 
+  std::unique_ptr<DisconnectedAppHandler> disconnected_app_handler_;
+
   DISALLOW_COPY_AND_ASSIGN(RootWindowController);
 };
 
diff --git a/ash/mus/root_windows_observer.h b/ash/mus/root_windows_observer.h
index 9df1111..9ef27e5 100644
--- a/ash/mus/root_windows_observer.h
+++ b/ash/mus/root_windows_observer.h
@@ -13,8 +13,11 @@
 class RootWindowsObserver {
  public:
   // Called once a new display has been created and the root Window obtained.
-  virtual void OnRootWindowControllerAdded(
-      RootWindowController* controller) = 0;
+  virtual void OnRootWindowControllerAdded(RootWindowController* controller) {}
+
+  // Called before a RootWindowController is destroyed.
+  virtual void OnWillDestroyRootWindowController(
+      RootWindowController* controller) {}
 
  protected:
   ~RootWindowsObserver() {}
diff --git a/ash/mus/test/wm_test_base.cc b/ash/mus/test/wm_test_base.cc
index f99703ce..0811793 100644
--- a/ash/mus/test/wm_test_base.cc
+++ b/ash/mus/test/wm_test_base.cc
@@ -200,8 +200,9 @@
 }
 
 std::vector<RootWindowController*> WmTestBase::GetRootsOrderedByDisplayId() {
-  std::set<RootWindowController*> roots =
-      test_helper_->window_manager_app()->GetRootControllers();
+  std::set<RootWindowController*> roots = test_helper_->window_manager_app()
+                                              ->window_manager()
+                                              ->GetRootWindowControllers();
   std::vector<RootWindowController*> ordered_roots;
   ordered_roots.insert(ordered_roots.begin(), roots.begin(), roots.end());
   std::sort(ordered_roots.begin(), ordered_roots.end(), &CompareByDisplayId);
diff --git a/ash/mus/test/wm_test_helper.cc b/ash/mus/test/wm_test_helper.cc
index ab16f62..0fbf4266 100644
--- a/ash/mus/test/wm_test_helper.cc
+++ b/ash/mus/test/wm_test_helper.cc
@@ -8,8 +8,10 @@
 #include "ash/mus/test/wm_test_screen.h"
 #include "ash/mus/window_manager.h"
 #include "ash/mus/window_manager_application.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "components/mus/public/cpp/property_type_converters.h"
+#include "components/mus/public/cpp/tests/window_tree_client_private.h"
 #include "components/mus/public/cpp/window_tree_client.h"
 #include "ui/display/display.h"
 
@@ -22,31 +24,32 @@
 
 void WmTestHelper::Init() {
   message_loop_.reset(new base::MessageLoopForUI());
-  const uint32_t app_id = 1;
-  window_manager_app_.Initialize(nullptr, shell::Identity(), app_id);
+  window_manager_app_.window_manager_.reset(
+      new WindowManager(&window_manager_app_, nullptr));
   screen_ = new WmTestScreen;
-  window_manager_app_.screen_.reset(screen_);
+  window_manager_app_.window_manager_->screen_.reset(screen_);
 
-  // RootWindowController controls its own lifetime.
-  RootWindowController* root_window_controller =
-      new RootWindowController(&window_manager_app_);
   // Need an id other than kInvalidDisplayID so the Display is considered valid.
-  root_window_controller->display_.set_id(1);
+  display::Display display(1);
   const gfx::Rect display_bounds(0, 0, 800, 600);
-  root_window_controller->display_.set_bounds(display_bounds);
+  display.set_bounds(display_bounds);
   // Offset the height slightly to give a different work area. -20 is arbitrary,
   // it could be anything.
   const gfx::Rect work_area(0, 0, display_bounds.width(),
                             display_bounds.height() - 20);
-  root_window_controller->display_.set_work_area(work_area);
+  display.set_work_area(work_area);
+  window_tree_client_setup_.InitForWindowManager(
+      window_manager_app_.window_manager_.get(),
+      window_manager_app_.window_manager_.get(), display);
 
-  screen_->display_list()->AddDisplay(root_window_controller->display(),
+  window_manager_app_.InitWindowManager(
+      window_tree_client_setup_.window_tree_client());
+
+  screen_->display_list()->AddDisplay(display,
                                       views::DisplayList::Type::PRIMARY);
 
-  window_tree_client_setup_.Init(root_window_controller,
-                                 root_window_controller->window_manager_.get());
-  root_window_controller->root()->SetBounds(display_bounds);
-  window_manager_app_.AddRootWindowController(root_window_controller);
+  ::mus::WindowTreeClientPrivate(window_tree_client_setup_.window_tree_client())
+      .CallWmNewDisplayAdded(display);
 }
 
 }  // namespace mus
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc
index 9605c5c..3be7ba8 100644
--- a/ash/mus/window_manager.cc
+++ b/ash/mus/window_manager.cc
@@ -9,12 +9,17 @@
 #include <utility>
 
 #include "ash/common/shell_window_ids.h"
-#include "ash/common/wm/container_finder.h"
+#include "ash/mus/bridge/wm_lookup_mus.h"
+#include "ash/mus/bridge/wm_shell_mus.h"
 #include "ash/mus/bridge/wm_window_mus.h"
 #include "ash/mus/non_client_frame_controller.h"
 #include "ash/mus/property_util.h"
 #include "ash/mus/root_window_controller.h"
+#include "ash/mus/root_windows_observer.h"
+#include "ash/mus/shadow_controller.h"
+#include "ash/mus/window_manager_application.h"
 #include "ash/public/interfaces/container.mojom.h"
+#include "components/mus/common/event_matcher_util.h"
 #include "components/mus/common/types.h"
 #include "components/mus/public/cpp/property_type_converters.h"
 #include "components/mus/public/cpp/window.h"
@@ -23,52 +28,33 @@
 #include "components/mus/public/interfaces/mus_constants.mojom.h"
 #include "components/mus/public/interfaces/window_manager.mojom.h"
 #include "ui/events/mojo/event.mojom.h"
+#include "ui/views/mus/screen_mus.h"
 
 namespace ash {
 namespace mus {
 
-WindowManager::WindowManager()
-    : root_controller_(nullptr),
-      window_manager_client_(nullptr),
-      binding_(this) {}
+const uint32_t kWindowSwitchAccelerator = 1;
 
-WindowManager::~WindowManager() {}
+void AssertTrue(bool success) {
+  DCHECK(success);
+}
 
-void WindowManager::Initialize(RootWindowController* root_controller,
-                               mash::session::mojom::Session* session) {
-  DCHECK(root_controller);
-  DCHECK(!root_controller_);
-  root_controller_ = root_controller;
+WindowManager::WindowManager(WindowManagerApplication* window_manager_app,
+                             shell::Connector* connector)
+    : window_manager_app_(window_manager_app), connector_(connector) {}
 
-  // Observe all the containers so that windows can be added to/removed from the
-  // |disconnected_app_handler_|.
-  WmWindowMus* root = WmWindowMus::Get(root_controller_->root());
-  for (int shell_window_id = kShellWindowId_Min;
-       shell_window_id < kShellWindowId_Max; ++shell_window_id) {
-    // kShellWindowId_VirtualKeyboardContainer is lazily created.
-    // TODO(sky): http://crbug.com/616909 .
-    // kShellWindowId_PhantomWindow is not a container, but a window.
-    if (shell_window_id == kShellWindowId_VirtualKeyboardContainer ||
-        shell_window_id == kShellWindowId_PhantomWindow)
-      continue;
+WindowManager::~WindowManager() {
+  // NOTE: |window_tree_client_| may already be null.
+  delete window_tree_client_;
+}
 
-// kShellWindowId_MouseCursorContainer is chromeos specific.
-#if !defined(OS_CHROMEOS)
-    if (shell_window_id == kShellWindowId_MouseCursorContainer)
-      continue;
-#endif
+void WindowManager::Init(::mus::WindowTreeClient* window_tree_client) {
+  DCHECK(!window_tree_client_);
+  window_tree_client_ = window_tree_client;
 
-    WmWindowMus* container = WmWindowMus::AsWmWindowMus(
-        root->GetChildByShellWindowId(shell_window_id));
-    Add(container->mus_window());
+  shadow_controller_.reset(new ShadowController(window_tree_client));
 
-    // Add any pre-existing windows in the container to
-    // |disconnected_app_handler_|.
-    for (::mus::Window* child : container->mus_window()->children()) {
-      if (!root_controller_->WindowIsContainer(child))
-        disconnected_app_handler_.Add(child);
-    }
-  }
+  AddAccelerators();
 
   // The insets are roughly what is needed by CustomFrameView. The expectation
   // is at some point we'll write our own NonClientFrameView and get the insets
@@ -84,93 +70,121 @@
   window_manager_client_->SetFrameDecorationValues(
       std::move(frame_decoration_values));
 
-  if (session)
-    session->AddScreenlockStateListener(binding_.CreateInterfacePtrAndBind());
+  shell_.reset(new WmShellMus(window_tree_client_));
+  lookup_.reset(new WmLookupMus);
+}
+
+void WindowManager::SetScreenLocked(bool is_locked) {
+  // TODO: screen locked state needs to be persisted for newly added displays.
+  for (auto& root_window_controller : root_window_controllers_) {
+    WmWindowMus* non_lock_screen_containers_container =
+        root_window_controller->GetWindowByShellWindowId(
+            kShellWindowId_NonLockScreenContainersContainer);
+    non_lock_screen_containers_container->mus_window()->SetVisible(!is_locked);
+  }
 }
 
 ::mus::Window* WindowManager::NewTopLevelWindow(
     std::map<std::string, std::vector<uint8_t>>* properties) {
-  DCHECK(root_controller_);
-  ::mus::Window* root = root_controller_->root();
-  DCHECK(root);
-
-  // TODO(sky): panels need a different frame, http:://crbug.com/614362.
-  const bool provide_non_client_frame =
-      GetWindowType(*properties) == ::mus::mojom::WindowType::WINDOW ||
-      GetWindowType(*properties) == ::mus::mojom::WindowType::PANEL;
-  if (provide_non_client_frame)
-    (*properties)[::mus::mojom::kWaitForUnderlay_Property].clear();
-
-  // TODO(sky): constrain and validate properties before passing to server.
-  ::mus::Window* window = root->window_tree()->NewWindow(properties);
-  window->SetBounds(CalculateDefaultBounds(window));
-
-  ::mus::Window* container_window = nullptr;
-  mojom::Container container;
-  if (GetRequestedContainer(window, &container)) {
-    container_window = root_controller_->GetWindowForContainer(container);
-  } else {
-    // TODO(sky): window->bounds() isn't quite right.
-    container_window = WmWindowMus::GetMusWindow(
-        wm::GetDefaultParent(WmWindowMus::Get(root_controller_->root()),
-                             WmWindowMus::Get(window), window->bounds()));
-  }
-  DCHECK(root_controller_->WindowIsContainer(container_window));
-
-  if (provide_non_client_frame) {
-    NonClientFrameController::Create(root_controller_->GetConnector(),
-                                     container_window, window,
-                                     root_controller_->window_manager_client());
-  } else {
-    container_window->AddChild(window);
-  }
-
-  root_controller_->IncrementWindowCount();
-
-  return window;
+  // TODO(sky): need to maintain active as well as allowing specifying display.
+  RootWindowController* root_window_controller =
+      root_window_controllers_.begin()->get();
+  return root_window_controller->NewTopLevelWindow(properties);
 }
 
-gfx::Rect WindowManager::CalculateDefaultBounds(::mus::Window* window) const {
-  if (window->HasSharedProperty(
-          ::mus::mojom::WindowManager::kInitialBounds_Property)) {
-    return window->GetSharedProperty<gfx::Rect>(
-        ::mus::mojom::WindowManager::kInitialBounds_Property);
-  }
-
-  DCHECK(root_controller_);
-  int width, height;
-  const gfx::Size pref = GetWindowPreferredSize(window);
-  const ::mus::Window* root = root_controller_->root();
-  if (pref.IsEmpty()) {
-    width = root->bounds().width() - 240;
-    height = root->bounds().height() - 240;
-  } else {
-    // TODO(sky): likely want to constrain more than root size.
-    const gfx::Size max_size = GetMaximizedWindowBounds().size();
-    width = std::max(0, std::min(max_size.width(), pref.width()));
-    height = std::max(0, std::min(max_size.height(), pref.height()));
-  }
-  return gfx::Rect(40 + (root_controller_->window_count() % 4) * 40,
-                   40 + (root_controller_->window_count() % 4) * 40, width,
-                   height);
+std::set<RootWindowController*> WindowManager::GetRootWindowControllers() {
+  std::set<RootWindowController*> result;
+  for (auto& root_window_controller : root_window_controllers_)
+    result.insert(root_window_controller.get());
+  return result;
 }
 
-gfx::Rect WindowManager::GetMaximizedWindowBounds() const {
-  DCHECK(root_controller_);
-  return gfx::Rect(root_controller_->root()->bounds().size());
+void WindowManager::AddRootWindowsObserver(RootWindowsObserver* observer) {
+  root_windows_observers_.AddObserver(observer);
 }
 
-void WindowManager::OnTreeChanging(const TreeChangeParams& params) {
-  DCHECK(root_controller_);
-  if (params.old_parent == params.receiver &&
-      root_controller_->WindowIsContainer(params.old_parent))
-    disconnected_app_handler_.Remove(params.target);
+void WindowManager::RemoveRootWindowsObserver(RootWindowsObserver* observer) {
+  root_windows_observers_.RemoveObserver(observer);
+}
 
-  if (params.new_parent == params.receiver &&
-      root_controller_->WindowIsContainer(params.new_parent))
-    disconnected_app_handler_.Add(params.target);
+void WindowManager::AddAccelerators() {
+  // TODO(sky): this is broke for multi-display case. Need to fix mus to
+  // deal correctly.
+  window_manager_client_->AddAccelerator(
+      kWindowSwitchAccelerator,
+      ::mus::CreateKeyMatcher(ui::mojom::KeyboardCode::TAB,
+                              ui::mojom::kEventFlagControlDown),
+      base::Bind(&AssertTrue));
+}
 
-  ::mus::WindowTracker::OnTreeChanging(params);
+RootWindowController* WindowManager::CreateRootWindowController(
+    ::mus::Window* window,
+    const display::Display& display) {
+  // TODO(sky): there is timing issues with using ScreenMus.
+  if (!screen_) {
+    std::unique_ptr<views::ScreenMus> screen(new views::ScreenMus(nullptr));
+    screen->Init(connector_);
+    screen_ = std::move(screen);
+  }
+
+  std::unique_ptr<RootWindowController> root_window_controller_ptr(
+      new RootWindowController(this, window, display));
+  RootWindowController* root_window_controller =
+      root_window_controller_ptr.get();
+  root_window_controllers_.insert(std::move(root_window_controller_ptr));
+  window->AddObserver(this);
+
+  FOR_EACH_OBSERVER(RootWindowsObserver, root_windows_observers_,
+                    OnRootWindowControllerAdded(root_window_controller));
+  return root_window_controller;
+}
+
+void WindowManager::OnWindowDestroying(::mus::Window* window) {
+  for (auto it = root_window_controllers_.begin();
+       it != root_window_controllers_.end(); ++it) {
+    if ((*it)->root() == window) {
+      FOR_EACH_OBSERVER(RootWindowsObserver, root_windows_observers_,
+                        OnWillDestroyRootWindowController((*it).get()));
+      return;
+    }
+  }
+  NOTREACHED();
+}
+
+void WindowManager::OnWindowDestroyed(::mus::Window* window) {
+  window->RemoveObserver(this);
+  for (auto it = root_window_controllers_.begin();
+       it != root_window_controllers_.end(); ++it) {
+    if ((*it)->root() == window) {
+      root_window_controllers_.erase(it);
+      return;
+    }
+  }
+  NOTREACHED();
+}
+
+void WindowManager::OnEmbed(::mus::Window* root) {
+  // WindowManager should never see this, instead OnWmNewDisplay() is called.
+  NOTREACHED();
+}
+
+void WindowManager::OnWindowTreeClientDestroyed(
+    ::mus::WindowTreeClient* client) {
+  // Destroying the roots should result in removal from
+  // |root_window_controllers_|.
+  DCHECK(root_window_controllers_.empty());
+
+  lookup_.reset();
+  shell_.reset();
+  shadow_controller_.reset();
+
+  window_tree_client_ = nullptr;
+  // TODO(sky): this should likely shutdown.
+}
+
+void WindowManager::OnEventObserved(const ui::Event& event,
+                                    ::mus::Window* target) {
+  // Does not use EventObservers.
 }
 
 void WindowManager::SetWindowManagerClient(::mus::WindowManagerClient* client) {
@@ -210,15 +224,20 @@
     SetWindowIsJanky(window, janky);
 }
 
-void WindowManager::OnAccelerator(uint32_t id, const ui::Event& event) {
-  root_controller_->OnAccelerator(id, std::move(event));
+void WindowManager::OnWmNewDisplay(::mus::Window* window,
+                                   const display::Display& display) {
+  CreateRootWindowController(window, display);
 }
 
-void WindowManager::ScreenlockStateChanged(bool locked) {
-  WmWindowMus* non_lock_screen_containers_container =
-      root_controller_->GetWindowByShellWindowId(
-          kShellWindowId_NonLockScreenContainersContainer);
-  non_lock_screen_containers_container->mus_window()->SetVisible(!locked);
+void WindowManager::OnAccelerator(uint32_t id, const ui::Event& event) {
+  switch (id) {
+    case kWindowSwitchAccelerator:
+      window_manager_client()->ActivateNextWindow();
+      break;
+    default:
+      window_manager_app_->OnAccelerator(id, event);
+      break;
+  }
 }
 
 }  // namespace mus
diff --git a/ash/mus/window_manager.h b/ash/mus/window_manager.h
index eeb605ad..a922d52 100644
--- a/ash/mus/window_manager.h
+++ b/ash/mus/window_manager.h
@@ -8,46 +8,86 @@
 #include <stdint.h>
 
 #include <memory>
+#include <set>
 
-#include "ash/mus/disconnected_app_handler.h"
 #include "base/macros.h"
+#include "base/observer_list.h"
 #include "components/mus/common/types.h"
 #include "components/mus/public/cpp/window_manager_delegate.h"
 #include "components/mus/public/cpp/window_observer.h"
-#include "components/mus/public/cpp/window_tracker.h"
+#include "components/mus/public/cpp/window_tree_client_delegate.h"
 #include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "mash/session/public/interfaces/session.mojom.h"
-#include "mojo/public/cpp/bindings/binding.h"
+
+namespace display {
+class Display;
+class Screen;
+}
+
+namespace shell {
+class Connector;
+}
 
 namespace ash {
 namespace mus {
 
 class RootWindowController;
+class RootWindowsObserver;
+class ShadowController;
+class WindowManagerApplication;
+class WmShellMus;
+class WmLookupMus;
+class WmTestHelper;
 
-class WindowManager : public ::mus::WindowTracker,
-                      public ::mus::WindowManagerDelegate,
-                      public mash::session::mojom::ScreenlockStateListener {
+// WindowManager serves as the WindowManagerDelegate and
+// WindowTreeClientDelegate for mash. WindowManager creates (and owns)
+// a RootWindowController per Display. WindowManager takes ownership of
+// the WindowTreeClient.
+class WindowManager : public ::mus::WindowManagerDelegate,
+                      public ::mus::WindowObserver,
+                      public ::mus::WindowTreeClientDelegate {
  public:
-  WindowManager();
+  WindowManager(WindowManagerApplication* window_manager_app,
+                shell::Connector* connector);
   ~WindowManager() override;
 
-  void Initialize(RootWindowController* root_controller,
-                  mash::session::mojom::Session* session);
+  void Init(::mus::WindowTreeClient* window_tree_client);
+
+  WmShellMus* shell() { return shell_.get(); }
 
   ::mus::WindowManagerClient* window_manager_client() {
     return window_manager_client_;
   }
 
+  shell::Connector* connector() { return connector_; }
+
+  void SetScreenLocked(bool is_locked);
+
   // Creates a new top level window.
   ::mus::Window* NewTopLevelWindow(
       std::map<std::string, std::vector<uint8_t>>* properties);
 
+  std::set<RootWindowController*> GetRootWindowControllers();
+
+  void AddRootWindowsObserver(RootWindowsObserver* observer);
+  void RemoveRootWindowsObserver(RootWindowsObserver* observer);
+
  private:
-  gfx::Rect CalculateDefaultBounds(::mus::Window* window) const;
-  gfx::Rect GetMaximizedWindowBounds() const;
+  friend class WmTestHelper;
+
+  void AddAccelerators();
+
+  RootWindowController* CreateRootWindowController(
+      ::mus::Window* window,
+      const display::Display& display);
 
   // ::mus::WindowObserver:
-  void OnTreeChanging(const TreeChangeParams& params) override;
+  void OnWindowDestroying(::mus::Window* window) override;
+  void OnWindowDestroyed(::mus::Window* window) override;
+
+  // WindowTreeClientDelegate:
+  void OnEmbed(::mus::Window* root) override;
+  void OnWindowTreeClientDestroyed(::mus::WindowTreeClient* client) override;
+  void OnEventObserved(const ui::Event& event, ::mus::Window* target) override;
 
   // WindowManagerDelegate:
   void SetWindowManagerClient(::mus::WindowManagerClient* client) override;
@@ -61,16 +101,30 @@
   void OnWmClientJankinessChanged(
       const std::set<::mus::Window*>& client_windows,
       bool not_responding) override;
+  void OnWmNewDisplay(::mus::Window* window,
+                      const display::Display& display) override;
   void OnAccelerator(uint32_t id, const ui::Event& event) override;
 
-  // session::mojom::ScreenlockStateListener:
-  void ScreenlockStateChanged(bool locked) override;
+  // TODO(sky): this is unfortunate, remove.
+  WindowManagerApplication* window_manager_app_;
 
-  RootWindowController* root_controller_;
-  ::mus::WindowManagerClient* window_manager_client_;
-  DisconnectedAppHandler disconnected_app_handler_;
+  shell::Connector* connector_;
 
-  mojo::Binding<mash::session::mojom::ScreenlockStateListener> binding_;
+  ::mus::WindowTreeClient* window_tree_client_ = nullptr;
+
+  ::mus::WindowManagerClient* window_manager_client_ = nullptr;
+
+  std::unique_ptr<ShadowController> shadow_controller_;
+
+  std::set<std::unique_ptr<RootWindowController>> root_window_controllers_;
+
+  base::ObserverList<RootWindowsObserver> root_windows_observers_;
+
+  std::unique_ptr<display::Screen> screen_;
+
+  std::unique_ptr<WmShellMus> shell_;
+
+  std::unique_ptr<WmLookupMus> lookup_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowManager);
 };
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc
index 20bb19b..a6b85af 100644
--- a/ash/mus/window_manager_application.cc
+++ b/ash/mus/window_manager_application.cc
@@ -7,29 +7,27 @@
 #include <utility>
 
 #include "ash/mus/accelerator_registrar_impl.h"
-#include "ash/mus/bridge/wm_lookup_mus.h"
-#include "ash/mus/bridge/wm_shell_mus.h"
 #include "ash/mus/root_window_controller.h"
 #include "ash/mus/root_windows_observer.h"
 #include "ash/mus/shelf_layout_impl.h"
 #include "ash/mus/user_window_controller_impl.h"
+#include "ash/mus/window_manager.h"
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "components/mus/common/event_matcher_util.h"
 #include "components/mus/public/cpp/window.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
+#include "components/mus/public/cpp/window_tree_client.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/tracing/public/cpp/tracing_impl.h"
 #include "ui/events/event.h"
 #include "ui/views/mus/aura_init.h"
-#include "ui/views/mus/screen_mus.h"
 
 namespace ash {
 namespace mus {
 
 WindowManagerApplication::WindowManagerApplication()
-    : connector_(nullptr), window_manager_factory_binding_(this) {}
+    : connector_(nullptr), screenlock_state_listener_binding_(this) {}
 
 WindowManagerApplication::~WindowManagerApplication() {
   // AcceleratorRegistrarImpl removes an observer in its destructor. Destroy
@@ -39,61 +37,9 @@
   for (AcceleratorRegistrarImpl* registrar : accelerator_registrars)
     registrar->Destroy();
 
-  std::set<RootWindowController*> controllers(root_controllers_);
-  for (RootWindowController* controller : controllers)
-    controller->Destroy();
-}
-
-std::set<RootWindowController*> WindowManagerApplication::GetRootControllers() {
-  std::set<RootWindowController*> root_controllers;
-  for (RootWindowController* controller : root_controllers_) {
-    if (controller->root())
-      root_controllers.insert(controller);
-  }
-  return root_controllers;
-}
-
-void WindowManagerApplication::OnRootWindowControllerGotRoot(
-    RootWindowController* root_controller) {
-  if (shell_)
-    return;  // |root_controller| is the > 1 root, nothing to do.
-
-  if (connector_)
-    aura_init_.reset(new views::AuraInit(connector_, "ash_mus_resources.pak"));
-
-  shell_.reset(new WmShellMus(root_controller->root()->window_tree()));
-  lookup_.reset(new WmLookupMus);
-}
-
-void WindowManagerApplication::OnRootWindowControllerDoneInit(
-    RootWindowController* root_controller) {
-  if (!screen_) {
-    std::unique_ptr<views::ScreenMus> screen(new views::ScreenMus(nullptr));
-    screen->Init(connector_);
-    screen_ = std::move(screen);
-  }
-
-  // TODO(msw): figure out if this should be per display, or global.
-  user_window_controller_->Initialize(root_controller);
-  for (auto& request : user_window_controller_requests_)
-    user_window_controller_bindings_.AddBinding(user_window_controller_.get(),
-                                                std::move(*request));
-  user_window_controller_requests_.clear();
-
-  // TODO(msw): figure out if this should be per display, or global.
-  shelf_layout_->Initialize(root_controller);
-  for (auto& request : shelf_layout_requests_)
-    shelf_layout_bindings_.AddBinding(shelf_layout_.get(), std::move(*request));
-  shelf_layout_requests_.clear();
-
-  FOR_EACH_OBSERVER(RootWindowsObserver, root_windows_observers_,
-                    OnRootWindowControllerAdded(root_controller));
-}
-
-void WindowManagerApplication::OnRootWindowDestroyed(
-    RootWindowController* root_controller) {
-  root_controllers_.erase(root_controller);
-  user_window_controller_.reset(nullptr);
+  // Destroy the WindowManager while still valid. This way we ensure
+  // OnWillDestroyRootWindowController() is called (if it hasn't been already).
+  window_manager_.reset();
 }
 
 void WindowManagerApplication::OnAccelerator(uint32_t id,
@@ -106,49 +52,43 @@
   }
 }
 
-void WindowManagerApplication::AddRootWindowsObserver(
-    RootWindowsObserver* observer) {
-  root_windows_observers_.AddObserver(observer);
-}
-
-void WindowManagerApplication::RemoveRootWindowsObserver(
-    RootWindowsObserver* observer) {
-  root_windows_observers_.RemoveObserver(observer);
-}
-
 void WindowManagerApplication::OnAcceleratorRegistrarDestroyed(
     AcceleratorRegistrarImpl* registrar) {
   accelerator_registrars_.erase(registrar);
 }
 
-void WindowManagerApplication::AddRootWindowController(
-    RootWindowController* root_window_controller) {
-  root_controllers_.insert(root_window_controller);
+void WindowManagerApplication::InitWindowManager(
+    ::mus::WindowTreeClient* window_tree_client) {
+  window_manager_->Init(window_tree_client);
+  window_manager_->AddRootWindowsObserver(this);
 }
 
 void WindowManagerApplication::Initialize(shell::Connector* connector,
                                           const shell::Identity& identity,
                                           uint32_t id) {
   connector_ = connector;
-  if (connector) {
-    tracing_.Initialize(connector, identity.name());
+  window_manager_.reset(new WindowManager(this, connector_));
 
-    ::mus::mojom::WindowManagerFactoryServicePtr wm_factory_service;
-    connector_->ConnectToInterface("mojo:mus", &wm_factory_service);
-    wm_factory_service->SetWindowManagerFactory(
-        window_manager_factory_binding_.CreateInterfacePtrAndBind());
-  }
+  aura_init_.reset(new views::AuraInit(connector_, "ash_mus_resources.pak"));
 
-  shelf_layout_.reset(new ShelfLayoutImpl);
-  user_window_controller_.reset(new UserWindowControllerImpl());
+  tracing_.Initialize(connector, identity.name());
+
+  ::mus::WindowTreeClient* window_tree_client = new ::mus::WindowTreeClient(
+      window_manager_.get(), window_manager_.get(), nullptr);
+  window_tree_client->ConnectAsWindowManager(connector);
+
+  InitWindowManager(window_tree_client);
 }
 
 bool WindowManagerApplication::AcceptConnection(shell::Connection* connection) {
   connection->AddInterface<mojom::ShelfLayout>(this);
   connection->AddInterface<mojom::UserWindowController>(this);
   connection->AddInterface<::mus::mojom::AcceleratorRegistrar>(this);
-  if (connection->GetRemoteIdentity().name() == "mojo:mash_session")
+  if (connection->GetRemoteIdentity().name() == "mojo:mash_session") {
     connection->GetInterface(&session_);
+    session_->AddScreenlockStateListener(
+        screenlock_state_listener_binding_.CreateInterfacePtrAndBind());
+  }
   return true;
 }
 
@@ -156,7 +96,7 @@
     shell::Connection* connection,
     mojo::InterfaceRequest<mojom::ShelfLayout> request) {
   // TODO(msw): Handle multiple shelves (one per display).
-  if (!root_controllers_.empty() && (*root_controllers_.begin())->root()) {
+  if (!window_manager_->GetRootWindowControllers().empty()) {
     shelf_layout_bindings_.AddBinding(shelf_layout_.get(), std::move(request));
   } else {
     shelf_layout_requests_.push_back(base::WrapUnique(
@@ -167,7 +107,7 @@
 void WindowManagerApplication::Create(
     shell::Connection* connection,
     mojo::InterfaceRequest<mojom::UserWindowController> request) {
-  if (!root_controllers_.empty() && (*root_controllers_.begin())->root()) {
+  if (!window_manager_->GetRootWindowControllers().empty()) {
     user_window_controller_bindings_.AddBinding(user_window_controller_.get(),
                                                 std::move(request));
   } else {
@@ -190,16 +130,48 @@
     accelerator_registrar_count = 0;
   }
   accelerator_registrars_.insert(new AcceleratorRegistrarImpl(
-      this, ++accelerator_registrar_count, std::move(request),
+      window_manager_.get(), ++accelerator_registrar_count, std::move(request),
       base::Bind(&WindowManagerApplication::OnAcceleratorRegistrarDestroyed,
                  base::Unretained(this))));
 }
 
-void WindowManagerApplication::CreateWindowManager(
-    ::mus::mojom::DisplayPtr display,
-    mojo::InterfaceRequest<::mus::mojom::WindowTreeClient> client_request) {
-  AddRootWindowController(RootWindowController::CreateFromDisplay(
-      this, std::move(display), std::move(client_request)));
+void WindowManagerApplication::ScreenlockStateChanged(bool locked) {
+  window_manager_->SetScreenLocked(locked);
+}
+
+void WindowManagerApplication::OnRootWindowControllerAdded(
+    RootWindowController* controller) {
+  if (user_window_controller_)
+    return;
+
+  // TODO(sky): |shelf_layout_| and |user_window_controller_| should really
+  // be owned by WindowManager and/or RootWindowController. But this code is
+  // temporary while migrating away from sysui.
+
+  shelf_layout_.reset(new ShelfLayoutImpl);
+  user_window_controller_.reset(new UserWindowControllerImpl());
+
+  // TODO(msw): figure out if this should be per display, or global.
+  user_window_controller_->Initialize(controller);
+  for (auto& request : user_window_controller_requests_)
+    user_window_controller_bindings_.AddBinding(user_window_controller_.get(),
+                                                std::move(*request));
+  user_window_controller_requests_.clear();
+
+  // TODO(msw): figure out if this should be per display, or global.
+  shelf_layout_->Initialize(controller);
+  for (auto& request : shelf_layout_requests_)
+    shelf_layout_bindings_.AddBinding(shelf_layout_.get(), std::move(*request));
+  shelf_layout_requests_.clear();
+}
+
+void WindowManagerApplication::OnWillDestroyRootWindowController(
+    RootWindowController* controller) {
+  // TODO(msw): this isn't right, ownership should belong in WindowManager
+  // and/or RootWindowController. But this is temporary until we get rid of
+  // sysui.
+  shelf_layout_.reset();
+  user_window_controller_.reset();
 }
 
 }  // namespace mus
diff --git a/ash/mus/window_manager_application.h b/ash/mus/window_manager_application.h
index 65ef494..16a51bc 100644
--- a/ash/mus/window_manager_application.h
+++ b/ash/mus/window_manager_application.h
@@ -10,23 +10,20 @@
 #include <memory>
 #include <set>
 
+#include "ash/mus/root_windows_observer.h"
 #include "ash/public/interfaces/shelf_layout.mojom.h"
 #include "ash/public/interfaces/user_window_controller.mojom.h"
 #include "base/macros.h"
-#include "base/observer_list.h"
 #include "components/mus/common/types.h"
 #include "components/mus/public/interfaces/accelerator_registrar.mojom.h"
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
-#include "components/mus/public/interfaces/window_tree_host.mojom.h"
 #include "mash/session/public/interfaces/session.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/shell/public/cpp/shell_client.h"
 #include "services/tracing/public/cpp/tracing_impl.h"
 
-namespace display {
-class Screen;
+namespace mus {
+class WindowTreeClient;
 }
 
 namespace views {
@@ -42,49 +39,28 @@
 
 class AcceleratorRegistrarImpl;
 class RootWindowController;
-class RootWindowsObserver;
 class ShelfLayoutImpl;
 class UserWindowControllerImpl;
-class WmShellMus;
-class WmLookupMus;
-class WmScreen;
+class WindowManager;
 
 class WindowManagerApplication
     : public shell::ShellClient,
-      public ::mus::mojom::WindowManagerFactory,
       public shell::InterfaceFactory<mojom::ShelfLayout>,
       public shell::InterfaceFactory<mojom::UserWindowController>,
-      public shell::InterfaceFactory<::mus::mojom::AcceleratorRegistrar> {
+      public shell::InterfaceFactory<::mus::mojom::AcceleratorRegistrar>,
+      public mash::session::mojom::ScreenlockStateListener,
+      public RootWindowsObserver {
  public:
   WindowManagerApplication();
   ~WindowManagerApplication() override;
 
   shell::Connector* connector() { return connector_; }
 
-  // Returns the RootWindowControllers that have valid roots.
-  //
-  // NOTE: this does not return |controllers_| as most clients want a
-  // RootWindowController that has a valid root window.
-  std::set<RootWindowController*> GetRootControllers();
-
-  WmShellMus* shell() { return shell_.get(); }
-
-  // Called when the root window of |root_controller| is obtained.
-  void OnRootWindowControllerGotRoot(RootWindowController* root_controller);
-
-  // Called after RootWindowController creates the necessary resources.
-  void OnRootWindowControllerDoneInit(RootWindowController* root_controller);
-
-  // Called when the root mus::Window of RootWindowController is destroyed.
-  // |root_controller| is destroyed after this call.
-  void OnRootWindowDestroyed(RootWindowController* root_controller);
+  WindowManager* window_manager() { return window_manager_.get(); }
 
   // TODO(sky): figure out right place for this code.
   void OnAccelerator(uint32_t id, const ui::Event& event);
 
-  void AddRootWindowsObserver(RootWindowsObserver* observer);
-  void RemoveRootWindowsObserver(RootWindowsObserver* observer);
-
   mash::session::mojom::Session* session() { return session_.get(); }
 
  private:
@@ -93,8 +69,7 @@
 
   void OnAcceleratorRegistrarDestroyed(AcceleratorRegistrarImpl* registrar);
 
-  // Adds |root_window_controller| to the set of known roots.
-  void AddRootWindowController(RootWindowController* root_window_controller);
+  void InitWindowManager(::mus::WindowTreeClient* window_tree_client);
 
   // shell::ShellClient:
   void Initialize(shell::Connector* connector,
@@ -116,22 +91,20 @@
               mojo::InterfaceRequest<::mus::mojom::AcceleratorRegistrar>
                   request) override;
 
-  // mus::mojom::WindowManagerFactory:
-  void CreateWindowManager(
-      ::mus::mojom::DisplayPtr display,
-      mojo::InterfaceRequest<::mus::mojom::WindowTreeClient> client_request)
-      override;
+  // session::mojom::ScreenlockStateListener:
+  void ScreenlockStateChanged(bool locked) override;
+
+  // RootWindowsObserver:
+  void OnRootWindowControllerAdded(RootWindowController* controller) override;
+  void OnWillDestroyRootWindowController(
+      RootWindowController* controller) override;
 
   shell::Connector* connector_;
 
   mojo::TracingImpl tracing_;
 
-  std::unique_ptr<display::Screen> screen_;
   std::unique_ptr<views::AuraInit> aura_init_;
 
-  std::unique_ptr<WmShellMus> shell_;
-  std::unique_ptr<WmLookupMus> lookup_;
-
   // The |shelf_layout_| object is created once OnEmbed() is called. Until that
   // time |shelf_layout_requests_| stores pending interface requests.
   std::unique_ptr<ShelfLayoutImpl> shelf_layout_;
@@ -148,15 +121,14 @@
       std::unique_ptr<mojo::InterfaceRequest<mojom::UserWindowController>>>
       user_window_controller_requests_;
 
-  std::set<AcceleratorRegistrarImpl*> accelerator_registrars_;
-  std::set<RootWindowController*> root_controllers_;
+  std::unique_ptr<WindowManager> window_manager_;
 
-  mojo::Binding<::mus::mojom::WindowManagerFactory>
-      window_manager_factory_binding_;
+  std::set<AcceleratorRegistrarImpl*> accelerator_registrars_;
 
   mash::session::mojom::SessionPtr session_;
 
-  base::ObserverList<RootWindowsObserver> root_windows_observers_;
+  mojo::Binding<mash::session::mojom::ScreenlockStateListener>
+      screenlock_state_listener_binding_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowManagerApplication);
 };
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 4863239c..8fc703e 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -7,11 +7,11 @@
 #include <queue>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/aura/aura_layout_manager_adapter.h"
 #include "ash/aura/wm_shelf_aura.h"
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/focus_cycler.h"
 #include "ash/common/root_window_controller_common.h"
 #include "ash/common/session/session_state_delegate.h"
@@ -763,8 +763,8 @@
   WmWindow* status_container =
       WmWindowAura::Get(GetContainer(kShellWindowId_StatusContainer));
   shelf_widget_.reset(new ShelfWidget(shelf_container, status_container,
+                                      wm_shelf_aura_.get(),
                                       workspace_controller()));
-  wm_shelf_aura_->SetShelfLayoutManager(shelf_widget_->shelf_layout_manager());
   workspace_layout_manager_delegate->set_shelf(
       shelf_widget_->shelf_layout_manager());
 
diff --git a/ash/shelf/overflow_button.cc b/ash/shelf/overflow_button.cc
index 4f1aa840..45130f72 100644
--- a/ash/shelf/overflow_button.cc
+++ b/ash/shelf/overflow_button.cc
@@ -4,8 +4,8 @@
 
 #include "ash/shelf/overflow_button.h"
 
-#include "ash/ash_switches.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/system/tray/tray_constants.h"
diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc
index 0f5d112..2d9f4d1 100644
--- a/ash/shelf/shelf_button.cc
+++ b/ash/shelf/shelf_button.cc
@@ -6,8 +6,8 @@
 
 #include <algorithm>
 
-#include "ash/ash_switches.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/shelf/ink_drop_button_listener.h"
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 4757e88f..1376d72d 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -11,8 +11,8 @@
 #include <vector>
 
 #include "ash/accelerators/accelerator_commands.h"
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/shelf/wm_shelf_util.h"
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index 4bfafa3..b95932a53 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -6,7 +6,7 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accelerators/accelerator_table.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/focus_cycler.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_constants.h"
diff --git a/ash/shelf/shelf_navigator_unittest.cc b/ash/shelf/shelf_navigator_unittest.cc
index fcaa0467..af2411aee 100644
--- a/ash/shelf/shelf_navigator_unittest.cc
+++ b/ash/shelf/shelf_navigator_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "ash/shelf/shelf_navigator.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_item_types.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/shelf/shelf.h"
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index b5f5e722..3d798c8 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -7,9 +7,9 @@
 #include <algorithm>
 #include <memory>
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/shelf/shelf_item_delegate_manager.h"
 #include "ash/common/shelf/shelf_menu_model.h"
@@ -1676,10 +1676,7 @@
       CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName());
       ShelfButton* button = static_cast<ShelfButton*>(view);
       ReflectItemStatus(item, button);
-      // The browser shortcut is currently not a "real" item and as such the
-      // the image is bogous as well. We therefore keep the image as is for it.
-      if (item.type != TYPE_BROWSER_SHORTCUT)
-        button->SetImage(item.image);
+      button->SetImage(item.image);
       button->SchedulePaint();
       break;
     }
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 2425b78c..4665343 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -4,9 +4,9 @@
 
 #include "ash/shelf/shelf_widget.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_shelf_aura.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/focus_cycler.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/session/session_state_delegate.h"
@@ -565,6 +565,7 @@
 
 ShelfWidget::ShelfWidget(WmWindow* wm_shelf_container,
                          WmWindow* wm_status_container,
+                         WmShelfAura* wm_shelf_aura,
                          WorkspaceController* workspace_controller)
     : delegate_view_(new DelegateView(this)),
       background_animator_(
@@ -592,8 +593,11 @@
   shelf_container->SetLayoutManager(shelf_layout_manager_);
   shelf_layout_manager_->set_workspace_controller(workspace_controller);
   workspace_controller->SetShelf(shelf_layout_manager_);
+  wm_shelf_aura->SetShelfLayoutManager(shelf_layout_manager_);
 
-  status_area_widget_ = new StatusAreaWidget(wm_status_container, this);
+  // TODO(jamescook): Move ownership to RootWindowController.
+  status_area_widget_ =
+      new StatusAreaWidget(wm_status_container, wm_shelf_aura);
   status_area_widget_->CreateTrayViews();
   if (Shell::GetInstance()->session_state_delegate()->
           IsActiveUserSessionStarted()) {
diff --git a/ash/shelf/shelf_widget.h b/ash/shelf/shelf_widget.h
index 8180c16..af6de3d 100644
--- a/ash/shelf/shelf_widget.h
+++ b/ash/shelf/shelf_widget.h
@@ -30,6 +30,7 @@
  public:
   ShelfWidget(WmWindow* wm_shelf_container,
               WmWindow* wm_status_container,
+              WmShelfAura* wm_shelf_aura,
               WorkspaceController* workspace_controller);
   ~ShelfWidget() override;
 
diff --git a/ash/shelf/shelf_window_watcher_unittest.cc b/ash/shelf/shelf_window_watcher_unittest.cc
index 39aee2bb..34dac4b 100644
--- a/ash/shelf/shelf_window_watcher_unittest.cc
+++ b/ash/shelf/shelf_window_watcher_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "ash/shelf/shelf_window_watcher.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_item_types.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shell_window_ids.h"
diff --git a/ash/shell.cc b/ash/shell.cc
index e1260682..8502d67d 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -11,10 +11,10 @@
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accelerators/accelerator_delegate.h"
 #include "ash/accelerators/focus_manager_factory.h"
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_shell_aura.h"
 #include "ash/aura/wm_window_aura.h"
 #include "ash/autoclick/autoclick_controller.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_item_delegate.h"
 #include "ash/common/shelf/shelf_item_delegate_manager.h"
diff --git a/ash/shell/content/client/shell_browser_main_parts.cc b/ash/shell/content/client/shell_browser_main_parts.cc
index dc25eb47..4151fb0 100644
--- a/ash/shell/content/client/shell_browser_main_parts.cc
+++ b/ash/shell/content/client/shell_browser_main_parts.cc
@@ -4,7 +4,7 @@
 
 #include "ash/shell/content/client/shell_browser_main_parts.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/content/shell_content_state.h"
 #include "ash/desktop_background/desktop_background_controller.h"
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index 2398fae..c9040949 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -7,7 +7,7 @@
 #include <algorithm>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/desktop_background/desktop_background_widget_controller.h"
diff --git a/ash/system/DEPS b/ash/system/DEPS
index 246c8e1..12841b5 100644
--- a/ash/system/DEPS
+++ b/ash/system/DEPS
@@ -1,4 +1,6 @@
 include_rules = [
+  # NOTE: Use WmShelf for all external shelf access. http://crbug.com/615502
+  "-ash/shelf/shelf_widget.h",
   "-chromeos",
   "+components/prefs",
   "+components/signin/core/account_id",
diff --git a/ash/system/chromeos/network/network_state_list_detailed_view.cc b/ash/system/chromeos/network/network_state_list_detailed_view.cc
index c8e951d..53050b4 100644
--- a/ash/system/chromeos/network/network_state_list_detailed_view.cc
+++ b/ash/system/chromeos/network/network_state_list_detailed_view.cc
@@ -7,8 +7,8 @@
 #include <algorithm>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/system/networking_config_delegate.h"
 #include "ash/common/system/tray/fixed_sized_image_view.h"
diff --git a/ash/system/chromeos/network/tray_network.cc b/ash/system/chromeos/network/tray_network.cc
index 2d87003..a8a2900 100644
--- a/ash/system/chromeos/network/tray_network.cc
+++ b/ash/system/chromeos/network/tray_network.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/chromeos/network/tray_network.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/system/tray/tray_constants.h"
diff --git a/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc b/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc
index 69606ed..afa036f 100644
--- a/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc
+++ b/ash/system/chromeos/rotation/tray_rotation_lock_unittest.cc
@@ -6,12 +6,11 @@
 
 #include <memory>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/display/display_manager.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
diff --git a/ash/system/ime/tray_ime_chromeos.cc b/ash/system/ime/tray_ime_chromeos.cc
index 829ecfe..d3a119a 100644
--- a/ash/system/ime/tray_ime_chromeos.cc
+++ b/ash/system/ime/tray_ime_chromeos.cc
@@ -16,7 +16,6 @@
 #include "ash/common/wm_shell.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/system/tray/system_tray_notifier.h"
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc
index c398123..cbc9909 100644
--- a/ash/system/overview/overview_button_tray_unittest.cc
+++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -4,13 +4,12 @@
 
 #include "ash/system/overview/overview_button_tray.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/common/wm_shell.h"
 #include "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/rotator/screen_rotation_animator.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/user/login_status.h"
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index 57d82b6..1cdc306 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -4,15 +4,12 @@
 
 #include "ash/system/status_area_widget.h"
 
+#include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_widget.h"
-#include "ash/shell.h"
-#include "ash/shell_delegate.h"
 #include "ash/system/overview/overview_button_tray.h"
 #include "ash/system/status_area_widget_delegate.h"
 #include "ash/system/tray/system_tray.h"
@@ -28,7 +25,7 @@
 namespace ash {
 
 StatusAreaWidget::StatusAreaWidget(WmWindow* status_container,
-                                   ShelfWidget* shelf_widget)
+                                   WmShelf* wm_shelf)
     : status_area_widget_delegate_(new StatusAreaWidgetDelegate),
       overview_button_tray_(NULL),
       system_tray_(NULL),
@@ -38,7 +35,7 @@
       virtual_keyboard_tray_(NULL),
 #endif
       login_status_(LoginStatus::NOT_LOGGED_IN),
-      shelf_widget_(shelf_widget) {
+      wm_shelf_(wm_shelf) {
   views::Widget::InitParams params(
       views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
   params.delegate = status_area_widget_delegate_;
@@ -102,7 +99,7 @@
        web_notification_tray_->ShouldBlockShelfAutoHide()))
     return true;
 
-  if (!shelf_widget_->shelf()->IsVisible())
+  if (!wm_shelf_->IsVisible())
     return false;
 
   // If the shelf is currently visible, don't hide the shelf if the mouse
@@ -137,14 +134,12 @@
 
 void StatusAreaWidget::OnMouseEvent(ui::MouseEvent* event) {
   Widget::OnMouseEvent(event);
-  if (Shell::GetInstance()->in_mus() && shelf_widget_->shelf_layout_manager())
-    shelf_widget_->shelf_layout_manager()->UpdateAutoHideForMouseEvent(event);
+  wm_shelf_->UpdateAutoHideForMouseEvent(event);
 }
 
 void StatusAreaWidget::OnGestureEvent(ui::GestureEvent* event) {
   Widget::OnGestureEvent(event);
-  if (Shell::GetInstance()->in_mus() && shelf_widget_->shelf_layout_manager())
-    shelf_widget_->shelf_layout_manager()->UpdateAutoHideForGestureEvent(event);
+  wm_shelf_->UpdateAutoHideForGestureEvent(event);
 }
 
 void StatusAreaWidget::AddSystemTray() {
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h
index cb49241..2885354 100644
--- a/ash/system/status_area_widget.h
+++ b/ash/system/status_area_widget.h
@@ -6,18 +6,18 @@
 #define ASH_SYSTEM_STATUS_AREA_WIDGET_H_
 
 #include "ash/ash_export.h"
+#include "ash/common/login_status.h"
 #include "ash/common/shelf/shelf_types.h"
-#include "ash/system/user/login_status.h"
 #include "base/macros.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
 class OverviewButtonTray;
-class ShelfWidget;
 class ShellDelegate;
 class StatusAreaWidgetDelegate;
 class SystemTray;
 class WebNotificationTray;
+class WmShelf;
 class WmWindow;
 #if defined(OS_CHROMEOS)
 class LogoutButtonTray;
@@ -26,7 +26,7 @@
 
 class ASH_EXPORT StatusAreaWidget : public views::Widget {
  public:
-  StatusAreaWidget(WmWindow* status_container, ShelfWidget* shelf_widget);
+  StatusAreaWidget(WmWindow* status_container, WmShelf* wm_shelf);
   ~StatusAreaWidget() override;
 
   // Creates the SystemTray, WebNotificationTray and LogoutButtonTray.
@@ -57,7 +57,7 @@
   OverviewButtonTray* overview_button_tray() {
     return overview_button_tray_;
   }
-  ShelfWidget* shelf_widget() { return shelf_widget_; }
+  WmShelf* wm_shelf() { return wm_shelf_; }
 
   LoginStatus login_status() const { return login_status_; }
 
@@ -98,7 +98,7 @@
 #endif
   LoginStatus login_status_;
 
-  ShelfWidget* shelf_widget_;
+  WmShelf* wm_shelf_;
 
   DISALLOW_COPY_AND_ASSIGN(StatusAreaWidget);
 };
diff --git a/ash/system/status_area_widget_delegate.cc b/ash/system/status_area_widget_delegate.cc
index 017fbff..d7ba5a19 100644
--- a/ash/system/status_area_widget_delegate.cc
+++ b/ash/system/status_area_widget_delegate.cc
@@ -5,7 +5,7 @@
 #include "ash/system/status_area_widget_delegate.h"
 
 #include "ash/ash_export.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/focus_cycler.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shelf/shelf_constants.h"
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index 1fe6be7..c7f95991 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -4,7 +4,9 @@
 
 #include "ash/system/tray/system_tray.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
+#include "ash/common/session/session_state_delegate.h"
+#include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/system/date/tray_date.h"
@@ -14,8 +16,6 @@
 #include "ash/common/system/update/tray_update.h"
 #include "ash/common/wm_shell.h"
 #include "ash/metrics/user_metrics_recorder.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_util.h"
 #include "ash/shell.h"
 #include "ash/system/audio/tray_audio.h"
 #include "ash/system/cast/tray_cast.h"
@@ -31,7 +31,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/timer/timer.h"
 #include "grit/ash_strings.h"
-#include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/display.h"
@@ -531,7 +530,7 @@
   UpdateNotificationBubble();  // State changed, re-create notifications.
   if (!notification_bubble_)
     UpdateWebNotifications();
-  GetShelfLayoutManager()->UpdateAutoHideState();
+  GetShelf()->UpdateAutoHideState();
 
   // When we show the system menu in our alternate shelf layout, we need to
   // tint the background.
@@ -651,7 +650,7 @@
   if (system_bubble_.get() && bubble_view == system_bubble_->bubble_view()) {
     DestroySystemBubble();
     UpdateNotificationBubble();  // State changed, re-create notifications.
-    GetShelfLayoutManager()->UpdateAutoHideState();
+    GetShelf()->UpdateAutoHideState();
   } else if (notification_bubble_.get() &&
              bubble_view == notification_bubble_->bubble_view()) {
     DestroyNotificationBubble();
diff --git a/ash/system/tray/system_tray_unittest.cc b/ash/system/tray/system_tray_unittest.cc
index 3cdc37f38..6e505f2e 100644
--- a/ash/system/tray/system_tray_unittest.cc
+++ b/ash/system/tray/system_tray_unittest.cc
@@ -12,12 +12,12 @@
 #include "ash/common/system/tray/tray_popup_item_container.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray_bubble.h"
 #include "ash/system/web_notification/web_notification_tray.h"
 #include "ash/test/ash_test_base.h"
+#include "ash/test/status_area_widget_test_helper.h"
 #include "ash/wm/window_util.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
@@ -42,17 +42,15 @@
 
 namespace {
 
-SystemTray* GetSystemTray() {
-  return Shell::GetPrimaryRootWindowController()
-      ->shelf_widget()
-      ->status_area_widget()
-      ->system_tray();
-}
-
 // Trivial item implementation that tracks its views for testing.
 class TestItem : public SystemTrayItem {
  public:
-  TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL) {}
+  TestItem()
+      : SystemTrayItem(AshTestBase::GetPrimarySystemTray()),
+        tray_view_(nullptr),
+        default_view_(nullptr),
+        detailed_view_(nullptr),
+        notification_view_(nullptr) {}
 
   views::View* CreateTrayView(LoginStatus status) override {
     tray_view_ = new views::View;
@@ -108,7 +106,7 @@
 // view creation methods.
 class TestNoViewItem : public SystemTrayItem {
  public:
-  TestNoViewItem() : SystemTrayItem(GetSystemTray()) {}
+  TestNoViewItem() : SystemTrayItem(AshTestBase::GetPrimarySystemTray()) {}
 
   views::View* CreateTrayView(LoginStatus status) override { return nullptr; }
 
@@ -148,7 +146,7 @@
 typedef AshTestBase SystemTrayTest;
 
 TEST_F(SystemTrayTest, SystemTrayDefaultView) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
@@ -161,7 +159,7 @@
 
 // Opening and closing the bubble should change the coloring of the tray.
 TEST_F(SystemTrayTest, SystemTrayColoring) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
   // At the beginning the tray coloring is not active.
   ASSERT_FALSE(tray->draw_background_as_active());
@@ -179,7 +177,7 @@
 // Closing the system bubble through an alignment change should change the
 // system tray coloring back to normal.
 TEST_F(SystemTrayTest, SystemTrayColoringAfterAlignmentChange) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
   Shelf* shelf = Shelf::ForPrimaryDisplay();
   shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
@@ -200,7 +198,7 @@
 }
 
 TEST_F(SystemTrayTest, SystemTrayTestItems) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   TestItem* test_item = new TestItem;
@@ -238,7 +236,7 @@
 }
 
 TEST_F(SystemTrayTest, SystemTrayNoViewItems) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   // Verify that no crashes occur on items lacking some views.
@@ -250,7 +248,7 @@
 }
 
 TEST_F(SystemTrayTest, TrayWidgetAutoResizes) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   // Add an initial tray item so that the tray gets laid out correctly.
@@ -279,7 +277,7 @@
 }
 
 TEST_F(SystemTrayTest, SystemTrayNotifications) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   TestItem* test_item = new TestItem;
@@ -314,7 +312,7 @@
 }
 
 TEST_F(SystemTrayTest, BubbleCreationTypesTest) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   TestItem* test_item = new TestItem;
@@ -347,54 +345,40 @@
   EXPECT_EQ(widget, test_item->default_view()->GetWidget());
 }
 
-// Tests that the tray is laid out properly and is fully contained within
-// the shelf.
+// Tests that the tray view is laid out properly and is fully contained within
+// the shelf widget.
 TEST_F(SystemTrayTest, TrayBoundsInWidget) {
   Shelf* shelf = Shelf::ForPrimaryDisplay();
-  StatusAreaWidget* widget = Shell::GetPrimaryRootWindowController()
-                                 ->shelf_widget()
-                                 ->status_area_widget();
-  SystemTray* tray = widget->system_tray();
+  StatusAreaWidget* widget = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
+  SystemTray* tray = GetPrimarySystemTray();
 
   // Test in bottom alignment.
   shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM);
   gfx::Rect window_bounds = widget->GetWindowBoundsInScreen();
   gfx::Rect tray_bounds = tray->GetBoundsInScreen();
-  EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
-  EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
-  EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
-  EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
+  EXPECT_TRUE(window_bounds.Contains(tray_bounds));
 
   // Test in locked alignment.
   shelf->SetAlignment(SHELF_ALIGNMENT_BOTTOM_LOCKED);
   window_bounds = widget->GetWindowBoundsInScreen();
   tray_bounds = tray->GetBoundsInScreen();
-  EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
-  EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
-  EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
-  EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
+  EXPECT_TRUE(window_bounds.Contains(tray_bounds));
 
   // Test in the left alignment.
   shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
   window_bounds = widget->GetWindowBoundsInScreen();
   tray_bounds = tray->GetBoundsInScreen();
-  EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
-  EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
-  EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
-  EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
+  EXPECT_TRUE(window_bounds.Contains(tray_bounds));
 
   // Test in the right alignment.
   shelf->SetAlignment(SHELF_ALIGNMENT_LEFT);
   window_bounds = widget->GetWindowBoundsInScreen();
   tray_bounds = tray->GetBoundsInScreen();
-  EXPECT_TRUE(window_bounds.bottom() >= tray_bounds.bottom());
-  EXPECT_TRUE(window_bounds.right() >= tray_bounds.right());
-  EXPECT_TRUE(window_bounds.x() >= tray_bounds.x());
-  EXPECT_TRUE(window_bounds.y() >= tray_bounds.y());
+  EXPECT_TRUE(window_bounds.Contains(tray_bounds));
 }
 
 TEST_F(SystemTrayTest, PersistentBubble) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   TestItem* test_item = new TestItem;
@@ -451,7 +435,7 @@
       gfx::Rect(0, 0, 100, 100));
   widget->Show();
 
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
 
   ASSERT_TRUE(tray->HasSystemBubble());
@@ -483,7 +467,7 @@
 // Tests that if SetVisible(true) is called while animating to hidden that the
 // tray becomes visible, and stops animating to hidden.
 TEST_F(SystemTrayTest, SetVisibleDuringHideAnimation) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->visible());
 
   std::unique_ptr<ui::ScopedAnimationDurationScaleMode> animation_duration;
@@ -505,7 +489,7 @@
 // Tests that touch on an item in the system bubble triggers it to become
 // active.
 TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedback) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
 
   TrayPopupItemContainer* view =
@@ -525,7 +509,7 @@
 // Tests that touch events on an item in the system bubble cause it to stop
 // being active.
 TEST_F(SystemTrayTest, TrayPopupItemContainerTouchFeedbackCancellation) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   tray->ShowDefaultView(BUBBLE_CREATE_NEW);
 
   TrayPopupItemContainer* view =
@@ -549,10 +533,7 @@
 }
 
 TEST_F(SystemTrayTest, SystemTrayHeightWithBubble) {
-  StatusAreaWidget* widget = Shell::GetPrimaryRootWindowController()
-                                 ->shelf_widget()
-                                 ->status_area_widget();
-  SystemTray* tray = widget->system_tray();
+  SystemTray* tray = GetPrimarySystemTray();
   WebNotificationTray* notification_tray =
       tray->status_area_widget()->web_notification_tray();
 
diff --git a/ash/system/tray/tray_background_view.cc b/ash/system/tray/tray_background_view.cc
index d15806c0..aa5dfe8 100644
--- a/ash/system/tray/tray_background_view.cc
+++ b/ash/system/tray/tray_background_view.cc
@@ -6,14 +6,12 @@
 
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shelf/shelf_constants.h"
+#include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/system/tray/tray_constants.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
-#include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_util.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/status_area_widget_delegate.h"
@@ -105,16 +103,14 @@
   ~TrayBackground() override {}
 
  private:
-  ShelfWidget* GetShelfWidget() const {
-    return tray_background_view_->GetShelfLayoutManager()->shelf_widget();
+  WmShelf* GetShelf() const {
+    return tray_background_view_->GetShelf();
   }
 
   void PaintMaterial(gfx::Canvas* canvas, views::View* view) const {
     SkColor background_color = SK_ColorTRANSPARENT;
-    ShelfWidget* shelf_widget = GetShelfWidget();
-    if (shelf_widget &&
-        shelf_widget->GetBackgroundType() ==
-            ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT) {
+    if (GetShelf()->GetBackgroundType() ==
+        ShelfBackgroundType::SHELF_BACKGROUND_DEFAULT) {
       background_color = SkColorSetA(kShelfBaseColor,
                                      GetShelfConstant(SHELF_BACKGROUND_ALPHA));
     }
@@ -153,17 +149,15 @@
       }
     };
 
-    int orientation = kImageHorizontal;
-    ShelfWidget* shelf_widget = GetShelfWidget();
-    if (shelf_widget &&
-        !shelf_widget->shelf_layout_manager()->IsHorizontalAlignment()) {
-      orientation = kImageVertical;
-    }
+    WmShelf* shelf = GetShelf();
+    const int orientation = IsHorizontalAlignment(shelf->GetAlignment())
+                                ? kImageHorizontal
+                                : kImageVertical;
 
     int state = kImageTypeDefault;
     if (tray_background_view_->draw_background_as_active())
       state = kImageTypePressed;
-    else if (shelf_widget && shelf_widget->GetDimsShelf())
+    else if (shelf->IsDimmed())
       state = kImageTypeOnBlack;
     else
       state = kImageTypeDefault;
@@ -247,6 +241,7 @@
       background_(NULL),
       draw_background_as_active_(false),
       widget_observer_(new TrayWidgetObserver(this)) {
+  DCHECK(status_area_widget->wm_shelf());
   set_notify_enter_exit_on_child(true);
 
   tray_container_ = new TrayContainer(shelf_alignment_);
@@ -389,8 +384,8 @@
   tray_container_->set_background(background_);
 }
 
-ShelfLayoutManager* TrayBackgroundView::GetShelfLayoutManager() {
-  return status_area_widget()->shelf_widget()->shelf_layout_manager();
+WmShelf* TrayBackgroundView::GetShelf() {
+  return status_area_widget_->wm_shelf();
 }
 
 void TrayBackgroundView::SetShelfAlignment(ShelfAlignment alignment) {
diff --git a/ash/system/tray/tray_background_view.h b/ash/system/tray/tray_background_view.h
index 8af71ce..cd7e042 100644
--- a/ash/system/tray/tray_background_view.h
+++ b/ash/system/tray/tray_background_view.h
@@ -20,6 +20,7 @@
 class StatusAreaWidget;
 class TrayEventFilter;
 class TrayBackground;
+class WmShelf;
 
 // Base class for children of StatusAreaWidget: SystemTray, WebNotificationTray,
 // LogoutButtonTray, OverviewButtonTray.
@@ -140,7 +141,7 @@
   ShelfAlignment shelf_alignment() const { return shelf_alignment_; }
   TrayEventFilter* tray_event_filter() { return tray_event_filter_.get(); }
 
-  ShelfLayoutManager* GetShelfLayoutManager();
+  WmShelf* GetShelf();
 
   // Updates the arrow visibility based on the launcher visibility.
   void UpdateBubbleViewArrow(views::TrayBubbleView* bubble_view);
@@ -167,6 +168,7 @@
   TrayContainer* tray_container_;
 
   // Shelf alignment.
+  // TODO(jamescook): Don't cache this, get it from WmShelf.
   ShelfAlignment shelf_alignment_;
 
   // Owned by the view passed to SetContents().
diff --git a/ash/system/tray/tray_details_view_unittest.cc b/ash/system/tray/tray_details_view_unittest.cc
index 9735f15..a4e2293 100644
--- a/ash/system/tray/tray_details_view_unittest.cc
+++ b/ash/system/tray/tray_details_view_unittest.cc
@@ -9,9 +9,6 @@
 #include "ash/common/system/tray/system_tray_item.h"
 #include "ash/common/system/tray/tray_popup_header_button.h"
 #include "ash/common/system/tray/view_click_listener.h"
-#include "ash/root_window_controller.h"
-#include "ash/shelf/shelf_widget.h"
-#include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
 #include "ash/test/ash_test_base.h"
@@ -29,13 +26,6 @@
 
 namespace {
 
-SystemTray* GetSystemTray() {
-  return Shell::GetPrimaryRootWindowController()
-      ->shelf_widget()
-      ->status_area_widget()
-      ->system_tray();
-}
-
 class TestDetailsView : public TrayDetailsView,
                         public ViewClickListener,
                         public views::ButtonListener {
@@ -78,7 +68,11 @@
 // Trivial item implementation that tracks its views for testing.
 class TestItem : public SystemTrayItem {
  public:
-  TestItem() : SystemTrayItem(GetSystemTray()), tray_view_(NULL) {}
+  TestItem()
+      : SystemTrayItem(AshTestBase::GetPrimarySystemTray()),
+        tray_view_(nullptr),
+        default_view_(nullptr),
+        detailed_view_(nullptr) {}
 
   // Overridden from SystemTrayItem:
   views::View* CreateTrayView(LoginStatus status) override {
@@ -118,7 +112,7 @@
   ~TrayDetailsViewTest() override {}
 
   HoverHighlightView* CreateAndShowHoverHighlightView() {
-    SystemTray* tray = GetSystemTray();
+    SystemTray* tray = GetPrimarySystemTray();
     TestItem* test_item = new TestItem;
     tray->AddTrayItem(test_item);
     tray->ShowDefaultView(BUBBLE_CREATE_NEW);
@@ -131,7 +125,7 @@
   }
 
   TrayPopupHeaderButton* CreateAndShowTrayPopupHeaderButton() {
-    SystemTray* tray = GetSystemTray();
+    SystemTray* tray = GetPrimarySystemTray();
     TestItem* test_item = new TestItem;
     tray->AddTrayItem(test_item);
     tray->ShowDefaultView(BUBBLE_CREATE_NEW);
@@ -147,7 +141,7 @@
 };
 
 TEST_F(TrayDetailsViewTest, TransitionToDefaultViewTest) {
-  SystemTray* tray = GetSystemTray();
+  SystemTray* tray = GetPrimarySystemTray();
   ASSERT_TRUE(tray->GetWidget());
 
   TestItem* test_item_1 = new TestItem;
@@ -200,7 +194,7 @@
   HoverHighlightView* view = CreateAndShowHoverHighlightView();
   EXPECT_FALSE(view->hover());
 
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   generator.set_current_location(view->GetBoundsInScreen().CenterPoint());
   generator.PressTouch();
   EXPECT_TRUE(view->hover());
@@ -215,7 +209,7 @@
   EXPECT_FALSE(view->hover());
 
   gfx::Rect view_bounds = view->GetBoundsInScreen();
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   generator.set_current_location(view_bounds.CenterPoint());
   generator.PressTouch();
   EXPECT_TRUE(view->hover());
@@ -234,7 +228,7 @@
   TrayPopupHeaderButton* button = CreateAndShowTrayPopupHeaderButton();
   EXPECT_FALSE(button->background());
 
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   generator.set_current_location(button->GetBoundsInScreen().CenterPoint());
   generator.PressTouch();
   EXPECT_TRUE(button->background());
@@ -250,7 +244,7 @@
   EXPECT_FALSE(button->background());
 
   gfx::Rect view_bounds = button->GetBoundsInScreen();
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   generator.set_current_location(view_bounds.CenterPoint());
   generator.PressTouch();
   EXPECT_TRUE(button->background());
@@ -270,7 +264,7 @@
   TrayPopupHeaderButton* button = CreateAndShowTrayPopupHeaderButton();
   EXPECT_FALSE(button->background());
 
-  ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+  ui::test::EventGenerator& generator = GetEventGenerator();
   gfx::Rect bounds = button->GetBoundsInScreen();
   gfx::Point initial_point(bounds.x() - 1, bounds.y());
   generator.set_current_location(initial_point);
diff --git a/ash/system/user/tray_user.cc b/ash/system/user/tray_user.cc
index 9f5a619..2bf3acdb 100644
--- a/ash/system/user/tray_user.cc
+++ b/ash/system/user/tray_user.cc
@@ -4,7 +4,7 @@
 
 #include "ash/system/user/tray_user.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc
index 122453ef..de86ec2 100644
--- a/ash/system/web_notification/web_notification_tray.cc
+++ b/ash/system/web_notification/web_notification_tray.cc
@@ -4,9 +4,11 @@
 
 #include "ash/system/web_notification/web_notification_tray.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
+#include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shelf/shelf_constants.h"
+#include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/shelf/wm_shelf_util.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/system/tray/tray_constants.h"
@@ -14,7 +16,6 @@
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_window.h"
-#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
@@ -257,9 +258,10 @@
           message_center_tray_.get(),
           true);
 
+  WmShelf* shelf = GetShelf();
   int max_height;
-  if (IsHorizontalAlignment(GetShelfLayoutManager()->GetAlignment())) {
-    max_height = GetShelfLayoutManager()->GetIdealBounds().y();
+  if (IsHorizontalAlignment(shelf->GetAlignment())) {
+    max_height = shelf->GetIdealBounds().y();
   } else {
     // Assume the status area and bubble bottoms are aligned when vertical.
     WmWindow* status_area_window =
@@ -277,7 +279,7 @@
       new WebNotificationBubbleWrapper(this, message_center_bubble));
 
   status_area_widget()->SetHideSystemNotifications(true);
-  GetShelfLayoutManager()->UpdateAutoHideState();
+  shelf->UpdateAutoHideState();
   button_->SetBubbleVisible(true);
   SetDrawBackgroundAsActive(true);
   return true;
@@ -295,7 +297,7 @@
   should_block_shelf_auto_hide_ = false;
   show_message_center_on_unlock_ = false;
   status_area_widget()->SetHideSystemNotifications(false);
-  GetShelfLayoutManager()->UpdateAutoHideState();
+  GetShelf()->UpdateAutoHideState();
   button_->SetBubbleVisible(false);
 }
 
diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc
index 91eeb4f..975222d5 100644
--- a/ash/system/web_notification/web_notification_tray_unittest.cc
+++ b/ash/system/web_notification/web_notification_tray_unittest.cc
@@ -17,7 +17,6 @@
 #include "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_layout_manager.h"
-#include "ash/shelf/shelf_widget.h"
 #include "ash/shell.h"
 #include "ash/system/status_area_widget.h"
 #include "ash/system/tray/system_tray.h"
diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc
index f3bf640..6baece0 100644
--- a/ash/test/ash_test_base.cc
+++ b/ash/test/ash_test_base.cc
@@ -7,7 +7,7 @@
 #include <string>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm/window_positioner.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_shell.h"
@@ -173,6 +173,11 @@
   display::Display::SetInternalDisplayId(display::Display::kInvalidDisplayID);
 }
 
+// static
+SystemTray* AshTestBase::GetPrimarySystemTray() {
+  return Shell::GetInstance()->GetPrimarySystemTray();
+}
+
 ui::test::EventGenerator& AshTestBase::GetEventGenerator() {
   if (!event_generator_) {
     event_generator_.reset(
@@ -286,10 +291,6 @@
   return ash_test_helper_->test_screenshot_delegate();
 }
 
-SystemTray* AshTestBase::GetPrimarySystemTray() {
-  return Shell::GetInstance()->GetPrimarySystemTray();
-}
-
 TestSystemTrayDelegate* AshTestBase::GetSystemTrayDelegate() {
   return static_cast<TestSystemTrayDelegate*>(
       WmShell::Get()->system_tray_delegate());
diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h
index df73c7d..8a7bd7ccf 100644
--- a/ash/test/ash_test_base.h
+++ b/ash/test/ash_test_base.h
@@ -63,6 +63,9 @@
   void SetUp() override;
   void TearDown() override;
 
+  // Returns the system tray on the primary display.
+  static SystemTray* GetPrimarySystemTray();
+
   // Update the display configuration as given in |display_specs|.
   // See ash::test::DisplayManagerTestApi::UpdateDisplay for more details.
   void UpdateDisplay(const std::string& display_specs);
@@ -129,9 +132,6 @@
 
   TestScreenshotDelegate* GetScreenshotDelegate();
 
-  // Returns the system tray on the primary display.
-  SystemTray* GetPrimarySystemTray();
-
   TestSystemTrayDelegate* GetSystemTrayDelegate();
 
   // Utility methods to emulate user logged in or not, session started or not
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc
index 23eb96fc..d6a90f0 100644
--- a/ash/test/ash_test_helper.cc
+++ b/ash/test/ash_test_helper.cc
@@ -5,7 +5,7 @@
 #include "ash/test/ash_test_helper.h"
 
 #include "ash/accelerators/accelerator_controller.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/display/display_info.h"
 #include "ash/shell.h"
diff --git a/ash/test/display_manager_test_api.cc b/ash/test/display_manager_test_api.cc
index 05328cf..5818984 100644
--- a/ash/test/display_manager_test_api.cc
+++ b/ash/test/display_manager_test_api.cc
@@ -7,7 +7,7 @@
 #include <cstdarg>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_info.h"
 #include "ash/display/display_layout_store.h"
 #include "ash/display/display_manager.h"
diff --git a/ash/test/test_suite.cc b/ash/test/test_suite.cc
index 5730fe8..c082591 100644
--- a/ash/test/test_suite.cc
+++ b/ash/test/test_suite.cc
@@ -4,7 +4,7 @@
 
 #include "ash/test/test_suite.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/i18n/rtl.h"
diff --git a/ash/touch/touch_observer_hud_unittest.cc b/ash/touch/touch_observer_hud_unittest.cc
index 926eed3..9b59888 100644
--- a/ash/touch/touch_observer_hud_unittest.cc
+++ b/ash/touch/touch_observer_hud_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "ash/touch/touch_observer_hud.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_manager.h"
 #include "ash/root_window_controller.h"
 #include "ash/screen_util.h"
diff --git a/ash/virtual_keyboard_controller.cc b/ash/virtual_keyboard_controller.cc
index d3a2fea..3dc93db 100644
--- a/ash/virtual_keyboard_controller.cc
+++ b/ash/virtual_keyboard_controller.cc
@@ -6,7 +6,7 @@
 
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm_shell.h"
 #include "ash/shell.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
diff --git a/ash/virtual_keyboard_controller_unittest.cc b/ash/virtual_keyboard_controller_unittest.cc
index 0bab286..875e725 100644
--- a/ash/virtual_keyboard_controller_unittest.cc
+++ b/ash/virtual_keyboard_controller_unittest.cc
@@ -7,12 +7,12 @@
 #include <utility>
 #include <vector>
 
+#include "ash/common/ash_switches.h"
 #include "ash/shell.h"
 #include "ash/system/chromeos/virtual_keyboard/virtual_keyboard_observer.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/wm/maximize_mode/scoped_disable_internal_mouse_and_keyboard.h"
-#include "ash_switches.h"
 #include "base/command_line.h"
 #include "ui/events/devices/device_data_manager.h"
 #include "ui/events/devices/device_hotplug_event_observer.h"
diff --git a/ash/wm/dock/docked_window_layout_manager_unittest.cc b/ash/wm/dock/docked_window_layout_manager_unittest.cc
index 610dddd..e6a72a2 100644
--- a/ash/wm/dock/docked_window_layout_manager_unittest.cc
+++ b/ash/wm/dock/docked_window_layout_manager_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "ash/common/wm/dock/docked_window_layout_manager.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/common/shell_window_ids.h"
diff --git a/ash/wm/dock/docked_window_resizer_unittest.cc b/ash/wm/dock/docked_window_resizer_unittest.cc
index 847b7db2..ee59164 100644
--- a/ash/wm/dock/docked_window_resizer_unittest.cc
+++ b/ash/wm/dock/docked_window_resizer_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "ash/common/wm/dock/docked_window_resizer.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/common/shell_window_ids.h"
diff --git a/ash/wm/lock_state_controller.cc b/ash/wm/lock_state_controller.cc
index 82d49a17..39a3a89 100644
--- a/ash/wm/lock_state_controller.cc
+++ b/ash/wm/lock_state_controller.cc
@@ -8,9 +8,9 @@
 #include <string>
 #include <utility>
 
-#include "ash/ash_switches.h"
 #include "ash/cancel_mode.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/shell.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_controller.cc b/ash/wm/maximize_mode/maximize_mode_controller.cc
index 779a8ee..2cc2fcf5 100644
--- a/ash/wm/maximize_mode/maximize_mode_controller.cc
+++ b/ash/wm/maximize_mode/maximize_mode_controller.cc
@@ -8,7 +8,7 @@
 
 #include "ash/accelerators/accelerator_controller.h"
 #include "ash/accelerators/accelerator_table.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm_shell.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
index ce6e4a06..69c3de24 100644
--- a/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
+++ b/ash/wm/maximize_mode/maximize_mode_controller_unittest.cc
@@ -8,7 +8,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
 #include "ash/display/display_manager.h"
 #include "ash/shell.h"
diff --git a/ash/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/wm/maximize_mode/maximize_mode_window_manager.cc
index 02b81808..bd83227 100644
--- a/ash/wm/maximize_mode/maximize_mode_window_manager.cc
+++ b/ash/wm/maximize_mode/maximize_mode_window_manager.cc
@@ -4,8 +4,8 @@
 
 #include "ash/wm/maximize_mode/maximize_mode_window_manager.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/mru_window_tracker.h"
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 6dd81c7..3b9c9ef 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -15,6 +15,9 @@
 #include "ash/wm/overview/scoped_overview_animation_settings_factory.h"
 #include "ash/wm/overview/window_selector_item.h"
 #include "base/macros.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkRect.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_delegate.h"
 #include "ui/compositor/paint_recorder.h"
@@ -168,10 +171,11 @@
 }  // namespace
 
 // Mask layer that clips the window's original header in overview mode.
+// Only used with Material Design.
 class ScopedTransformOverviewWindow::OverviewContentMask
     : public ui::LayerDelegate {
  public:
-  explicit OverviewContentMask(int inset);
+  OverviewContentMask(int inset, int radius);
   ~OverviewContentMask() override;
 
   ui::Layer* layer() { return &layer_; }
@@ -185,13 +189,15 @@
  private:
   ui::Layer layer_;
   int inset_;
+  int radius_;
 
   DISALLOW_COPY_AND_ASSIGN(OverviewContentMask);
 };
 
 ScopedTransformOverviewWindow::OverviewContentMask::OverviewContentMask(
-    int inset)
-    : layer_(ui::LAYER_TEXTURED), inset_(inset) {
+    int inset,
+    int radius)
+    : layer_(ui::LAYER_TEXTURED), inset_(inset), radius_(radius) {
   layer_.set_delegate(this);
 }
 
@@ -202,12 +208,29 @@
 void ScopedTransformOverviewWindow::OverviewContentMask::OnPaintLayer(
     const ui::PaintContext& context) {
   ui::PaintRecorder recorder(context, layer()->size());
+  gfx::Rect bounds(layer()->bounds().size());
+  bounds.Inset(0, inset_, 0, 0);
+
+  // Tile a window into an area, rounding the bottom corners.
+  const SkRect rect = gfx::RectToSkRect(bounds);
+  const SkScalar corner_radius_scalar = SkIntToScalar(radius_);
+  SkScalar radii[8] = {0,
+                       0,  // top-left
+                       0,
+                       0,  // top-right
+                       corner_radius_scalar,
+                       corner_radius_scalar,  // bottom-right
+                       corner_radius_scalar,
+                       corner_radius_scalar};  // bottom-left
+  SkPath path;
+  path.addRoundRect(rect, radii, SkPath::kCW_Direction);
+
+  // Set a mask.
   SkPaint paint;
   paint.setAlpha(kOverviewContentMaskAlpha);
   paint.setStyle(SkPaint::kFill_Style);
-  gfx::Rect rect(layer()->bounds().size());
-  rect.Inset(0, inset_, 0, 0);
-  recorder.canvas()->DrawRect(rect, paint);
+  paint.setAntiAlias(true);
+  recorder.canvas()->DrawPath(path, paint);
 }
 
 void ScopedTransformOverviewWindow::OverviewContentMask::
@@ -241,7 +264,7 @@
   BeginScopedAnimation(
       OverviewAnimationType::OVERVIEW_ANIMATION_RESTORE_WINDOW,
       &animation_settings_list);
-  SetTransform(window()->GetRootWindow(), original_transform_);
+  SetTransform(window()->GetRootWindow(), original_transform_, 0);
 
   std::unique_ptr<ScopedOverviewAnimationSettings> animation_settings =
       CreateScopedOverviewAnimationSettings(
@@ -367,12 +390,13 @@
 
 void ScopedTransformOverviewWindow::SetTransform(
     WmWindow* root_window,
-    const gfx::Transform& transform) {
+    const gfx::Transform& transform,
+    int radius) {
   DCHECK(overview_started_);
 
   if (ash::MaterialDesignController::IsOverviewMaterial()) {
     mask_.reset(new OverviewContentMask(
-        window()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET)));
+        window()->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET), radius));
     mask_->layer()->SetBounds(GetTargetBoundsInScreen());
     window()->GetLayer()->SetMaskLayer(mask_->layer());
   }
diff --git a/ash/wm/overview/scoped_transform_overview_window.h b/ash/wm/overview/scoped_transform_overview_window.h
index 97b0fe7..32e277d2 100644
--- a/ash/wm/overview/scoped_transform_overview_window.h
+++ b/ash/wm/overview/scoped_transform_overview_window.h
@@ -102,8 +102,11 @@
   void PrepareForOverview();
 
   // Applies the |transform| to the overview window and all of its transient
-  // children.
-  void SetTransform(WmWindow* root_window, const gfx::Transform& transform);
+  // children. With Material Design creates a mask layer with the bottom edge
+  // using rounded corners of |radius|.
+  void SetTransform(WmWindow* root_window,
+                    const gfx::Transform& transform,
+                    int radius);
 
   // Set's the opacity of the managed windows.
   void SetOpacity(float opacity);
diff --git a/ash/wm/overview/window_grid.cc b/ash/wm/overview/window_grid.cc
index 844724f4..e2da894 100644
--- a/ash/wm/overview/window_grid.cc
+++ b/ash/wm/overview/window_grid.cc
@@ -10,7 +10,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/window_state.h"
@@ -25,13 +25,17 @@
 #include "base/i18n/string_search.h"
 #include "base/memory/scoped_vector.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/pathops/SkPathOps.h"
 #include "ui/compositor/layer_animation_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/gfx/animation/tween.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/views/background.h"
 #include "ui/views/border.h"
+#include "ui/views/painter.h"
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/wm/core/window_animations.h"
@@ -98,14 +102,18 @@
 
 // The color and opacity of the overview selector.
 const SkColor kWindowSelectionColor = SkColorSetARGB(128, 0, 0, 0);
-const SkColor kWindowSelectionColorMD = SkColorSetARGB(41, 255, 255, 255);
+const SkColor kWindowSelectionColorMD = SkColorSetARGB(51, 255, 255, 255);
 const SkColor kWindowSelectionBorderColor = SkColorSetARGB(38, 255, 255, 255);
-const SkColor kWindowSelectionBorderColorMD = SkColorSetARGB(51, 255, 255, 255);
+const SkColor kWindowSelectionBorderColorMD = SkColorSetARGB(76, 255, 255, 255);
 
 // Border thickness of overview selector.
 const int kWindowSelectionBorderThickness = 2;
 const int kWindowSelectionBorderThicknessMD = 1;
 
+// Corner radius of the overview selector border.
+const int kWindowSelectionRadius = 0;
+const int kWindowSelectionRadiusMD = 3;
+
 // The minimum amount of spacing between the bottom of the text filtering
 // text field and the top of the selection widget on the first row of items.
 const int kTextFilterBottomMargin = 5;
@@ -116,7 +124,7 @@
 const int kWindowMarginMD = 5;
 
 // Additional inset of overview selector (4 is the visible selector thickness).
-const int kSelectionInset = kWindowMarginMD - 4;
+const int kSelectionInset = kWindowMarginMD - 5;
 
 // Windows are not allowed to get taller than this.
 const int kMaxHeight = 512;
@@ -127,6 +135,114 @@
 // Additional vertical inset reserved for windows in overview mode.
 const float kOverviewVerticalInset = 0.1f;
 
+// A View having rounded corners and a specified background color which is
+// only painted within the bounds defined by the rounded corners.
+// TODO(varkha): This duplicates code from RoundedImageView. Refactor these
+//               classes and move into ui/views.
+class RoundedRectView : public views::View {
+ public:
+  RoundedRectView(int corner_radius, SkColor background)
+      : corner_radius_(corner_radius), background_(background) {}
+
+  ~RoundedRectView() override {}
+
+  void OnPaint(gfx::Canvas* canvas) override {
+    views::View::OnPaint(canvas);
+
+    SkScalar radius = SkIntToScalar(corner_radius_);
+    const SkScalar kRadius[8] = {radius, radius, radius, radius,
+                                 radius, radius, radius, radius};
+    SkPath path;
+    gfx::Rect bounds(size());
+    bounds.set_height(bounds.height() + radius);
+    path.addRoundRect(gfx::RectToSkRect(bounds), kRadius);
+
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    canvas->ClipPath(path, true);
+    canvas->DrawColor(background_);
+  }
+
+ private:
+  int corner_radius_;
+  SkColor background_;
+
+  DISALLOW_COPY_AND_ASSIGN(RoundedRectView);
+};
+
+// BackgroundWith1PxBorder renders a solid background color, with a one pixel
+// border with rounded corners. This accounts for the scaling of the canvas, so
+// that the border is 1 pixel thick regardless of display scaling.
+class BackgroundWith1PxBorder : public views::Background {
+ public:
+  BackgroundWith1PxBorder(SkColor background,
+                          SkColor border_color,
+                          int border_thickness,
+                          int corner_radius);
+
+  void Paint(gfx::Canvas* canvas, views::View* view) const override;
+
+ private:
+  // Color for the one pixel border.
+  SkColor border_color_;
+
+  // Thickness of border inset.
+  int border_thickness_;
+
+  // Corner radius of the inside edge of the roundrect border stroke.
+  int corner_radius_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundWith1PxBorder);
+};
+
+BackgroundWith1PxBorder::BackgroundWith1PxBorder(SkColor background,
+                                                 SkColor border_color,
+                                                 int border_thickness,
+                                                 int corner_radius)
+    : border_color_(border_color),
+      border_thickness_(border_thickness),
+      corner_radius_(corner_radius) {
+  SetNativeControlColor(background);
+}
+
+void BackgroundWith1PxBorder::Paint(gfx::Canvas* canvas,
+                                    views::View* view) const {
+  gfx::RectF border_rect_f(view->GetContentsBounds());
+
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  const float scale = canvas->UndoDeviceScaleFactor();
+  border_rect_f.Scale(scale);
+  if (border_thickness_ > 0) {
+    const float inset = border_thickness_ * scale - 0.5f;
+    border_rect_f.Inset(inset, inset);
+  }
+
+  SkPath path;
+  const SkScalar scaled_corner_radius =
+      SkFloatToScalar(corner_radius_ * scale + 0.5f);
+  path.addRoundRect(gfx::RectFToSkRect(border_rect_f), scaled_corner_radius,
+                    scaled_corner_radius);
+
+  SkPaint paint;
+  paint.setStyle(SkPaint::kStroke_Style);
+  paint.setStrokeWidth(1);
+  paint.setAntiAlias(true);
+
+  SkPath stroke_path;
+  paint.getFillPath(path, &stroke_path);
+
+  SkPath fill_path;
+  Op(path, stroke_path, kDifference_SkPathOp, &fill_path);
+  paint.setStyle(SkPaint::kFill_Style);
+  paint.setColor(get_color());
+  canvas->sk_canvas()->drawPath(fill_path, paint);
+
+  if (border_thickness_ > 0) {
+    paint.setColor(border_color_);
+    canvas->sk_canvas()->drawPath(stroke_path, paint);
+  }
+}
+
 // Returns the vector for the fade in animation.
 gfx::Vector2d GetSlideVectorForFadeIn(WindowSelector::Direction direction,
                                       const gfx::Rect& bounds) {
@@ -159,6 +275,7 @@
 // individual item.
 void CalculateOverviewSizes(WmWindow* root_window,
                             size_t items,
+                            int text_filter_bottom,
                             gfx::Rect* bounding_rect,
                             gfx::Size* item_size) {
   gfx::Rect total_bounds = root_window->ConvertRectToScreen(
@@ -166,8 +283,7 @@
           kShellWindowId_DefaultContainer)));
 
   // Reserve space at the top for the text filtering textbox to appear.
-  total_bounds.Inset(
-      0, WindowSelector::kTextFilterBottomEdge + kTextFilterBottomMargin, 0, 0);
+  total_bounds.Inset(0, text_filter_bottom + kTextFilterBottomMargin, 0, 0);
 
   // Find the minimum number of windows per row that will fit all of the
   // windows on screen.
@@ -198,13 +314,14 @@
 // equidistant windows preserves a stable order between overview sessions
 // by comparing window pointers.
 void ReorderItemsGreedyLeastMovement(std::vector<WmWindow*>* items,
-                                     WmWindow* root_window) {
+                                     WmWindow* root_window,
+                                     int text_filter_bottom) {
   if (items->empty())
     return;
   gfx::Rect bounding_rect;
   gfx::Size item_size;
-  CalculateOverviewSizes(root_window, items->size(), &bounding_rect,
-                         &item_size);
+  CalculateOverviewSizes(root_window, items->size(), text_filter_bottom,
+                         &bounding_rect, &item_size);
   int num_columns = std::min(static_cast<int>(items->size()),
                              bounding_rect.width() / item_size.width());
   for (size_t i = 0; i < items->size(); ++i) {
@@ -243,6 +360,7 @@
 views::Widget* CreateBackgroundWidget(WmWindow* root_window,
                                       SkColor background_color,
                                       int border_thickness,
+                                      int border_radius,
                                       SkColor border_color) {
   views::Widget* widget = new views::Widget;
   views::Widget::InitParams params;
@@ -265,12 +383,18 @@
   // The background widget should not activate the shelf when passing under it.
   widget_window->GetWindowState()->set_ignored_by_shelf(true);
 
-  views::View* content_view = new views::View;
-  content_view->set_background(
-      views::Background::CreateSolidBackground(background_color));
-  if (border_thickness) {
-    content_view->SetBorder(
-        views::Border::CreateSolidBorder(border_thickness, border_color));
+  views::View* content_view =
+      new RoundedRectView(border_radius, SK_ColorTRANSPARENT);
+  if (ash::MaterialDesignController::IsOverviewMaterial()) {
+    content_view->set_background(new BackgroundWith1PxBorder(
+        background_color, border_color, border_thickness, border_radius));
+  } else {
+    content_view->set_background(
+        views::Background::CreateSolidBackground(background_color));
+    if (border_thickness) {
+      content_view->SetBorder(
+          views::Border::CreateSolidBorder(border_thickness, border_color));
+    }
   }
   widget->SetContentsView(content_view);
   widget_window->GetParent()->StackChildAtTop(widget_window);
@@ -300,7 +424,8 @@
           switches::kAshEnableStableOverviewOrder)) {
     // Reorder windows to try to minimize movement to target overview positions.
     // This also creates a stable window ordering.
-    ReorderItemsGreedyLeastMovement(&windows_in_root, root_window_);
+    ReorderItemsGreedyLeastMovement(&windows_in_root, root_window_,
+                                    window_selector_->text_filter_bottom());
   }
   for (auto window : windows_in_root) {
     window->AddObserver(this);
@@ -459,7 +584,8 @@
   CHECK(!window_list_.empty());
   gfx::Rect bounding_rect;
   gfx::Size item_size;
-  CalculateOverviewSizes(root_window_, window_list_.size(), &bounding_rect,
+  CalculateOverviewSizes(root_window_, window_list_.size(),
+                         window_selector_->text_filter_bottom(), &bounding_rect,
                          &item_size);
   num_columns_ = std::min(static_cast<int>(window_list_.size()),
                           bounding_rect.width() / item_size.width());
@@ -596,8 +722,10 @@
       (*iter)->SetDimmed(false);
     } else {
       (*iter)->SetDimmed(true);
-      if (selection_widget_ && SelectedWindow() == *iter)
+      if (selection_widget_ && SelectedWindow() == *iter) {
+        SelectedWindow()->SetSelected(false);
         selection_widget_.reset();
+      }
     }
   }
 }
@@ -648,7 +776,7 @@
 }
 
 void WindowGrid::InitShieldWidget() {
-  shield_widget_.reset(CreateBackgroundWidget(root_window_, kShieldColor, 0,
+  shield_widget_.reset(CreateBackgroundWidget(root_window_, kShieldColor, 0, 0,
                                               SK_ColorTRANSPARENT));
 
   WmWindow* widget_window =
@@ -674,8 +802,11 @@
       material ? kWindowSelectionBorderColorMD : kWindowSelectionBorderColor;
   const int selection_color =
       material ? kWindowSelectionColorMD : kWindowSelectionColor;
-  selection_widget_.reset(CreateBackgroundWidget(
-      root_window_, selection_color, border_thickness, border_color));
+  const int border_radius =
+      material ? kWindowSelectionRadiusMD : kWindowSelectionRadius;
+  selection_widget_.reset(CreateBackgroundWidget(root_window_, selection_color,
+                                                 border_thickness,
+                                                 border_radius, border_color));
 
   WmWindow* widget_window =
       WmLookup::Get()->GetWindowForWidget(selection_widget_.get());
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index e67ad31..0f711d0 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -10,8 +10,9 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
+#include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/metrics/user_metrics_action.h"
 #include "ash/common/shelf/wm_shelf.h"
 #include "ash/common/shell_window_ids.h"
@@ -19,6 +20,7 @@
 #include "ash/common/wm/panels/panel_layout_manager.h"
 #include "ash/common/wm/switchable_windows.h"
 #include "ash/common/wm/window_state.h"
+#include "ash/common/wm/wm_screen_util.h"
 #include "ash/common/wm_lookup.h"
 #include "ash/common/wm_root_window_controller.h"
 #include "ash/common/wm_shell.h"
@@ -36,8 +38,11 @@
 #include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/gfx/vector_icons.h"
 #include "ui/views/border.h"
+#include "ui/views/controls/image_view.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/layout/box_layout.h"
 
@@ -50,6 +55,7 @@
 
 // The amount of padding surrounding the text in the text filtering textbox.
 const int kTextFilterHorizontalPadding = 8;
+const int kTextFilterHorizontalPaddingMD = 10;
 
 // The distance between the top of the screen and the top edge of the
 // text filtering textbox.
@@ -57,16 +63,36 @@
 
 // The height of the text filtering textbox.
 const int kTextFilterHeight = 32;
+const int kTextFilterHeightMD = 40;
 
-// The font style used for text filtering.
+// Distance from top of overview to the top of text filtering textbox as a
+// proportion of the total overview area with Material Design.
+const float kTextFilterTopScreenProportion = 0.02f;
+
+// Width of the text filter area with Material Design.
+const int kTextFilterWidthMD = 280;
+
+// The font style used for text filtering textbox.
 static const ::ui::ResourceBundle::FontStyle kTextFilterFontStyle =
     ::ui::ResourceBundle::FontStyle::MediumFont;
+static const ::ui::ResourceBundle::FontStyle kTextFilterFontStyleMD =
+    ::ui::ResourceBundle::FontStyle::BaseFont;
 
-// The alpha value for the background of the text filtering textbox.
-const unsigned char kTextFilterOpacity = 180;
+// The color of the text and its background in the text filtering textbox.
+const SkColor kTextFilterTextColor = SK_ColorWHITE;
+const SkColor kTextFilterTextColorMD = SkColorSetARGB(222, 0, 0, 0);
+const SkColor kTextFilterBackgroundColor = SkColorSetARGB(180, 0, 0, 0);
+const SkColor kTextFilterBackgroundColorMD = SK_ColorWHITE;
+
+// The color or search icon with Material Design.
+const SkColor kTextFilterIconColorMD = SkColorSetARGB(138, 0, 0, 0);
+
+// The size of search icon with Material Design.
+const int kTextFilterIconSize = 20;
 
 // The radius used for the rounded corners on the text filtering textbox.
 const int kTextFilterCornerRadius = 1;
+const int kTextFilterCornerRadiusMD = 2;
 
 // A comparator for locating a grid with a given root window.
 struct RootWindowGridComparator {
@@ -146,52 +172,87 @@
     root->GetRootWindowController()->GetShelf()->UpdateVisibilityState();
 }
 
+gfx::Rect GetTextFilterPosition(WmWindow* root_window) {
+  if (ash::MaterialDesignController::IsOverviewMaterial()) {
+    gfx::Rect total_bounds =
+        root_window->ConvertRectToScreen(wm::GetDisplayWorkAreaBoundsInParent(
+            root_window->GetChildByShellWindowId(
+                kShellWindowId_DefaultContainer)));
+    return gfx::Rect(0.5 * (total_bounds.width() -
+                            std::min(kTextFilterWidthMD, total_bounds.width())),
+                     total_bounds.height() * kTextFilterTopScreenProportion,
+                     std::min(kTextFilterWidthMD, total_bounds.width()),
+                     kTextFilterHeightMD);
+  }
+  return gfx::Rect(
+      0.5 * root_window->GetBounds().width() *
+          (1 - kTextFilterScreenProportion),
+      kTextFilterDistanceFromTop,
+      root_window->GetBounds().width() * kTextFilterScreenProportion,
+      kTextFilterHeight);
+}
+
 // Initializes the text filter on the top of the main root window and requests
-// focus on its textfield.
+// focus on its textfield. With Material Design uses |image| to place an icon
+// to the left of the text field.
 views::Widget* CreateTextFilter(views::TextfieldController* controller,
-                                WmWindow* root_window) {
+                                WmWindow* root_window,
+                                const gfx::ImageSkia& image,
+                                int* text_filter_bottom) {
   views::Widget* widget = new views::Widget;
   views::Widget::InitParams params;
   params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
   params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   params.accept_events = true;
-  params.bounds = gfx::Rect(
-      root_window->GetBounds().width() / 2 * (1 - kTextFilterScreenProportion),
-      kTextFilterDistanceFromTop,
-      root_window->GetBounds().width() * kTextFilterScreenProportion,
-      kTextFilterHeight);
+  params.bounds = GetTextFilterPosition(root_window);
+  *text_filter_bottom = params.bounds.bottom();
   root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer(
       widget, kShellWindowId_OverlayContainer, &params);
   widget->Init(params);
 
   // Use |container| to specify the padding surrounding the text and to give
   // the textfield rounded corners.
+  const bool material = ash::MaterialDesignController::IsOverviewMaterial();
   views::View* container = new RoundedContainerView(
-      kTextFilterCornerRadius, SkColorSetARGB(kTextFilterOpacity, 0, 0, 0));
+      material ? kTextFilterCornerRadiusMD : kTextFilterCornerRadius,
+      material ? kTextFilterBackgroundColorMD : kTextFilterBackgroundColor);
   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-  int text_height = bundle.GetFontList(kTextFilterFontStyle).GetHeight();
+  const ::ui::ResourceBundle::FontStyle font_style =
+      material ? kTextFilterFontStyleMD : kTextFilterFontStyle;
+  const int text_height =
+      std::max(kTextFilterIconSize, bundle.GetFontList(font_style).GetHeight());
   DCHECK(text_height);
-  int vertical_padding = (kTextFilterHeight - text_height) / 2;
-  container->SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
-                                                   kTextFilterHorizontalPadding,
-                                                   vertical_padding,
-                                                   0));
+  const int vertical_padding = (params.bounds.height() - text_height) / 2;
+  const int horizontal_padding =
+      material ? kTextFilterHorizontalPaddingMD : kTextFilterHorizontalPadding;
+  views::BoxLayout* layout =
+      new views::BoxLayout(views::BoxLayout::kHorizontal, horizontal_padding,
+                           vertical_padding, horizontal_padding);
+  container->SetLayoutManager(layout);
 
   views::Textfield* textfield = new views::Textfield;
   textfield->set_controller(controller);
-  textfield->SetBackgroundColor(SK_ColorTRANSPARENT);
   textfield->SetBorder(views::Border::NullBorder());
-  textfield->SetTextColor(SK_ColorWHITE);
-  textfield->SetFontList(bundle.GetFontList(kTextFilterFontStyle));
-
+  if (material) {
+    textfield->SetBackgroundColor(kTextFilterBackgroundColorMD);
+    textfield->SetTextColor(kTextFilterTextColorMD);
+    views::ImageView* image_view = new views::ImageView;
+    image_view->SetImage(image);
+    container->AddChildView(image_view);
+  } else {
+    textfield->SetBackgroundColor(SK_ColorTRANSPARENT);
+    textfield->SetTextColor(kTextFilterTextColor);
+  }
+  textfield->SetFontList(bundle.GetFontList(font_style));
   container->AddChildView(textfield);
+  layout->SetFlexForView(textfield, 1);
   widget->SetContentsView(container);
 
   // The textfield initially contains no text, so shift its position to be
   // outside the visible bounds of the screen.
   gfx::Transform transform;
-  transform.Translate(0, -WindowSelector::kTextFilterBottomEdge);
+  transform.Translate(0, -params.bounds.bottom());
   WmLookup::Get()->GetWindowForWidget(widget)->SetTransform(transform);
   widget->Show();
   textfield->RequestFocus();
@@ -201,9 +262,6 @@
 
 }  // namespace
 
-const int WindowSelector::kTextFilterBottomEdge =
-    kTextFilterDistanceFromTop + kTextFilterHeight;
-
 // static
 bool WindowSelector::IsSelectable(WmWindow* window) {
   wm::WindowState* state = window->GetWindowState();
@@ -225,7 +283,8 @@
       showing_selection_widget_(false),
       text_filter_string_length_(0),
       num_times_textfield_cleared_(0),
-      restoring_minimized_windows_(false) {
+      restoring_minimized_windows_(false),
+      text_filter_bottom_(0) {
   DCHECK(delegate_);
 }
 
@@ -293,8 +352,14 @@
       window_grid->PositionWindows(true);
     }
 
-    text_filter_widget_.reset(
-        CreateTextFilter(this, shell->GetPrimaryRootWindow()));
+    if (ash::MaterialDesignController::IsOverviewMaterial()) {
+      search_image_ =
+          gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH,
+                                kTextFilterIconSize, kTextFilterIconColorMD);
+    }
+    WmWindow* root_window = shell->GetPrimaryRootWindow();
+    text_filter_widget_.reset(CreateTextFilter(this, root_window, search_image_,
+                                               &text_filter_bottom_));
   }
 
   DCHECK(!grid_list_.empty());
@@ -545,7 +610,7 @@
       transform.Translate(0, 0);
       text_filter_widget_window->SetOpacity(1);
     } else {
-      transform.Translate(0, -kTextFilterBottomEdge);
+      transform.Translate(0, -text_filter_bottom_);
       text_filter_widget_window->SetOpacity(0);
     }
 
@@ -573,18 +638,13 @@
 
 void WindowSelector::RepositionTextFilterOnDisplayMetricsChange() {
   WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow();
-  gfx::Rect rect(
-      root_window->GetBounds().width() / 2 * (1 - kTextFilterScreenProportion),
-      kTextFilterDistanceFromTop,
-      root_window->GetBounds().width() * kTextFilterScreenProportion,
-      kTextFilterHeight);
-
+  const gfx::Rect rect = GetTextFilterPosition(root_window);
+  text_filter_bottom_ = rect.bottom();
   text_filter_widget_->SetBounds(rect);
 
   gfx::Transform transform;
-  transform.Translate(0, text_filter_string_length_ == 0
-                             ? -WindowSelector::kTextFilterBottomEdge
-                             : 0);
+  transform.Translate(
+      0, text_filter_string_length_ == 0 ? -text_filter_bottom_ : 0);
   GetTextFilterWidgetWindow()->SetTransform(transform);
 }
 
diff --git a/ash/wm/overview/window_selector.h b/ash/wm/overview/window_selector.h
index d1dbbc2..1412b05 100644
--- a/ash/wm/overview/window_selector.h
+++ b/ash/wm/overview/window_selector.h
@@ -18,6 +18,7 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "ui/display/display_observer.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 
 namespace views {
@@ -38,10 +39,6 @@
                                   public WmActivationObserver,
                                   public views::TextfieldController {
  public:
-  // The distance between the top edge of the screen and the bottom edge of
-  // the text filtering textfield.
-  static const int kTextFilterBottomEdge;
-
   // Returns true if the window can be selected in overview mode.
   static bool IsSelectable(WmWindow* window);
 
@@ -76,6 +73,8 @@
     return restoring_minimized_windows_;
   }
 
+  int text_filter_bottom() { return text_filter_bottom_; }
+
   // display::DisplayObserver:
   void OnDisplayAdded(const display::Display& display) override;
   void OnDisplayRemoved(const display::Display& display) override;
@@ -164,6 +163,9 @@
   // such as enter key to select.
   std::unique_ptr<views::Widget> text_filter_widget_;
 
+  // Image used for text filter textfield.
+  gfx::ImageSkia search_image_;
+
   // The current length of the string entered into the text filtering textfield.
   size_t text_filter_string_length_;
 
@@ -175,6 +177,10 @@
   // mode.
   bool restoring_minimized_windows_;
 
+  // The distance between the top edge of the screen and the bottom edge of
+  // the text filtering textfield.
+  int text_filter_bottom_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowSelector);
 };
 
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index 17c1f34..5846185 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -28,6 +28,7 @@
 #include "grit/ash_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/vector2d.h"
 #include "ui/gfx/paint_vector_icon.h"
@@ -66,6 +67,9 @@
 // TODO(varkha): Make background color conform to window header.
 static const SkColor kLabelBackgroundColor = SkColorSetARGB(25, 255, 255, 255);
 
+// Corner radius for the selection tiles used with Material Design.
+static int kLabelBackgroundRadius = 2;
+
 // Label shadow color.
 static const SkColor kLabelShadow = SkColorSetARGB(176, 0, 0, 0);
 
@@ -73,7 +77,7 @@
 static const int kVerticalLabelPadding = 20;
 
 // Horizontal padding for the label, on both sides. Used with Material Design.
-static const int kHorizontalLabelPaddingMD = 4;
+static const int kHorizontalLabelPaddingMD = 8;
 
 // Solid shadow length from the label
 static const int kVerticalShadowOffset = 1;
@@ -165,6 +169,41 @@
 OverviewCloseButton::~OverviewCloseButton() {
 }
 
+// A View having rounded corners and a specified background color which is
+// only painted within the bounds defined by the rounded corners.
+// TODO(varkha): This duplicates code from RoundedImageView. Refactor these
+//               classes and move into ui/views.
+class RoundedContainerView : public views::View {
+ public:
+  RoundedContainerView(int corner_radius, SkColor background)
+      : corner_radius_(corner_radius), background_(background) {}
+
+  ~RoundedContainerView() override {}
+
+  void OnPaint(gfx::Canvas* canvas) override {
+    views::View::OnPaint(canvas);
+
+    SkScalar radius = SkIntToScalar(corner_radius_);
+    const SkScalar kRadius[8] = {radius, radius, radius, radius,
+                                 radius, radius, radius, radius};
+    SkPath path;
+    gfx::Rect bounds(size());
+    bounds.set_height(bounds.height() + radius);
+    path.addRoundRect(gfx::RectToSkRect(bounds), kRadius);
+
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    canvas->ClipPath(path, true);
+    canvas->DrawColor(background_);
+  }
+
+ private:
+  int corner_radius_;
+  SkColor background_;
+
+  DISALLOW_COPY_AND_ASSIGN(RoundedContainerView);
+};
+
 }  // namespace
 
 WindowSelectorItem::OverviewLabelButton::OverviewLabelButton(
@@ -405,7 +444,13 @@
       screen_rect, selector_item_bounds);
   ScopedTransformOverviewWindow::ScopedAnimationSettings animation_settings;
   transform_window_.BeginScopedAnimation(animation_type, &animation_settings);
-  transform_window_.SetTransform(root_window_, transform);
+  // Rounded corners are achieved by using a mask layer on the original window
+  // before the transform. Dividing by scale factor obtains the corner radius
+  // which when scaled will yield |kLabelBackgroundRadius|.
+  transform_window_.SetTransform(
+      root_window_, transform,
+      gfx::ToFlooredInt(kLabelBackgroundRadius /
+                        GetItemScale(target_bounds.size())));
   transform_window_.set_overview_transform(transform);
 }
 
@@ -474,9 +519,8 @@
     window_label_button_view_->SetVisible(false);
     window_label_->Show();
 
-    views::View* background_view = new views::View;
-    background_view->set_background(
-        views::Background::CreateSolidBackground(kLabelBackgroundColor));
+    views::View* background_view =
+        new RoundedContainerView(kLabelBackgroundRadius, kLabelBackgroundColor);
     window_label_selector_.reset(new views::Widget);
     params.activatable = views::Widget::InitParams::Activatable::ACTIVATABLE_NO;
     params.accept_events = false;
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 75992163..997264b 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -5,9 +5,9 @@
 #include <algorithm>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/mru_window_tracker.h"
@@ -363,11 +363,21 @@
 
   // Formula for initial placement found in window_selector.cc using
   // width = 400, height = 300:
-  // x: root_window->bounds().width() / 2 * (1 - kTextFilterScreenProportion).
-  // y: -kTextFilterDistanceFromTop (since there's no text in the filter).
+  // x: 0.5 * root_window->bounds().width() * (1 - kTextFilterScreenProportion).
+  // y: -kTextFilterHeight (since there's no text in the filter).
   // w: root_window->bounds().width() * kTextFilterScreenProportion.
   // h: kTextFilterHeight.
-  EXPECT_EQ("150,-32 100x32",
+  //
+  // With Material Design the text filter position is calculated as:
+  // x: 0.5 * (total_bounds.width() -
+  //           std::min(kTextFilterWidthMD, total_bounds.width())).
+  // y: -kTextFilterHeightMD (since there's no text in the filter).
+  // w: std::min(kTextFilterWidthMD, total_bounds.width()).
+  // h: kTextFilterHeightMD.
+  const bool material = ash::MaterialDesignController::IsOverviewMaterial();
+  gfx::Rect expected_bounds(150, -32, 100, 32);
+  gfx::Rect expected_bounds_MD(60, -40, 280, 40);
+  EXPECT_EQ((material ? expected_bounds_MD : expected_bounds).ToString(),
             text_filter->GetClientAreaBoundsInScreen().ToString());
 
   // Rotates the display, which triggers the WindowSelector's
@@ -375,7 +385,9 @@
   UpdateDisplay("400x300/r");
 
   // Uses the same formulas as above using width = 300, height = 400.
-  EXPECT_EQ("112,-32 75x32",
+  expected_bounds = gfx::Rect(112, -32, 75, 32);
+  expected_bounds_MD = gfx::Rect(10, -40, 280, 40);
+  EXPECT_EQ((material ? expected_bounds_MD : expected_bounds).ToString(),
             text_filter->GetClientAreaBoundsInScreen().ToString());
 }
 #endif
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index be02908..7d0c62d3 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -4,8 +4,8 @@
 
 #include "ash/common/wm/panels/panel_layout_manager.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/common/shell_window_ids.h"
diff --git a/ash/wm/power_button_controller.cc b/ash/wm/power_button_controller.cc
index ae20c85..007870b0 100644
--- a/ash/wm/power_button_controller.cc
+++ b/ash/wm/power_button_controller.cc
@@ -4,7 +4,7 @@
 
 #include "ash/wm/power_button_controller.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/shell.h"
diff --git a/ash/wm/system_gesture_event_filter.cc b/ash/wm/system_gesture_event_filter.cc
index fbd76ac..d02dba9 100644
--- a/ash/wm/system_gesture_event_filter.cc
+++ b/ash/wm/system_gesture_event_filter.cc
@@ -4,7 +4,7 @@
 
 #include "ash/wm/system_gesture_event_filter.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/shell.h"
 #include "ash/touch/touch_uma.h"
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 0b5cbfa1..6d60848 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1886,6 +1886,7 @@
     "synchronization/read_write_lock_unittest.cc",
     "synchronization/waitable_event_unittest.cc",
     "synchronization/waitable_event_watcher_unittest.cc",
+    "sys_byteorder_unittest.cc",
     "sys_info_unittest.cc",
     "system_monitor/system_monitor_unittest.cc",
     "task/cancelable_task_tracker_unittest.cc",
diff --git a/base/base.gyp b/base/base.gyp
index 269bbe3..8c6a7bd 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -546,6 +546,7 @@
         'synchronization/read_write_lock_unittest.cc',
         'synchronization/waitable_event_unittest.cc',
         'synchronization/waitable_event_watcher_unittest.cc',
+        'sys_byteorder_unittest.cc',
         'sys_info_unittest.cc',
         'system_monitor/system_monitor_unittest.cc',
         'task/cancelable_task_tracker_unittest.cc',
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
index 8d4e51b..57cb3abe 100644
--- a/base/process/process_metrics.h
+++ b/base/process/process_metrics.h
@@ -272,6 +272,14 @@
   int total;
   int free;
 
+#if defined(OS_LINUX)
+  // This provides an estimate of available memory as described here:
+  // https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=34e431b0ae398fc54ea69ff85ec700722c9da773
+  // NOTE: this is ONLY valid in kernels 3.14 and up.  Its value will always
+  // be 0 in earlier kernel versions.
+  int available;
+#endif
+
 #if !defined(OS_MACOSX)
   int swap_total;
   int swap_free;
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
index 89a26090..3d27656 100644
--- a/base/process/process_metrics_linux.cc
+++ b/base/process/process_metrics_linux.cc
@@ -534,6 +534,9 @@
 SystemMemoryInfoKB::SystemMemoryInfoKB() {
   total = 0;
   free = 0;
+#if defined(OS_LINUX)
+  available = 0;
+#endif
   buffers = 0;
   cached = 0;
   active_anon = 0;
@@ -564,6 +567,9 @@
 
   res->SetInteger("total", total);
   res->SetInteger("free", free);
+#if defined(OS_LINUX)
+  res->SetInteger("available", available);
+#endif
   res->SetInteger("buffers", buffers);
   res->SetInteger("cached", cached);
   res->SetInteger("active_anon", active_anon);
@@ -621,6 +627,10 @@
       target = &meminfo->total;
     else if (tokens[0] == "MemFree:")
       target = &meminfo->free;
+#if defined(OS_LINUX)
+    else if (tokens[0] == "MemAvailable:")
+      target = &meminfo->available;
+#endif
     else if (tokens[0] == "Buffers:")
       target = &meminfo->buffers;
     else if (tokens[0] == "Cached:")
diff --git a/base/sha1.cc b/base/sha1.cc
index dd2ab6f..a710001 100644
--- a/base/sha1.cc
+++ b/base/sha1.cc
@@ -8,6 +8,7 @@
 #include <stdint.h>
 #include <string.h>
 
+#include "base/sys_byteorder.h"
 
 namespace base {
 
@@ -92,10 +93,6 @@
   }
 }
 
-static inline void swapends(uint32_t* t) {
-  *t = (*t >> 24) | ((*t >> 8) & 0xff00) | ((*t & 0xff00) << 8) | (*t << 24);
-}
-
 const int SecureHashAlgorithm::kDigestSizeBytes = 20;
 
 void SecureHashAlgorithm::Init() {
@@ -118,7 +115,7 @@
   Process();
 
   for (int t = 0; t < 5; ++t)
-    swapends(&H[t]);
+    H[t] = ByteSwap(H[t]);
 }
 
 void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
@@ -165,7 +162,7 @@
   // W and M are in a union, so no need to memcpy.
   // memcpy(W, M, sizeof(M));
   for (t = 0; t < 16; ++t)
-    swapends(&W[t]);
+    W[t] = ByteSwap(W[t]);
 
   // b.
   for (t = 16; t < 80; ++t)
diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h
index ddb3f5b..8d9066c 100644
--- a/base/sys_byteorder.h
+++ b/base/sys_byteorder.h
@@ -15,27 +15,35 @@
 
 #include "build/build_config.h"
 
+#if defined(COMPILER_MSVC)
+#include <stdlib.h>
+#endif
+
 namespace base {
 
 // Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
 inline uint16_t ByteSwap(uint16_t x) {
-  return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
+#if defined(COMPILER_MSVC)
+  return _byteswap_ushort(x);
+#else
+  return __builtin_bswap16(x);
+#endif
 }
 
 inline uint32_t ByteSwap(uint32_t x) {
-  return ((x & 0x000000fful) << 24) | ((x & 0x0000ff00ul) << 8) |
-      ((x & 0x00ff0000ul) >> 8) | ((x & 0xff000000ul) >> 24);
+#if defined(COMPILER_MSVC)
+  return _byteswap_ulong(x);
+#else
+  return __builtin_bswap32(x);
+#endif
 }
 
 inline uint64_t ByteSwap(uint64_t x) {
-  return ((x & 0x00000000000000ffull) << 56) |
-      ((x & 0x000000000000ff00ull) << 40) |
-      ((x & 0x0000000000ff0000ull) << 24) |
-      ((x & 0x00000000ff000000ull) << 8) |
-      ((x & 0x000000ff00000000ull) >> 8) |
-      ((x & 0x0000ff0000000000ull) >> 24) |
-      ((x & 0x00ff000000000000ull) >> 40) |
-      ((x & 0xff00000000000000ull) >> 56);
+#if defined(COMPILER_MSVC)
+  return _byteswap_uint64(x);
+#else
+  return __builtin_bswap64(x);
+#endif
 }
 
 // Converts the bytes in |x| from host order (endianness) to little endian, and
diff --git a/base/sys_byteorder_unittest.cc b/base/sys_byteorder_unittest.cc
new file mode 100644
index 0000000..0352c2a
--- /dev/null
+++ b/base/sys_byteorder_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sys_byteorder.h"
+
+#include <stdint.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const uint16_t k16BitTestData = 0xaabb;
+const uint16_t k16BitSwappedTestData = 0xbbaa;
+const uint32_t k32BitTestData = 0xaabbccdd;
+const uint32_t k32BitSwappedTestData = 0xddccbbaa;
+const uint64_t k64BitTestData = 0xaabbccdd44332211;
+const uint64_t k64BitSwappedTestData = 0x11223344ddccbbaa;
+
+}  // namespace
+
+TEST(ByteOrderTest, ByteSwap16) {
+  uint16_t swapped = base::ByteSwap(k16BitTestData);
+  EXPECT_EQ(k16BitSwappedTestData, swapped);
+  uint16_t reswapped = base::ByteSwap(swapped);
+  EXPECT_EQ(k16BitTestData, reswapped);
+}
+
+TEST(ByteOrderTest, ByteSwap32) {
+  uint32_t swapped = base::ByteSwap(k32BitTestData);
+  EXPECT_EQ(k32BitSwappedTestData, swapped);
+  uint32_t reswapped = base::ByteSwap(swapped);
+  EXPECT_EQ(k32BitTestData, reswapped);
+}
+
+TEST(ByteOrderTest, ByteSwap64) {
+  uint64_t swapped = base::ByteSwap(k64BitTestData);
+  EXPECT_EQ(k64BitSwappedTestData, swapped);
+  uint64_t reswapped = base::ByteSwap(swapped);
+  EXPECT_EQ(k64BitTestData, reswapped);
+}
+
+TEST(ByteOrderTest, ByteSwapToLE16) {
+  uint16_t le = base::ByteSwapToLE16(k16BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k16BitTestData, le);
+#else
+  EXPECT_EQ(k16BitSwappedTestData, le);
+#endif
+}
+
+TEST(ByteOrderTest, ByteSwapToLE32) {
+  uint32_t le = base::ByteSwapToLE32(k32BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k32BitTestData, le);
+#else
+  EXPECT_EQ(k32BitSwappedTestData, le);
+#endif
+}
+
+TEST(ByteOrderTest, ByteSwapToLE64) {
+  uint64_t le = base::ByteSwapToLE64(k64BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k64BitTestData, le);
+#else
+  EXPECT_EQ(k64BitSwappedTestData, le);
+#endif
+}
+
+TEST(ByteOrderTest, NetToHost16) {
+  uint16_t h = base::NetToHost16(k16BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k16BitSwappedTestData, h);
+#else
+  EXPECT_EQ(k16BitTestData, h);
+#endif
+}
+
+TEST(ByteOrderTest, NetToHost32) {
+  uint32_t h = base::NetToHost32(k32BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k32BitSwappedTestData, h);
+#else
+  EXPECT_EQ(k32BitTestData, h);
+#endif
+}
+
+TEST(ByteOrderTest, NetToHost64) {
+  uint64_t h = base::NetToHost64(k64BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k64BitSwappedTestData, h);
+#else
+  EXPECT_EQ(k64BitTestData, h);
+#endif
+}
+
+TEST(ByteOrderTest, HostToNet16) {
+  uint16_t n = base::HostToNet16(k16BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k16BitSwappedTestData, n);
+#else
+  EXPECT_EQ(k16BitTestData, n);
+#endif
+}
+
+TEST(ByteOrderTest, HostToNet32) {
+  uint32_t n = base::HostToNet32(k32BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k32BitSwappedTestData, n);
+#else
+  EXPECT_EQ(k32BitTestData, n);
+#endif
+}
+
+TEST(ByteOrderTest, HostToNet64) {
+  uint64_t n = base::HostToNet64(k64BitTestData);
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  EXPECT_EQ(k64BitSwappedTestData, n);
+#else
+  EXPECT_EQ(k64BitTestData, n);
+#endif
+}
diff --git a/base/test/test_message_loop.h b/base/test/test_message_loop.h
index fbb0669..9c0aed8 100644
--- a/base/test/test_message_loop.h
+++ b/base/test/test_message_loop.h
@@ -21,6 +21,10 @@
   explicit TestMessageLoop(MessageLoop::Type type);
   ~TestMessageLoop();
 
+  const scoped_refptr<SingleThreadTaskRunner>& task_runner() {
+    return loop_.task_runner();
+  }
+
  private:
   MessageLoop loop_;
 };
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
index b787f671..1c67cc0 100644
--- a/base/trace_event/trace_config.h
+++ b/base/trace_event/trace_config.h
@@ -139,7 +139,7 @@
   //                             "inc_pattern*",
   //                             "disabled-by-default-memory-infra"],
   //     "excluded_categories": ["excluded", "exc_pattern*"],
-  //     "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"]
+  //     "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"],
   //     "memory_dump_config": {
   //       "triggers": [
   //         {
diff --git a/blimp/BUILD.gn b/blimp/BUILD.gn
index a13bfb4b..a4c48f60 100644
--- a/blimp/BUILD.gn
+++ b/blimp/BUILD.gn
@@ -64,6 +64,7 @@
     "//blimp/client:app_unit_tests",
     "//blimp/client:blimp_client_unit_tests",
     "//blimp/client:feature_unit_tests",
+    "//blimp/client/core:unit_tests",
     "//blimp/common:unit_tests",
     "//blimp/net:unit_tests",
   ]
diff --git a/blimp/client/BUILD.gn b/blimp/client/BUILD.gn
index 2d420ba..602b255 100644
--- a/blimp/client/BUILD.gn
+++ b/blimp/client/BUILD.gn
@@ -56,6 +56,7 @@
   deps = [
     ":compositor",
     "//base",
+    "//blimp/client/core",
     "//blimp/common",
     "//blimp/common/proto",
     "//blimp/net",
diff --git a/blimp/client/core/BUILD.gn b/blimp/client/core/BUILD.gn
new file mode 100644
index 0000000..9512eb80
--- /dev/null
+++ b/blimp/client/core/BUILD.gn
@@ -0,0 +1,38 @@
+# 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.
+
+source_set("core") {
+  visibility = [ "//blimp/*" ]
+
+  sources = [
+    "blimp_contents_impl.cc",
+    "blimp_contents_impl.h",
+    "blimp_navigation_controller_delegate.h",
+    "blimp_navigation_controller_impl.cc",
+    "blimp_navigation_controller_impl.h",
+  ]
+
+  deps = [
+    "//base",
+    "//blimp/client/core/public",
+    "//url",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  sources = [
+    "blimp_contents_impl_unittest.cc",
+    "blimp_navigation_controller_impl_unittest.cc",
+  ]
+
+  deps = [
+    "//base",
+    "//blimp/client/core",
+    "//blimp/client/core/public",
+    "//testing/gtest",
+    "//url",
+  ]
+}
diff --git a/blimp/client/core/blimp_contents_impl.cc b/blimp/client/core/blimp_contents_impl.cc
new file mode 100644
index 0000000..ac4e264
--- /dev/null
+++ b/blimp/client/core/blimp_contents_impl.cc
@@ -0,0 +1,34 @@
+// 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 "blimp/client/core/blimp_contents_impl.h"
+
+#include "base/memory/ptr_util.h"
+#include "blimp/client/core/public/blimp_contents_observer.h"
+
+namespace blimp {
+namespace client {
+
+BlimpContentsImpl::BlimpContentsImpl() : navigation_controller_(this) {}
+
+BlimpContentsImpl::~BlimpContentsImpl() {}
+
+BlimpNavigationControllerImpl& BlimpContentsImpl::GetNavigationController() {
+  return navigation_controller_;
+}
+
+void BlimpContentsImpl::AddObserver(BlimpContentsObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void BlimpContentsImpl::RemoveObserver(BlimpContentsObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+void BlimpContentsImpl::NotifyURLLoaded(const GURL& url) {
+  FOR_EACH_OBSERVER(BlimpContentsObserver, observers_, OnURLUpdated(url));
+}
+
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/core/blimp_contents_impl.h b/blimp/client/core/blimp_contents_impl.h
new file mode 100644
index 0000000..8710ab1
--- /dev/null
+++ b/blimp/client/core/blimp_contents_impl.h
@@ -0,0 +1,50 @@
+// 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 BLIMP_CLIENT_CORE_BLIMP_CONTENTS_IMPL_H_
+#define BLIMP_CLIENT_CORE_BLIMP_CONTENTS_IMPL_H_
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "blimp/client/core/blimp_navigation_controller_delegate.h"
+#include "blimp/client/core/blimp_navigation_controller_impl.h"
+#include "blimp/client/core/public/blimp_contents.h"
+#include "url/gurl.h"
+
+namespace blimp {
+namespace client {
+
+class BlimpContentsObserver;
+class BlimpNavigationController;
+
+// BlimpContentsImpl is the implementation of the core class in
+// //blimp/client/core, the BlimpContents.
+class BlimpContentsImpl : public BlimpContents,
+                          public BlimpNavigationControllerDelegate {
+ public:
+  BlimpContentsImpl();
+  ~BlimpContentsImpl() override;
+
+  // BlimpContents implementation.
+  BlimpNavigationControllerImpl& GetNavigationController() override;
+  void AddObserver(BlimpContentsObserver* observer) override;
+  void RemoveObserver(BlimpContentsObserver* observer) override;
+
+  // BlimpNavigationControllerDelegate implementation.
+  void NotifyURLLoaded(const GURL& url) override;
+
+ private:
+  // Handles the back/forward list and loading URLs.
+  BlimpNavigationControllerImpl navigation_controller_;
+
+  // A list of all the observers of this BlimpContentsImpl.
+  base::ObserverList<BlimpContentsObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpContentsImpl);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_CORE_BLIMP_CONTENTS_IMPL_H_
diff --git a/blimp/client/core/blimp_contents_impl_unittest.cc b/blimp/client/core/blimp_contents_impl_unittest.cc
new file mode 100644
index 0000000..3d4a7c0
--- /dev/null
+++ b/blimp/client/core/blimp_contents_impl_unittest.cc
@@ -0,0 +1,66 @@
+// 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 "blimp/client/core/blimp_contents_impl.h"
+
+#include "base/message_loop/message_loop.h"
+#include "blimp/client/core/blimp_contents_impl.h"
+#include "blimp/client/core/public/blimp_contents_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blimp {
+namespace client {
+namespace {
+
+const GURL kExampleURL = GURL("https://www.example.com/");
+const GURL kOtherExampleURL = GURL("https://www.otherexample.com/");
+
+class TestBlimpContentsObserver : public BlimpContentsObserver {
+ public:
+  TestBlimpContentsObserver() = default;
+  ~TestBlimpContentsObserver() override = default;
+
+  void OnURLUpdated(const GURL& url) override { last_url_ = url; }
+
+  GURL GetLastURL() { return last_url_; }
+
+ private:
+  GURL last_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestBlimpContentsObserver);
+};
+
+TEST(BlimpContentsImplTest, Basic) {
+  base::MessageLoop loop;
+  BlimpContentsImpl blimp_contents;
+
+  BlimpNavigationController& navigation_controller =
+      blimp_contents.GetNavigationController();
+
+  TestBlimpContentsObserver observer1;
+  blimp_contents.AddObserver(&observer1);
+  TestBlimpContentsObserver observer2;
+  blimp_contents.AddObserver(&observer2);
+
+  navigation_controller.LoadURL(kExampleURL);
+  loop.RunUntilIdle();
+
+  EXPECT_EQ(kExampleURL, navigation_controller.GetURL());
+  EXPECT_EQ(kExampleURL, observer1.GetLastURL());
+  EXPECT_EQ(kExampleURL, observer2.GetLastURL());
+
+  // Observer should no longer receive callbacks.
+  blimp_contents.RemoveObserver(&observer1);
+
+  navigation_controller.LoadURL(kOtherExampleURL);
+  loop.RunUntilIdle();
+
+  EXPECT_EQ(kOtherExampleURL, navigation_controller.GetURL());
+  EXPECT_EQ(kExampleURL, observer1.GetLastURL());
+  EXPECT_EQ(kOtherExampleURL, observer2.GetLastURL());
+}
+
+}  // namespace
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/core/blimp_navigation_controller_delegate.h b/blimp/client/core/blimp_navigation_controller_delegate.h
new file mode 100644
index 0000000..10647fb
--- /dev/null
+++ b/blimp/client/core/blimp_navigation_controller_delegate.h
@@ -0,0 +1,33 @@
+// 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 BLIMP_CLIENT_CORE_BLIMP_NAVIGATION_CONTROLLER_DELEGATE_H_
+#define BLIMP_CLIENT_CORE_BLIMP_NAVIGATION_CONTROLLER_DELEGATE_H_
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace blimp {
+namespace client {
+
+// Interface for objects embedding a BlimpNavigationControllerImpl to provide
+// the functionality BlimpNavigationControllerImpl needs.
+class BlimpNavigationControllerDelegate {
+ public:
+  virtual ~BlimpNavigationControllerDelegate() = default;
+
+  // Invoked whenever a new URL has been loaded.
+  virtual void NotifyURLLoaded(const GURL& url) = 0;
+
+ protected:
+  BlimpNavigationControllerDelegate() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpNavigationControllerDelegate);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_CORE_BLIMP_NAVIGATION_CONTROLLER_DELEGATE_H_
diff --git a/blimp/client/core/blimp_navigation_controller_impl.cc b/blimp/client/core/blimp_navigation_controller_impl.cc
new file mode 100644
index 0000000..6c57ea09
--- /dev/null
+++ b/blimp/client/core/blimp_navigation_controller_impl.cc
@@ -0,0 +1,43 @@
+// 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 "blimp/client/core/blimp_navigation_controller_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "blimp/client/core/blimp_navigation_controller_delegate.h"
+
+namespace blimp {
+namespace client {
+
+BlimpNavigationControllerImpl::BlimpNavigationControllerImpl(
+    BlimpNavigationControllerDelegate* delegate)
+    : delegate_(delegate), weak_ptr_factory_(this) {}
+
+BlimpNavigationControllerImpl::~BlimpNavigationControllerImpl() = default;
+
+void BlimpNavigationControllerImpl::LoadURL(const GURL& url) {
+  current_url_ = url;
+  // Temporary trick to ensure that the delegate is not invoked before this
+  // method has finished executing. This enables tests to test the
+  // asynchronous nature of the API.
+  // TODO(shaktisahu): Remove this after integration with NavigationFeature.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(&BlimpNavigationControllerImpl::NotifyDelegateURLLoaded,
+                 weak_ptr_factory_.GetWeakPtr(), url));
+}
+
+const GURL& BlimpNavigationControllerImpl::GetURL() {
+  return current_url_;
+}
+
+void BlimpNavigationControllerImpl::NotifyDelegateURLLoaded(const GURL& url) {
+  delegate_->NotifyURLLoaded(url);
+}
+
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/core/blimp_navigation_controller_impl.h b/blimp/client/core/blimp_navigation_controller_impl.h
new file mode 100644
index 0000000..b62ed25a
--- /dev/null
+++ b/blimp/client/core/blimp_navigation_controller_impl.h
@@ -0,0 +1,54 @@
+// 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 BLIMP_CLIENT_CORE_BLIMP_NAVIGATION_CONTROLLER_IMPL_H_
+#define BLIMP_CLIENT_CORE_BLIMP_NAVIGATION_CONTROLLER_IMPL_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "blimp/client/core/public/blimp_navigation_controller.h"
+#include "url/gurl.h"
+
+namespace blimp {
+namespace client {
+
+class BlimpContentsObserver;
+class BlimpNavigationControllerDelegate;
+
+// BlimpContentsImpl is the implementation of the core class in
+// //blimp/client/core, the BlimpContents.
+// The BlimpNavigationControllerImpl is the implementation part of
+// BlimpNavigationController. It maintains the back-forward list for a
+// BlimpContentsImpl and manages all navigation within that list.
+class BlimpNavigationControllerImpl : public BlimpNavigationController {
+ public:
+  explicit BlimpNavigationControllerImpl(
+      BlimpNavigationControllerDelegate* delegate);
+  ~BlimpNavigationControllerImpl() override;
+
+  // BlimpNavigationController implementation.
+  void LoadURL(const GURL& url) override;
+  const GURL& GetURL() override;
+
+ private:
+  void NotifyDelegateURLLoaded(const GURL& url);
+
+  // The delegate contains functionality required for the navigation controller
+  // to function correctly. It is also invoked on relevant state changes of the
+  // navigation controller.
+  BlimpNavigationControllerDelegate* delegate_;
+
+  // The currently active URL.
+  GURL current_url_;
+
+  // TODO(shaktisahu): Remove this after integration with NavigationFeature.
+  base::WeakPtrFactory<BlimpNavigationControllerImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpNavigationControllerImpl);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_CORE_BLIMP_NAVIGATION_CONTROLLER_IMPL_H_
diff --git a/blimp/client/core/blimp_navigation_controller_impl_unittest.cc b/blimp/client/core/blimp_navigation_controller_impl_unittest.cc
new file mode 100644
index 0000000..2b2d7319
--- /dev/null
+++ b/blimp/client/core/blimp_navigation_controller_impl_unittest.cc
@@ -0,0 +1,49 @@
+// 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 "blimp/client/core/blimp_navigation_controller_impl.h"
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "blimp/client/core/blimp_navigation_controller_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blimp {
+namespace client {
+namespace {
+
+const GURL kExampleURL = GURL("https://www.example.com/");
+
+class TestBlimpNavigationControllerDelegate
+    : public BlimpNavigationControllerDelegate {
+ public:
+  TestBlimpNavigationControllerDelegate() = default;
+  ~TestBlimpNavigationControllerDelegate() override = default;
+
+  void NotifyURLLoaded(const GURL& url) override { last_loaded_url_ = url; }
+
+  GURL GetLastLoadedURL() { return last_loaded_url_; }
+
+ private:
+  GURL last_loaded_url_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestBlimpNavigationControllerDelegate);
+};
+
+TEST(BlimpNavigationControllerImplTest, Basic) {
+  base::MessageLoop loop;
+
+  TestBlimpNavigationControllerDelegate delegate;
+  BlimpNavigationControllerImpl navigation_controller(&delegate);
+
+  navigation_controller.LoadURL(kExampleURL);
+  EXPECT_EQ(kExampleURL, navigation_controller.GetURL());
+
+  loop.RunUntilIdle();
+  EXPECT_EQ(kExampleURL, delegate.GetLastLoadedURL());
+}
+
+}  // namespace
+}  // namespace client
+}  // namespace blimp
diff --git a/blimp/client/core/public/BUILD.gn b/blimp/client/core/public/BUILD.gn
new file mode 100644
index 0000000..17e95b2
--- /dev/null
+++ b/blimp/client/core/public/BUILD.gn
@@ -0,0 +1,16 @@
+# 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.
+
+source_set("public") {
+  sources = [
+    "blimp_contents.h",
+    "blimp_contents_observer.h",
+    "blimp_navigation_controller.h",
+  ]
+
+  deps = [
+    "//base",
+    "//url",
+  ]
+}
diff --git a/blimp/client/core/public/blimp_contents.h b/blimp/client/core/public/blimp_contents.h
new file mode 100644
index 0000000..5da71d27
--- /dev/null
+++ b/blimp/client/core/public/blimp_contents.h
@@ -0,0 +1,43 @@
+// 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 BLIMP_CLIENT_CORE_PUBLIC_BLIMP_CONTENTS_H_
+#define BLIMP_CLIENT_CORE_PUBLIC_BLIMP_CONTENTS_H_
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace blimp {
+namespace client {
+
+class BlimpContentsObserver;
+class BlimpNavigationController;
+
+// BlimpContents is the core class in //blimp/client/core. It renders web pages
+// from an engine in a rectangular area.
+// It enables callers to control the blimp engine through the use of the
+// navigation controller.
+class BlimpContents {
+ public:
+  virtual ~BlimpContents() = default;
+
+  // Retrives the navigation controller that controls all navigation related
+  // to this BlimpContents.
+  virtual BlimpNavigationController& GetNavigationController() = 0;
+
+  // Enables adding and removing observers to this BlimpContents.
+  virtual void AddObserver(BlimpContentsObserver* observer) = 0;
+  virtual void RemoveObserver(BlimpContentsObserver* observer) = 0;
+
+ protected:
+  BlimpContents() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpContents);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_CORE_PUBLIC_BLIMP_CONTENTS_H_
diff --git a/blimp/client/core/public/blimp_contents_observer.h b/blimp/client/core/public/blimp_contents_observer.h
new file mode 100644
index 0000000..bd3b86a
--- /dev/null
+++ b/blimp/client/core/public/blimp_contents_observer.h
@@ -0,0 +1,33 @@
+// 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 BLIMP_CLIENT_CORE_PUBLIC_BLIMP_CONTENTS_OBSERVER_H_
+#define BLIMP_CLIENT_CORE_PUBLIC_BLIMP_CONTENTS_OBSERVER_H_
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace blimp {
+namespace client {
+
+// An observer API implemented by classes which are interested in various events
+// related to BlimpContents.
+class BlimpContentsObserver {
+ public:
+  virtual ~BlimpContentsObserver() = default;
+
+  // Invoked when the URL of the BlimpContents is changes.
+  virtual void OnURLUpdated(const GURL& url) {}
+
+ protected:
+  BlimpContentsObserver() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpContentsObserver);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_CORE_PUBLIC_BLIMP_CONTENTS_OBSERVER_H_
diff --git a/blimp/client/core/public/blimp_navigation_controller.h b/blimp/client/core/public/blimp_navigation_controller.h
new file mode 100644
index 0000000..fc79b068
--- /dev/null
+++ b/blimp/client/core/public/blimp_navigation_controller.h
@@ -0,0 +1,42 @@
+// 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 BLIMP_CLIENT_CORE_PUBLIC_BLIMP_NAVIGATION_CONTROLLER_H_
+#define BLIMP_CLIENT_CORE_PUBLIC_BLIMP_NAVIGATION_CONTROLLER_H_
+
+#include "base/macros.h"
+#include "url/gurl.h"
+
+namespace blimp {
+namespace client {
+
+class BlimpContentsObserver;
+
+// The BlimpNavigationController maintains the back-forward list for a
+// BlimpContents and manages all navigation within that list.
+//
+// Each BlimpNavigationController belongs to one BlimpContents, and each
+// BlimpContents has exactly one BlimpNavigationController.
+class BlimpNavigationController {
+ public:
+  virtual ~BlimpNavigationController() = default;
+
+  // Calls to LoadURL informs the engine that it should start navigating to the
+  // provided |url|.
+  virtual void LoadURL(const GURL& url) = 0;
+
+  // Retrieves the URL of the currently selected item in the navigation list.
+  virtual const GURL& GetURL() = 0;
+
+ protected:
+  BlimpNavigationController() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BlimpNavigationController);
+};
+
+}  // namespace client
+}  // namespace blimp
+
+#endif  // BLIMP_CLIENT_CORE_PUBLIC_BLIMP_NAVIGATION_CONTROLLER_H_
diff --git a/build/common.gypi b/build/common.gypi
index 4d9fdb4..34e8f390 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1284,7 +1284,6 @@
 
     # Turns on compiler optimizations in V8 in Debug build.
     'v8_optimized_debug%': 1,
-    'v8_tracing_include_dir': '<(DEPTH)',
 
     # Use system protobuf instead of bundled one.
     'use_system_protobuf%': 0,
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index 7807746f..75e84d88 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -38,6 +38,30 @@
     rebase_path("//tools/gyp/pylib/gyp/mac_tool.py", root_build_dir)
 exec_script("setup_toolchain.py", [ gyp_mac_tool_source ])
 
+# When implementing tools using Python scripts, a TOOL_VERSION=N env
+# variable is placed in front of the command. The N should be incremented
+# whenever the script is changed, so that the build system rebuilds all
+# edges that utilize the script. Ideally this should be changed to use
+# proper input-dirty checking, but that could be expensive. Instead, use a
+# script to get the tool scripts' modification time to use as the version.
+# This won't cause a re-generation of GN files when the tool script changes
+# but it will cause edges to be marked as dirty if the ninja files are
+# regenerated. See https://crbug.com/619083 for details. A proper fix
+# would be to have inputs to tools (https://crbug.com/621119).
+tool_versions =
+    exec_script("get_tool_mtime.py",
+                rebase_path([
+                              "//build/toolchain/mac/compile_xcassets.py",
+                              "//build/toolchain/mac/copy_bundle_data.py",
+                              "//build/toolchain/mac/filter_libtool.py",
+                              "//build/toolchain/mac/linker_driver.py",
+                            ],
+                            root_build_dir),
+                "trim scope")
+
+# Work around for unused variable warning in template https://crbug.com/395883.
+assert(tool_versions != "")
+
 # Shared toolchain definition. Invocations should set toolchain_os to set the
 # build args in this definition.
 template("mac_toolchain") {
@@ -60,6 +84,7 @@
     ld = invoker.ld
 
     linker_driver =
+        "TOOL_VERSION=${tool_versions.linker_driver} " +
         rebase_path("//build/toolchain/mac/linker_driver.py", root_build_dir)
 
     # Make these apply to all tools below.
@@ -136,7 +161,7 @@
     tool("alink") {
       script =
           rebase_path("//build/toolchain/mac/filter_libtool.py", root_build_dir)
-      command = "rm -f {{output}} && python $script libtool -static {{arflags}} -o {{output}} {{inputs}}"
+      command = "rm -f {{output}} && TOOL_VERSION=${tool_versions.filter_libtool} python $script libtool -static {{arflags}} -o {{output}} {{inputs}}"
       description = "LIBTOOL-STATIC {{output}}"
       outputs = [
         "{{output_dir}}/{{target_output_name}}{{output_extension}}",
@@ -283,7 +308,7 @@
       }
       _tool = rebase_path("//build/toolchain/mac/copy_bundle_data.py",
                           root_build_dir)
-      command = "python $_tool ${_extra_args} {{source}} {{output}}"
+      command = "TOOL_VERSION=${tool_versions.copy_bundle_data} python $_tool ${_extra_args} {{source}} {{output}}"
       description = "COPY_BUNDLE_DATA {{source}} {{output}}"
       pool = ":bundle_pool($default_toolchain)"
     }
@@ -298,6 +323,7 @@
         _min_deployment_target = mac_deployment_target
       }
       command = "rm -f {{output}} && " +
+                "TOOL_VERSION=${tool_versions.compile_xcassets} " +
                 "python $_tool -p $_sdk_name -t $_min_deployment_target " +
                 "-o {{output}} {{inputs}}"
 
diff --git a/build/toolchain/mac/copy_bundle_data.py b/build/toolchain/mac/copy_bundle_data.py
index 15127a0..170e8c3 100644
--- a/build/toolchain/mac/copy_bundle_data.py
+++ b/build/toolchain/mac/copy_bundle_data.py
@@ -3,10 +3,22 @@
 # found in the LICENSE file.
 
 import argparse
+import errno
 import os
 import shutil
+import subprocess
 import sys
 
+# Copies a macOS or iOS resource into a bundle. Special handling is given to
+# .strings files.
+#
+# Usage: python copy_bundle_data.py path/to/source path/of/destination
+#
+# Note that if |source| is a directory, its contents will be copied to |dest|,
+# rather than copying the |source| directory itself. Example:
+#   copy_bundle_data.py out/Release/Foo.framework out/Release/App/Foo.framework
+# The contents of Foo.framwork will be copied into the destination path, which
+# includes the name of the destination framework, which is also Foo.framework.
 
 def DetectEncoding(data, default_encoding='UTF-8'):
   """Detects the encoding used by |data| from the Byte-Order-Mark if present.
@@ -80,25 +92,28 @@
     source: string, path to the source file
     dest: string, path to the destination file
   """
-  if os.path.isdir(source):
-    if os.path.exists(dest):
-      shutil.rmtree(dest)
-    # Copy tree.
-    # TODO(thakis): This copies file attributes like mtime, while the
-    # single-file branch below doesn't. This should probably be changed to
-    # be consistent with the single-file branch.
-    shutil.copytree(source, dest, symlinks=True)
-    return
-
-  if os.path.exists(dest):
-    os.unlink(dest)
+  try:
+    shutil.rmtree(dest)
+  except OSError as e:
+    if e.errno == errno.ENOENT:
+      pass
+    elif e.errno == errno.ENOTDIR:
+      os.unlink(dest)
+    else:
+      raise
 
   _, extension = os.path.splitext(source)
   if extension == '.strings':
     CopyStringsFile(source, dest, strings_format)
     return
 
-  shutil.copy(source, dest)
+  # If the source is a directory, add a trailing slash so its contents get
+  # copied, rather than copying the directory itself.
+  if os.path.isdir(source) and not source.endswith('/'):
+    source += '/'
+
+  subprocess.check_call(
+      ['rsync', '--recursive', '--perms', '--links', source, dest])
 
 
 def Main():
diff --git a/build/toolchain/mac/get_tool_mtime.py b/build/toolchain/mac/get_tool_mtime.py
new file mode 100644
index 0000000..4106344b
--- /dev/null
+++ b/build/toolchain/mac/get_tool_mtime.py
@@ -0,0 +1,17 @@
+# 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 os
+import sys
+
+# Usage: python get_tool_mtime.py path/to/file1.py path/to/file2.py
+#
+# Prints a GN scope with the variable name being the basename sans-extension
+# and the value being the file modification time. A variable is emitted for
+# each file argument on the command line.
+
+if __name__ == '__main__':
+  for f in sys.argv[1:]:
+    variable = os.path.splitext(os.path.basename(f))[0]
+    print '%s = %d' % (variable, os.path.getmtime(f))
diff --git a/cc/ipc/quads_struct_traits.cc b/cc/ipc/quads_struct_traits.cc
index cdc16d9..26e1d3f5 100644
--- a/cc/ipc/quads_struct_traits.cc
+++ b/cc/ipc/quads_struct_traits.cc
@@ -211,6 +211,65 @@
   return true;
 }
 
+cc::mojom::YUVColorSpace
+EnumTraits<cc::mojom::YUVColorSpace, cc::YUVVideoDrawQuad::ColorSpace>::ToMojom(
+    cc::YUVVideoDrawQuad::ColorSpace color_space) {
+  switch (color_space) {
+    case cc::YUVVideoDrawQuad::REC_601:
+      return cc::mojom::YUVColorSpace::REC_601;
+    case cc::YUVVideoDrawQuad::REC_709:
+      return cc::mojom::YUVColorSpace::REC_709;
+    case cc::YUVVideoDrawQuad::JPEG:
+      return cc::mojom::YUVColorSpace::JPEG;
+  }
+  NOTREACHED();
+  return cc::mojom::YUVColorSpace::JPEG;
+}
+
+// static
+bool EnumTraits<cc::mojom::YUVColorSpace, cc::YUVVideoDrawQuad::ColorSpace>::
+    FromMojom(cc::mojom::YUVColorSpace input,
+              cc::YUVVideoDrawQuad::ColorSpace* out) {
+  switch (input) {
+    case cc::mojom::YUVColorSpace::REC_601:
+      *out = cc::YUVVideoDrawQuad::REC_601;
+      return true;
+    case cc::mojom::YUVColorSpace::REC_709:
+      *out = cc::YUVVideoDrawQuad::REC_709;
+      return true;
+    case cc::mojom::YUVColorSpace::JPEG:
+      *out = cc::YUVVideoDrawQuad::JPEG;
+      return true;
+  }
+  return false;
+}
+
+// static
+bool StructTraits<cc::mojom::YUVVideoQuadState, cc::DrawQuad>::Read(
+    cc::mojom::YUVVideoQuadStateDataView data,
+    cc::DrawQuad* out) {
+  cc::YUVVideoDrawQuad* quad = static_cast<cc::YUVVideoDrawQuad*>(out);
+  if (!data.ReadYaTexCoordRect(&quad->ya_tex_coord_rect) ||
+      !data.ReadUvTexCoordRect(&quad->uv_tex_coord_rect) ||
+      !data.ReadYaTexSize(&quad->ya_tex_size) ||
+      !data.ReadUvTexSize(&quad->uv_tex_size)) {
+    return false;
+  }
+  quad->resources.ids[cc::YUVVideoDrawQuad::kYPlaneResourceIdIndex] =
+      data.y_plane_resource_id();
+  quad->resources.ids[cc::YUVVideoDrawQuad::kUPlaneResourceIdIndex] =
+      data.u_plane_resource_id();
+  quad->resources.ids[cc::YUVVideoDrawQuad::kVPlaneResourceIdIndex] =
+      data.v_plane_resource_id();
+  quad->resources.ids[cc::YUVVideoDrawQuad::kAPlaneResourceIdIndex] =
+      data.a_plane_resource_id();
+  if (!data.ReadColorSpace(&quad->color_space))
+    return false;
+  quad->resource_offset = data.resource_offset();
+  quad->resource_multiplier = data.resource_multiplier();
+  return true;
+}
+
 // static
 bool StructTraits<cc::mojom::DrawQuad, cc::DrawQuad>::Read(
     cc::mojom::DrawQuadDataView data,
@@ -241,9 +300,7 @@
     case cc::mojom::Material::TILED_CONTENT:
       return data.ReadTileQuadState(out);
     case cc::mojom::Material::YUV_VIDEO_CONTENT:
-      // TODO(fsamuel): Implement YUVVideoDrawQuad
-      // serialization/deserialization.
-      break;
+      return data.ReadYuvVideoQuadState(out);
   }
   NOTREACHED();
   return false;
diff --git a/cc/ipc/quads_struct_traits.h b/cc/ipc/quads_struct_traits.h
index 17abed2..f495efe 100644
--- a/cc/ipc/quads_struct_traits.h
+++ b/cc/ipc/quads_struct_traits.h
@@ -265,6 +265,97 @@
 };
 
 template <>
+struct EnumTraits<cc::mojom::YUVColorSpace, cc::YUVVideoDrawQuad::ColorSpace> {
+  static cc::mojom::YUVColorSpace ToMojom(
+      cc::YUVVideoDrawQuad::ColorSpace color_space);
+  static bool FromMojom(cc::mojom::YUVColorSpace input,
+                        cc::YUVVideoDrawQuad::ColorSpace* out);
+};
+
+template <>
+struct StructTraits<cc::mojom::YUVVideoQuadState, cc::DrawQuad> {
+  static bool IsNull(const cc::DrawQuad& input) {
+    return input.material != cc::DrawQuad::YUV_VIDEO_CONTENT;
+  }
+
+  static void SetToNull(cc::DrawQuad* output) {
+    // There is nothing to deserialize here if the DrawQuad is not a
+    // YUVVideoDrawQuad. If it is, then this should not be called.
+    DCHECK_NE(cc::DrawQuad::YUV_VIDEO_CONTENT, output->material);
+  }
+
+  static const gfx::RectF& ya_tex_coord_rect(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->ya_tex_coord_rect;
+  }
+
+  static const gfx::RectF& uv_tex_coord_rect(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->uv_tex_coord_rect;
+  }
+
+  static const gfx::Size& ya_tex_size(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->ya_tex_size;
+  }
+
+  static const gfx::Size& uv_tex_size(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->uv_tex_size;
+  }
+
+  static uint32_t y_plane_resource_id(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->y_plane_resource_id();
+  }
+
+  static uint32_t u_plane_resource_id(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->u_plane_resource_id();
+  }
+
+  static uint32_t v_plane_resource_id(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->v_plane_resource_id();
+  }
+
+  static uint32_t a_plane_resource_id(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->a_plane_resource_id();
+  }
+
+  static cc::YUVVideoDrawQuad::ColorSpace color_space(
+      const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->color_space;
+  }
+
+  static float resource_offset(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->resource_offset;
+  }
+
+  static float resource_multiplier(const cc::DrawQuad& input) {
+    const cc::YUVVideoDrawQuad* quad =
+        cc::YUVVideoDrawQuad::MaterialCast(&input);
+    return quad->resource_multiplier;
+  }
+
+  static bool Read(cc::mojom::YUVVideoQuadStateDataView data,
+                   cc::DrawQuad* out);
+};
+
+template <>
 struct StructTraits<cc::mojom::DrawQuad, cc::DrawQuad> {
   static cc::DrawQuad::Material material(const cc::DrawQuad& quad) {
     return quad.material;
@@ -318,9 +409,8 @@
     return nullptr;
   }
 
-  static cc::mojom::YUVVideoQuadStatePtr yuv_video_quad_state(
-      const cc::DrawQuad& data) {
-    return nullptr;
+  static const cc::DrawQuad& yuv_video_quad_state(const cc::DrawQuad& data) {
+    return data;
   }
 
   static bool Read(cc::mojom::DrawQuadDataView data, cc::DrawQuad* out);
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index 792eb5e..f958558 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -11,6 +11,7 @@
 #include "cc/quads/render_pass_id.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
+#include "cc/quads/yuv_video_draw_quad.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkString.h"
@@ -510,4 +511,57 @@
   EXPECT_EQ(is_overlay_candidate, output.is_overlay_candidate);
 }
 
+TEST_F(StructTraitsTest, YUVDrawQuad) {
+  const DrawQuad::Material material = DrawQuad::YUV_VIDEO_CONTENT;
+  const gfx::Rect rect(1234, 4321, 1357, 7531);
+  const gfx::Rect opaque_rect(1357, 8642, 432, 123);
+  const gfx::Rect visible_rect(1337, 7331, 561, 293);
+  const bool needs_blending = true;
+  const gfx::RectF ya_tex_coord_rect(1234.1f, 5678.2f, 9101112.3f, 13141516.4f);
+  const gfx::RectF uv_tex_coord_rect(1234.1f, 4321.2f, 1357.3f, 7531.4f);
+  const gfx::Size ya_tex_size(1234, 5678);
+  const gfx::Size uv_tex_size(4321, 8765);
+  const uint32_t y_plane_resource_id = 1337;
+  const uint32_t u_plane_resource_id = 1234;
+  const uint32_t v_plane_resource_id = 2468;
+  const uint32_t a_plane_resource_id = 7890;
+  const YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::JPEG;
+  const float resource_offset = 1337.5f;
+  const float resource_multiplier = 1234.6f;
+
+  SharedQuadState sqs;
+  QuadList input;
+  YUVVideoDrawQuad* quad = input.AllocateAndConstruct<YUVVideoDrawQuad>();
+  quad->SetAll(&sqs, rect, opaque_rect, visible_rect, needs_blending,
+               ya_tex_coord_rect, uv_tex_coord_rect, ya_tex_size, uv_tex_size,
+               y_plane_resource_id, u_plane_resource_id, v_plane_resource_id,
+               a_plane_resource_id, color_space, resource_offset,
+               resource_multiplier);
+
+  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
+  QuadList output;
+  proxy->EchoQuadList(input, &output);
+
+  ASSERT_EQ(input.size(), output.size());
+
+  ASSERT_EQ(material, output.ElementAt(0)->material);
+  const YUVVideoDrawQuad* out_quad =
+      YUVVideoDrawQuad::MaterialCast(output.ElementAt(0));
+  EXPECT_EQ(rect, out_quad->rect);
+  EXPECT_EQ(opaque_rect, out_quad->opaque_rect);
+  EXPECT_EQ(visible_rect, out_quad->visible_rect);
+  EXPECT_EQ(needs_blending, out_quad->needs_blending);
+  EXPECT_EQ(ya_tex_coord_rect, out_quad->ya_tex_coord_rect);
+  EXPECT_EQ(uv_tex_coord_rect, out_quad->uv_tex_coord_rect);
+  EXPECT_EQ(ya_tex_size, out_quad->ya_tex_size);
+  EXPECT_EQ(uv_tex_size, out_quad->uv_tex_size);
+  EXPECT_EQ(y_plane_resource_id, out_quad->y_plane_resource_id());
+  EXPECT_EQ(u_plane_resource_id, out_quad->u_plane_resource_id());
+  EXPECT_EQ(v_plane_resource_id, out_quad->v_plane_resource_id());
+  EXPECT_EQ(a_plane_resource_id, out_quad->a_plane_resource_id());
+  EXPECT_EQ(color_space, out_quad->color_space);
+  EXPECT_EQ(resource_offset, out_quad->resource_offset);
+  EXPECT_EQ(resource_multiplier, out_quad->resource_multiplier);
+}
+
 }  // namespace cc
diff --git a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h
index 1f53e8d..d0581e82 100644
--- a/cc/quads/yuv_video_draw_quad.h
+++ b/cc/quads/yuv_video_draw_quad.h
@@ -18,6 +18,11 @@
 
 class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
  public:
+  static const size_t kYPlaneResourceIdIndex = 0;
+  static const size_t kUPlaneResourceIdIndex = 1;
+  static const size_t kVPlaneResourceIdIndex = 2;
+  static const size_t kAPlaneResourceIdIndex = 3;
+
   enum ColorSpace {
     REC_601,  // SDTV standard with restricted "studio swing" color range.
     REC_709,  // HDTV standard with restricted "studio swing" color range.
@@ -93,11 +98,6 @@
   }
 
  private:
-  static const size_t kYPlaneResourceIdIndex = 0;
-  static const size_t kUPlaneResourceIdIndex = 1;
-  static const size_t kVPlaneResourceIdIndex = 2;
-  static const size_t kAPlaneResourceIdIndex = 3;
-
   void ExtendValue(base::trace_event::TracedValue* value) const override;
 };
 
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index 8a3034cc..0a8a51f 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -114,6 +114,15 @@
   virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
 };
 
+// A BeginFrameSource that does nothing.
+class StubBeginFrameSource : public BeginFrameSource {
+ public:
+  void DidFinishFrame(BeginFrameObserver* obs,
+                      size_t remaining_frames) override {}
+  void AddObserver(BeginFrameObserver* obs) override {}
+  void RemoveObserver(BeginFrameObserver* obs) override {}
+};
+
 // A frame source which ticks itself independently.
 class CC_EXPORT SyntheticBeginFrameSource : public BeginFrameSource {
  public:
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index 7ccaac5..f109a97c 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -16,7 +16,8 @@
 #include "cc/output/gl_renderer.h"
 #include "cc/output/renderer_settings.h"
 #include "cc/output/software_renderer.h"
-#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/display_client.h"
 #include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface.h"
@@ -29,18 +30,6 @@
 #include "cc/output/vulkan_renderer.h"
 #endif
 
-namespace {
-
-class EmptyBeginFrameSource : public cc::BeginFrameSource {
- public:
-  void DidFinishFrame(cc::BeginFrameObserver* obs,
-                      size_t remaining_frames) override{};
-  void AddObserver(cc::BeginFrameObserver* obs) override{};
-  void RemoveObserver(cc::BeginFrameObserver* obs) override{};
-};
-
-}  // namespace
-
 namespace cc {
 
 Display::Display(SurfaceManager* manager,
@@ -48,22 +37,35 @@
                  gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
                  const RendererSettings& settings,
                  uint32_t compositor_surface_namespace,
-                 base::SingleThreadTaskRunner* task_runner,
-                 std::unique_ptr<OutputSurface> output_surface)
+                 std::unique_ptr<BeginFrameSource> begin_frame_source,
+                 std::unique_ptr<OutputSurface> output_surface,
+                 std::unique_ptr<DisplayScheduler> scheduler,
+                 std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter)
     : surface_manager_(manager),
       bitmap_manager_(bitmap_manager),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       settings_(settings),
       compositor_surface_namespace_(compositor_surface_namespace),
-      task_runner_(task_runner),
+      begin_frame_source_(std::move(begin_frame_source)),
       output_surface_(std::move(output_surface)),
-      texture_mailbox_deleter_(task_runner) {
+      scheduler_(std::move(scheduler)),
+      texture_mailbox_deleter_(std::move(texture_mailbox_deleter)) {
+  DCHECK(surface_manager_);
+  DCHECK(output_surface_);
+  DCHECK(texture_mailbox_deleter_);
+  DCHECK_EQ(!scheduler_, !begin_frame_source_);
+
   surface_manager_->AddObserver(this);
+
+  if (scheduler_)
+    scheduler_->SetClient(this);
 }
 
 Display::~Display() {
-  if (observed_begin_frame_source_)
-    surface_manager_->UnregisterBeginFrameSource(observed_begin_frame_source_);
+  // Only do this if Initialize() happened.
+  if (begin_frame_source_ && client_)
+    surface_manager_->UnregisterBeginFrameSource(begin_frame_source_.get());
+
   surface_manager_->RemoveObserver(this);
   if (aggregator_) {
     for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
@@ -74,46 +76,21 @@
   }
 }
 
-void Display::CreateScheduler() {
-  DCHECK(!scheduler_);
-  if (!task_runner_) {
-    // WebView doesn't have a task runner or a real begin frame source,
-    // so just create something fake here.
-    internal_begin_frame_source_.reset(new EmptyBeginFrameSource());
-    vsync_begin_frame_source_ = internal_begin_frame_source_.get();
-    observed_begin_frame_source_ = vsync_begin_frame_source_;
-  } else {
-    DCHECK(vsync_begin_frame_source_);
+void Display::Initialize(DisplayClient* client) {
+  DCHECK(client);
+  client_ = client;
 
-    observed_begin_frame_source_ = vsync_begin_frame_source_;
-    if (settings_.disable_display_vsync) {
-      internal_begin_frame_source_.reset(new BackToBackBeginFrameSource(
-          base::MakeUnique<DelayBasedTimeSource>(task_runner_)));
-      observed_begin_frame_source_ = internal_begin_frame_source_.get();
-    }
+  // This must be done in Initialize() so that the caller can delay this until
+  // they are ready to receive a BeginFrameSource.
+  if (begin_frame_source_) {
+    surface_manager_->RegisterBeginFrameSource(begin_frame_source_.get(),
+                                               compositor_surface_namespace_);
   }
 
-  scheduler_.reset(
-      new DisplayScheduler(this, observed_begin_frame_source_, task_runner_,
-                           output_surface_->capabilities().max_frames_pending));
-  surface_manager_->RegisterBeginFrameSource(observed_begin_frame_source_,
-                                             compositor_surface_namespace_);
-}
-
-bool Display::Initialize(DisplayClient* client) {
-  client_ = client;
-  if (!output_surface_->BindToClient(this))
-    return false;
-  CreateScheduler();
-  return true;
-}
-
-bool Display::InitializeSynchronous(DisplayClient* client) {
-  client_ = client;
-  if (!output_surface_->BindToClient(this))
-    return false;
-  // No scheduler created here.
-  return true;
+  bool ok = output_surface_->BindToClient(this);
+  // The context given to the Display's OutputSurface should already be
+  // initialized, so Bind can not fail.
+  DCHECK(ok);
 }
 
 void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) {
@@ -184,7 +161,7 @@
   if (output_surface_->context_provider()) {
     std::unique_ptr<GLRenderer> renderer = GLRenderer::Create(
         this, &settings_, output_surface_.get(), resource_provider.get(),
-        &texture_mailbox_deleter_, settings_.highp_threshold_min);
+        texture_mailbox_deleter_.get(), settings_.highp_threshold_min);
     if (!renderer)
       return;
     renderer_ = std::move(renderer);
@@ -192,7 +169,7 @@
 #if defined(ENABLE_VULKAN)
     std::unique_ptr<VulkanRenderer> renderer = VulkanRenderer::Create(
         this, &settings_, output_surface_.get(), resource_provider.get(),
-        &texture_mailbox_deleter_, settings_.highp_threshold_min);
+        texture_mailbox_deleter_.get(), settings_.highp_threshold_min);
     if (!renderer)
       return;
     renderer_ = std::move(renderer);
@@ -357,15 +334,16 @@
     renderer_->SwapBuffersComplete();
 }
 
+void Display::CommitVSyncParameters(base::TimeTicks timebase,
+                                    base::TimeDelta interval) {
+  // Display uses a BeginFrameSource instead.
+  NOTREACHED();
+}
+
 void Display::SetBeginFrameSource(BeginFrameSource* source) {
-  // It's expected that there's only a single source from the
-  // BrowserCompositorOutputSurface that corresponds to vsync.  The BFS is
-  // passed BrowserCompositorOutputSurface -> Display -> DisplayScheduler as an
-  // input.  DisplayScheduler makes a decision about which BFS to use and
-  // calls back to Display as DisplaySchedulerClient to register for that
-  // surface id.
-  DCHECK(!vsync_begin_frame_source_);
-  vsync_begin_frame_source_ = source;
+  // The BeginFrameSource is set from the constructor, it doesn't come
+  // from the OutputSurface for the Display.
+  NOTREACHED();
 }
 
 void Display::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 204cfb4..dcd91fdc 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "cc/output/output_surface_client.h"
 #include "cc/output/renderer.h"
-#include "cc/output/texture_mailbox_deleter.h"
 #include "cc/resources/returned_resource.h"
 #include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/display_scheduler.h"
@@ -52,20 +51,21 @@
                                    public RendererClient,
                                    public SurfaceDamageObserver {
  public:
+  // The |begin_frame_source| and |scheduler| may be null (together). In that
+  // case, DrawAndSwap must be called externally when needed.
   Display(SurfaceManager* manager,
           SharedBitmapManager* bitmap_manager,
           gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
           const RendererSettings& settings,
           uint32_t compositor_surface_namespace,
-          base::SingleThreadTaskRunner* task_runner,
-          std::unique_ptr<OutputSurface> output_surface);
+          std::unique_ptr<BeginFrameSource> begin_frame_source,
+          std::unique_ptr<OutputSurface> output_surface,
+          std::unique_ptr<DisplayScheduler> scheduler,
+          std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter);
+
   ~Display() override;
 
-  bool Initialize(DisplayClient* client);
-
-  // When this variant is used, no DisplayScheduler is created, and the caller
-  // is responsible for calling DrawAndSwap when required.
-  bool InitializeSynchronous(DisplayClient* client);
+  void Initialize(DisplayClient* client);
 
   // device_scale_factor is used to communicate to the external window system
   // what scale this was rendered at.
@@ -81,7 +81,7 @@
 
   // OutputSurfaceClient implementation.
   void CommitVSyncParameters(base::TimeTicks timebase,
-                             base::TimeDelta interval) override {}
+                             base::TimeDelta interval) override;
   void SetBeginFrameSource(BeginFrameSource* source) override;
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
   void DidSwapBuffers() override;
@@ -109,10 +109,7 @@
     enlarge_texture_amount_ = enlarge_texture_amount;
   }
 
- protected:
-  // Virtual for tests.
-  virtual void CreateScheduler();
-
+ private:
   void InitializeRenderer();
   void UpdateRootSurfaceResourcesLocked();
 
@@ -130,20 +127,14 @@
   gfx::Size enlarge_texture_amount_;
   bool output_is_secure_ = false;
 
-  // TODO(danakj): Not needed if we create the scheduler from the constructor.
-  base::SingleThreadTaskRunner* task_runner_;
-
+  // The begin_frame_source_ is often known by the output_surface_ and
+  // the scheduler_.
+  std::unique_ptr<BeginFrameSource> begin_frame_source_;
   std::unique_ptr<OutputSurface> output_surface_;
-  // An internal synthetic BFS. May be null when not used.
-  std::unique_ptr<BeginFrameSource> internal_begin_frame_source_;
-  // The real BFS tied to vsync provided by the BrowserCompositorOutputSurface.
-  BeginFrameSource* vsync_begin_frame_source_ = nullptr;
-  // The current BFS driving the Display/DisplayScheduler.
-  BeginFrameSource* observed_begin_frame_source_ = nullptr;
   std::unique_ptr<DisplayScheduler> scheduler_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<SurfaceAggregator> aggregator_;
-  TextureMailboxDeleter texture_mailbox_deleter_;
+  std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter_;
   std::unique_ptr<DirectRenderer> renderer_;
   std::vector<ui::LatencyInfo> stored_latency_info_;
 
diff --git a/cc/surfaces/display_scheduler.cc b/cc/surfaces/display_scheduler.cc
index 4308550..98f2a689 100644
--- a/cc/surfaces/display_scheduler.cc
+++ b/cc/surfaces/display_scheduler.cc
@@ -12,12 +12,10 @@
 
 namespace cc {
 
-DisplayScheduler::DisplayScheduler(DisplaySchedulerClient* client,
-                                   BeginFrameSource* begin_frame_source,
+DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source,
                                    base::SingleThreadTaskRunner* task_runner,
                                    int max_pending_swaps)
-    : client_(client),
-      begin_frame_source_(begin_frame_source),
+    : begin_frame_source_(begin_frame_source),
       task_runner_(task_runner),
       output_surface_lost_(false),
       root_surface_resources_locked_(true),
@@ -40,6 +38,10 @@
     begin_frame_source_->RemoveObserver(this);
 }
 
+void DisplayScheduler::SetClient(DisplaySchedulerClient* client) {
+  client_ = client;
+}
+
 // If we try to draw when the root surface resources are locked, the
 // draw will fail.
 void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) {
diff --git a/cc/surfaces/display_scheduler.h b/cc/surfaces/display_scheduler.h
index fd868b8d..aa3a9067 100644
--- a/cc/surfaces/display_scheduler.h
+++ b/cc/surfaces/display_scheduler.h
@@ -30,12 +30,13 @@
 
 class CC_SURFACES_EXPORT DisplayScheduler : public BeginFrameObserverBase {
  public:
-  DisplayScheduler(DisplaySchedulerClient* client,
-                   BeginFrameSource* begin_frame_source,
+  DisplayScheduler(BeginFrameSource* begin_frame_source,
                    base::SingleThreadTaskRunner* task_runner,
                    int max_pending_swaps);
   ~DisplayScheduler() override;
 
+  void SetClient(DisplaySchedulerClient* client);
+
   void SetRootSurfaceResourcesLocked(bool locked);
   void ForceImmediateSwapIfPossible();
   virtual void DisplayResized();
diff --git a/cc/surfaces/display_scheduler_unittest.cc b/cc/surfaces/display_scheduler_unittest.cc
index bd857c4..082d1621 100644
--- a/cc/surfaces/display_scheduler_unittest.cc
+++ b/cc/surfaces/display_scheduler_unittest.cc
@@ -40,14 +40,10 @@
 
 class TestDisplayScheduler : public DisplayScheduler {
  public:
-  TestDisplayScheduler(DisplaySchedulerClient* client,
-                       BeginFrameSource* begin_frame_source,
+  TestDisplayScheduler(BeginFrameSource* begin_frame_source,
                        base::SingleThreadTaskRunner* task_runner,
                        int max_pending_swaps)
-      : DisplayScheduler(client,
-                         begin_frame_source,
-                         task_runner,
-                         max_pending_swaps),
+      : DisplayScheduler(begin_frame_source, task_runner, max_pending_swaps),
         scheduler_begin_frame_deadline_count_(0) {}
 
   base::TimeTicks DesiredBeginFrameDeadlineTimeForTest() {
@@ -73,22 +69,20 @@
  public:
   DisplaySchedulerTest()
       : fake_begin_frame_source_(0.f, false),
-        now_src_(new base::SimpleTestTickClock()),
         task_runner_(new base::NullTaskRunner),
-        client_(new FakeDisplaySchedulerClient),
-        scheduler_(new TestDisplayScheduler(client_.get(),
-                                            &fake_begin_frame_source_,
-                                            task_runner_.get(),
-                                            kMaxPendingSwaps)) {
-    now_src_->Advance(base::TimeDelta::FromMicroseconds(10000));
+        scheduler_(&fake_begin_frame_source_,
+                   task_runner_.get(),
+                   kMaxPendingSwaps) {
+    now_src_.Advance(base::TimeDelta::FromMicroseconds(10000));
+    scheduler_.SetClient(&client_);
   }
 
   ~DisplaySchedulerTest() override {}
 
-  void SetUp() override { scheduler_->SetRootSurfaceResourcesLocked(false); }
+  void SetUp() override { scheduler_.SetRootSurfaceResourcesLocked(false); }
 
   void BeginFrameForTest() {
-    base::TimeTicks frame_time = now_src_->NowTicks();
+    base::TimeTicks frame_time = now_src_.NowTicks();
     base::TimeDelta interval = BeginFrameArgs::DefaultInterval();
     base::TimeTicks deadline = frame_time + interval;
     fake_begin_frame_source_.TestOnBeginFrame(
@@ -97,16 +91,16 @@
   }
 
  protected:
-  base::SimpleTestTickClock& now_src() { return *now_src_; }
-  FakeDisplaySchedulerClient& client() { return *client_; }
-  DisplayScheduler& scheduler() { return *scheduler_; }
+  base::SimpleTestTickClock& now_src() { return now_src_; }
+  FakeDisplaySchedulerClient& client() { return client_; }
+  DisplayScheduler& scheduler() { return scheduler_; }
 
   FakeExternalBeginFrameSource fake_begin_frame_source_;
 
-  std::unique_ptr<base::SimpleTestTickClock> now_src_;
+  base::SimpleTestTickClock now_src_;
   scoped_refptr<base::NullTaskRunner> task_runner_;
-  std::unique_ptr<FakeDisplaySchedulerClient> client_;
-  std::unique_ptr<TestDisplayScheduler> scheduler_;
+  FakeDisplaySchedulerClient client_;
+  TestDisplayScheduler scheduler_;
 };
 
 TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilNewRootSurface) {
@@ -117,31 +111,31 @@
 
   // Go trough an initial BeginFrame cycle with the root surface.
   BeginFrameForTest();
-  scheduler_->SetNewRootSurface(root_surface_id1);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SetNewRootSurface(root_surface_id1);
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Resize on the next begin frame cycle should cause the deadline to wait
   // for a new root surface.
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->DisplayResized();
-  EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SetNewRootSurface(root_surface_id2);
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.DisplayResized();
+  EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SetNewRootSurface(root_surface_id2);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Verify deadline goes back to normal after resize.
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SurfaceDamaged(root_surface_id2);
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(root_surface_id2);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 }
 
 TEST_F(DisplaySchedulerTest, ResizeHasLateDeadlineUntilDamagedSurface) {
@@ -151,31 +145,31 @@
 
   // Go trough an initial BeginFrame cycle with the root surface.
   BeginFrameForTest();
-  scheduler_->SetNewRootSurface(root_surface_id);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SetNewRootSurface(root_surface_id);
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Resize on the next begin frame cycle should cause the deadline to wait
   // for a new root surface.
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->DisplayResized();
-  EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SurfaceDamaged(root_surface_id);
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.DisplayResized();
+  EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(root_surface_id);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Verify deadline goes back to normal after resize.
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SurfaceDamaged(root_surface_id);
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(root_surface_id);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 }
 
 TEST_F(DisplaySchedulerTest, SurfaceDamaged) {
@@ -184,62 +178,62 @@
   SurfaceId sid2(0, 2, 0);
 
   // Set the root surface
-  scheduler_->SetNewRootSurface(root_surface_id);
+  scheduler_.SetNewRootSurface(root_surface_id);
 
   // Get scheduler to detect surface 1 as active by drawing
   // two frames in a row with damage from surface 1.
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Damage only from surface 2 (inactive) does not trigger deadline early.
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid2);
+  scheduler_.SurfaceDamaged(sid2);
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
 
   // Damage from surface 1 triggers deadline early.
-  scheduler_->SurfaceDamaged(sid1);
+  scheduler_.SurfaceDamaged(sid1);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Make both surface 1 and 2 active.
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid2);
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SurfaceDamaged(sid2);
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Deadline doesn't trigger early until surface 1 and 2 are both damaged.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SurfaceDamaged(sid1);
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(sid1);
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SurfaceDamaged(sid2);
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(sid2);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Make the system idle
   BeginFrameForTest();
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.BeginFrameDeadlineForTest();
   BeginFrameForTest();
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.BeginFrameDeadlineForTest();
 
   // Deadline should trigger early if child surfaces are idle and
   // we get damage on the root surface.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SurfaceDamaged(root_surface_id);
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(root_surface_id);
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->BeginFrameDeadlineForTest();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.BeginFrameDeadlineForTest();
 }
 
 TEST_F(DisplaySchedulerTest, OutputSurfaceLost) {
@@ -247,30 +241,30 @@
   SurfaceId sid1(0, 1, 0);
 
   // Set the root surface
-  scheduler_->SetNewRootSurface(root_surface_id);
+  scheduler_.SetNewRootSurface(root_surface_id);
 
   // DrawAndSwap normally.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  EXPECT_EQ(0, client_->draw_and_swap_count());
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(1, client_->draw_and_swap_count());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  EXPECT_EQ(0, client_.draw_and_swap_count());
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(1, client_.draw_and_swap_count());
 
   // Deadline triggers immediately on OutputSurfaceLost.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->OutputSurfaceLost();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.OutputSurfaceLost();
   EXPECT_GE(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
 
   // Deadline does not DrawAndSwap after OutputSurfaceLost.
-  EXPECT_EQ(1, client_->draw_and_swap_count());
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(1, client_->draw_and_swap_count());
+  EXPECT_EQ(1, client_.draw_and_swap_count());
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(1, client_.draw_and_swap_count());
 }
 
 TEST_F(DisplaySchedulerTest, ResizeCausesSwap) {
@@ -278,22 +272,22 @@
   SurfaceId sid1(0, 1, 0);
 
   // Set the root surface
-  scheduler_->SetNewRootSurface(root_surface_id);
+  scheduler_.SetNewRootSurface(root_surface_id);
 
   // DrawAndSwap normally.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  EXPECT_EQ(0, client_->draw_and_swap_count());
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(1, client_->draw_and_swap_count());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  EXPECT_EQ(0, client_.draw_and_swap_count());
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(1, client_.draw_and_swap_count());
 
-  scheduler_->DisplayResized();
+  scheduler_.DisplayResized();
   BeginFrameForTest();
   // DisplayResized should trigger a swap to happen.
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(2, client_->draw_and_swap_count());
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(2, client_.draw_and_swap_count());
 }
 
 TEST_F(DisplaySchedulerTest, RootSurfaceResourcesLocked) {
@@ -302,44 +296,44 @@
   base::TimeTicks late_deadline;
 
   // Set the root surface
-  scheduler_->SetNewRootSurface(root_surface_id);
+  scheduler_.SetNewRootSurface(root_surface_id);
 
   // DrawAndSwap normally.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  EXPECT_EQ(0, client_->draw_and_swap_count());
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(1, client_->draw_and_swap_count());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  EXPECT_EQ(0, client_.draw_and_swap_count());
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(1, client_.draw_and_swap_count());
 
   // Deadline triggers late while root resources are locked.
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_GT(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SetRootSurfaceResourcesLocked(true);
-  EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_GT(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SetRootSurfaceResourcesLocked(true);
+  EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
 
   // Deadline does not DrawAndSwap while root resources are locked.
-  EXPECT_EQ(1, client_->draw_and_swap_count());
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(1, client_->draw_and_swap_count());
+  EXPECT_EQ(1, client_.draw_and_swap_count());
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(1, client_.draw_and_swap_count());
 
   //  Deadline triggers normally when root resources are unlocked.
   late_deadline = now_src().NowTicks() + BeginFrameArgs::DefaultInterval();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  scheduler_->SetRootSurfaceResourcesLocked(false);
-  scheduler_->SurfaceDamaged(root_surface_id);
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SetRootSurfaceResourcesLocked(false);
+  scheduler_.SurfaceDamaged(root_surface_id);
   EXPECT_EQ(base::TimeTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
 
-  EXPECT_EQ(1, client_->draw_and_swap_count());
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(2, client_->draw_and_swap_count());
+  EXPECT_EQ(1, client_.draw_and_swap_count());
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(2, client_.draw_and_swap_count());
 }
 
 TEST_F(DisplaySchedulerTest, DidSwapBuffers) {
@@ -348,28 +342,28 @@
   SurfaceId sid2(0, 2, 0);
 
   // Set the root surface
-  scheduler_->SetNewRootSurface(root_surface_id);
+  scheduler_.SetNewRootSurface(root_surface_id);
 
   // Get scheduler to detect surface 1 and 2 as active.
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->SurfaceDamaged(sid2);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.SurfaceDamaged(sid2);
+  scheduler_.BeginFrameDeadlineForTest();
   BeginFrameForTest();
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->SurfaceDamaged(sid2);
-  scheduler_->BeginFrameDeadlineForTest();
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.SurfaceDamaged(sid2);
+  scheduler_.BeginFrameDeadlineForTest();
 
   // DrawAndSwap normally.
   BeginFrameForTest();
   EXPECT_LT(now_src().NowTicks(),
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
-  EXPECT_EQ(2, client_->draw_and_swap_count());
-  scheduler_->SurfaceDamaged(sid1);
-  scheduler_->SurfaceDamaged(sid2);
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(3, client_->draw_and_swap_count());
-  scheduler_->DidSwapBuffers();
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
+  EXPECT_EQ(2, client_.draw_and_swap_count());
+  scheduler_.SurfaceDamaged(sid1);
+  scheduler_.SurfaceDamaged(sid2);
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(3, client_.draw_and_swap_count());
+  scheduler_.DidSwapBuffers();
 
   // Deadline triggers late when swap throttled.
   base::TimeTicks late_deadline =
@@ -377,32 +371,32 @@
   BeginFrameForTest();
   // Damage surface 1, but not surface 2 so we avoid triggering deadline
   // early because all surfaces are ready.
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_EQ(late_deadline, scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_EQ(late_deadline, scheduler_.DesiredBeginFrameDeadlineTimeForTest());
 
   // Don't draw and swap in deadline while swap throttled.
-  EXPECT_EQ(3, client_->draw_and_swap_count());
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(3, client_->draw_and_swap_count());
+  EXPECT_EQ(3, client_.draw_and_swap_count());
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(3, client_.draw_and_swap_count());
 
   // Deadline triggers normally once not swap throttled.
   // Damage from previous BeginFrame should cary over, so don't damage again.
   base::TimeTicks expected_deadline =
-      scheduler_->LastUsedBeginFrameArgs().deadline -
+      scheduler_.LastUsedBeginFrameArgs().deadline -
       BeginFrameArgs::DefaultEstimatedParentDrawTime();
-  scheduler_->DidSwapBuffersComplete();
+  scheduler_.DidSwapBuffersComplete();
   BeginFrameForTest();
   EXPECT_EQ(expected_deadline,
-            scheduler_->DesiredBeginFrameDeadlineTimeForTest());
+            scheduler_.DesiredBeginFrameDeadlineTimeForTest());
   // Still waiting for surface 2. Once it updates, deadline should trigger
   // immediately again.
-  scheduler_->SurfaceDamaged(sid2);
-  EXPECT_EQ(scheduler_->DesiredBeginFrameDeadlineTimeForTest(),
+  scheduler_.SurfaceDamaged(sid2);
+  EXPECT_EQ(scheduler_.DesiredBeginFrameDeadlineTimeForTest(),
             base::TimeTicks());
   // Draw and swap now that we aren't throttled.
-  EXPECT_EQ(3, client_->draw_and_swap_count());
-  scheduler_->BeginFrameDeadlineForTest();
-  EXPECT_EQ(4, client_->draw_and_swap_count());
+  EXPECT_EQ(3, client_.draw_and_swap_count());
+  scheduler_.BeginFrameDeadlineForTest();
+  EXPECT_EQ(4, client_.draw_and_swap_count());
 }
 
 // This test verfies that we try to reschedule the deadline
@@ -411,37 +405,37 @@
   SurfaceId root_surface_id(0, 1, 0);
   SurfaceId sid1(0, 2, 0);
   int count = 1;
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
   // Set the root surface
-  scheduler_->SetNewRootSurface(root_surface_id);
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.SetNewRootSurface(root_surface_id);
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
   BeginFrameForTest();
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->BeginFrameDeadlineForTest();
-  scheduler_->DidSwapBuffers();
+  scheduler_.BeginFrameDeadlineForTest();
+  scheduler_.DidSwapBuffers();
   BeginFrameForTest();
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->DidSwapBuffersComplete();
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.DidSwapBuffersComplete();
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->DisplayResized();
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.DisplayResized();
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->SetNewRootSurface(root_surface_id);
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.SetNewRootSurface(root_surface_id);
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->SurfaceDamaged(sid1);
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.SurfaceDamaged(sid1);
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->SetRootSurfaceResourcesLocked(true);
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.SetRootSurfaceResourcesLocked(true);
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 
-  scheduler_->OutputSurfaceLost();
-  EXPECT_EQ(count++, scheduler_->scheduler_begin_frame_deadline_count());
+  scheduler_.OutputSurfaceLost();
+  EXPECT_EQ(count++, scheduler_.scheduler_begin_frame_deadline_count());
 }
 
 }  // namespace
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index 810479bd..3a7ede8e 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -10,9 +10,12 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/copy_output_result.h"
 #include "cc/output/delegated_frame_data.h"
+#include "cc/output/texture_mailbox_deleter.h"
 #include "cc/quads/render_pass.h"
 #include "cc/resources/shared_bitmap_manager.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/display_client.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_factory.h"
 #include "cc/surfaces/surface_factory_client.h"
@@ -53,68 +56,11 @@
   gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; }
 };
 
-class DisplayTest : public testing::Test {
- public:
-  DisplayTest()
-      : factory_(&manager_, &surface_factory_client_),
-        id_allocator_(kArbitrarySurfaceNamespace),
-        software_output_device_(nullptr),
-        task_runner_(new base::NullTaskRunner) {
-    id_allocator_.RegisterSurfaceIdNamespace(&manager_);
-  }
-
- protected:
-  void SetUpContext(std::unique_ptr<TestWebGraphicsContext3D> context) {
-    if (context) {
-      output_surface_ = FakeOutputSurface::Create3d(
-          TestContextProvider::Create(std::move(context)));
-    } else {
-      std::unique_ptr<TestSoftwareOutputDevice> output_device(
-          new TestSoftwareOutputDevice);
-      software_output_device_ = output_device.get();
-      output_surface_ =
-          FakeOutputSurface::CreateSoftware(std::move(output_device));
-    }
-    shared_bitmap_manager_.reset(new TestSharedBitmapManager);
-    output_surface_ptr_ = output_surface_.get();
-  }
-
-  void SubmitCompositorFrame(RenderPassList* pass_list, SurfaceId surface_id) {
-    std::unique_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
-    pass_list->swap(frame_data->render_pass_list);
-
-    std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
-    frame->delegated_frame_data = std::move(frame_data);
-
-    factory_.SubmitCompositorFrame(surface_id, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
-  }
-
-  enum { kArbitrarySurfaceNamespace = 3 };
-
-  SurfaceManager manager_;
-  FakeSurfaceFactoryClient surface_factory_client_;
-  SurfaceFactory factory_;
-  SurfaceIdAllocator id_allocator_;
-  TestSoftwareOutputDevice* software_output_device_;
-  std::unique_ptr<FakeOutputSurface> output_surface_;
-  FakeOutputSurface* output_surface_ptr_;
-  scoped_refptr<base::NullTaskRunner> task_runner_;
-  std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
-};
-
-class StubDisplayClient : public DisplayClient {
- public:
-  void DisplayOutputSurfaceLost() override {}
-  void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
-};
-
 class TestDisplayScheduler : public DisplayScheduler {
  public:
-  TestDisplayScheduler(DisplaySchedulerClient* client,
-                       BeginFrameSource* begin_frame_source,
+  TestDisplayScheduler(BeginFrameSource* begin_frame_source,
                        base::SingleThreadTaskRunner* task_runner)
-      : DisplayScheduler(client, begin_frame_source, task_runner, 1),
+      : DisplayScheduler(begin_frame_source, task_runner, 1),
         damaged(false),
         display_resized_(false),
         has_new_root_surface(false),
@@ -145,41 +91,75 @@
   bool display_resized_;
   bool has_new_root_surface;
   bool swapped;
-
- private:
-  RendererSettings settings_;
 };
 
-class TestDisplay : public Display {
+class DisplayTest : public testing::Test {
  public:
-  TestDisplay(SurfaceManager* manager,
-              SharedBitmapManager* bitmap_manager,
-              gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-              const RendererSettings& settings,
-              uint32_t compositor_surface_namespace,
-              base::SingleThreadTaskRunner* task_runner,
-              std::unique_ptr<OutputSurface> output_surface)
-      : Display(manager,
-                bitmap_manager,
-                gpu_memory_buffer_manager,
-                settings,
-                compositor_surface_namespace,
-                task_runner,
-                std::move(output_surface)),
-        task_runner_(task_runner) {}
+  DisplayTest()
+      : factory_(&manager_, &surface_factory_client_),
+        id_allocator_(kArbitrarySurfaceNamespace),
+        task_runner_(new base::NullTaskRunner) {
+    id_allocator_.RegisterSurfaceIdNamespace(&manager_);
+  }
 
-  TestDisplayScheduler& scheduler() {
-    return *static_cast<TestDisplayScheduler*>(scheduler_.get());
+  void SetUpDisplay(const RendererSettings& settings,
+                    std::unique_ptr<TestWebGraphicsContext3D> context) {
+    std::unique_ptr<BeginFrameSource> begin_frame_source(
+        new StubBeginFrameSource);
+
+    std::unique_ptr<FakeOutputSurface> output_surface;
+    if (context) {
+      output_surface = FakeOutputSurface::Create3d(std::move(context));
+    } else {
+      std::unique_ptr<TestSoftwareOutputDevice> device(
+          new TestSoftwareOutputDevice);
+      software_output_device_ = device.get();
+      output_surface = FakeOutputSurface::CreateSoftware(std::move(device));
+    }
+    output_surface_ = output_surface.get();
+
+    std::unique_ptr<TestDisplayScheduler> scheduler(
+        new TestDisplayScheduler(begin_frame_source.get(), task_runner_.get()));
+    scheduler_ = scheduler.get();
+
+    display_ = base::MakeUnique<Display>(
+        &manager_, &shared_bitmap_manager_,
+        nullptr /* gpu_memory_buffer_manager */, settings,
+        id_allocator_.id_namespace(), std::move(begin_frame_source),
+        std::move(output_surface), std::move(scheduler),
+        base::MakeUnique<TextureMailboxDeleter>(task_runner_.get()));
   }
 
  protected:
-  void CreateScheduler() override {
-    scheduler_.reset(new TestDisplayScheduler(this, vsync_begin_frame_source_,
-                                              task_runner_));
+  void SubmitCompositorFrame(RenderPassList* pass_list, SurfaceId surface_id) {
+    std::unique_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+    pass_list->swap(frame_data->render_pass_list);
+
+    std::unique_ptr<CompositorFrame> frame(new CompositorFrame);
+    frame->delegated_frame_data = std::move(frame_data);
+
+    factory_.SubmitCompositorFrame(surface_id, std::move(frame),
+                                   SurfaceFactory::DrawCallback());
   }
 
- private:
-  base::SingleThreadTaskRunner* task_runner_;
+  static constexpr int kArbitrarySurfaceNamespace = 3;
+
+  SurfaceManager manager_;
+  FakeSurfaceFactoryClient surface_factory_client_;
+  SurfaceFactory factory_;
+  SurfaceIdAllocator id_allocator_;
+  scoped_refptr<base::NullTaskRunner> task_runner_;
+  TestSharedBitmapManager shared_bitmap_manager_;
+  std::unique_ptr<Display> display_;
+  TestSoftwareOutputDevice* software_output_device_ = nullptr;
+  FakeOutputSurface* output_surface_ = nullptr;
+  TestDisplayScheduler* scheduler_ = nullptr;
+};
+
+class StubDisplayClient : public DisplayClient {
+ public:
+  void DisplayOutputSurfaceLost() override {}
+  void DisplaySetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
 };
 
 void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
@@ -188,30 +168,27 @@
 
 // Check that frame is damaged and swapped only under correct conditions.
 TEST_F(DisplayTest, DisplayDamaged) {
-  SetUpContext(nullptr);
-  StubDisplayClient client;
   RendererSettings settings;
   settings.partial_swap_enabled = true;
   settings.finish_rendering_on_resize = true;
-  TestDisplay display(&manager_, shared_bitmap_manager_.get(), nullptr,
-                      settings, id_allocator_.id_namespace(),
-                      task_runner_.get(), std::move(output_surface_));
-  display.Initialize(&client);
-  TestDisplayScheduler& scheduler = display.scheduler();
+  SetUpDisplay(settings, nullptr);
+
+  StubDisplayClient client;
+  display_->Initialize(&client);
 
   SurfaceId surface_id(id_allocator_.GenerateId());
-  EXPECT_FALSE(scheduler.damaged);
-  EXPECT_FALSE(scheduler.has_new_root_surface);
-  display.SetSurfaceId(surface_id, 1.f);
-  EXPECT_FALSE(scheduler.damaged);
-  EXPECT_FALSE(scheduler.display_resized_);
-  EXPECT_TRUE(scheduler.has_new_root_surface);
+  EXPECT_FALSE(scheduler_->damaged);
+  EXPECT_FALSE(scheduler_->has_new_root_surface);
+  display_->SetSurfaceId(surface_id, 1.f);
+  EXPECT_FALSE(scheduler_->damaged);
+  EXPECT_FALSE(scheduler_->display_resized_);
+  EXPECT_TRUE(scheduler_->has_new_root_surface);
 
-  scheduler.ResetDamageForTest();
-  display.Resize(gfx::Size(100, 100));
-  EXPECT_FALSE(scheduler.damaged);
-  EXPECT_TRUE(scheduler.display_resized_);
-  EXPECT_FALSE(scheduler.has_new_root_surface);
+  scheduler_->ResetDamageForTest();
+  display_->Resize(gfx::Size(100, 100));
+  EXPECT_FALSE(scheduler_->damaged);
+  EXPECT_TRUE(scheduler_->display_resized_);
+  EXPECT_FALSE(scheduler_->has_new_root_surface);
 
   factory_.Create(surface_id);
 
@@ -223,17 +200,17 @@
   pass->id = RenderPassId(1, 1);
   pass_list.push_back(std::move(pass));
 
-  scheduler.ResetDamageForTest();
+  scheduler_->ResetDamageForTest();
   SubmitCompositorFrame(&pass_list, surface_id);
-  EXPECT_TRUE(scheduler.damaged);
-  EXPECT_FALSE(scheduler.display_resized_);
-  EXPECT_FALSE(scheduler.has_new_root_surface);
+  EXPECT_TRUE(scheduler_->damaged);
+  EXPECT_FALSE(scheduler_->display_resized_);
+  EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-  EXPECT_FALSE(scheduler.swapped);
-  EXPECT_EQ(0u, output_surface_ptr_->num_sent_frames());
-  display.DrawAndSwap();
-  EXPECT_TRUE(scheduler.swapped);
-  EXPECT_EQ(1u, output_surface_ptr_->num_sent_frames());
+  EXPECT_FALSE(scheduler_->swapped);
+  EXPECT_EQ(0u, output_surface_->num_sent_frames());
+  display_->DrawAndSwap();
+  EXPECT_TRUE(scheduler_->swapped);
+  EXPECT_EQ(1u, output_surface_->num_sent_frames());
   EXPECT_EQ(gfx::Size(100, 100),
             software_output_device_->viewport_pixel_size());
   EXPECT_EQ(gfx::Rect(0, 0, 100, 100), software_output_device_->damage_rect());
@@ -246,16 +223,16 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     SubmitCompositorFrame(&pass_list, surface_id);
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(2u, output_surface_->num_sent_frames());
     EXPECT_EQ(gfx::Size(100, 100),
               software_output_device_->viewport_pixel_size());
     EXPECT_EQ(gfx::Rect(10, 10, 1, 1), software_output_device_->damage_rect());
@@ -269,16 +246,16 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     SubmitCompositorFrame(&pass_list, surface_id);
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(2u, output_surface_->num_sent_frames());
   }
 
   {
@@ -289,16 +266,16 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     SubmitCompositorFrame(&pass_list, surface_id);
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(2u, output_surface_->num_sent_frames());
   }
 
   {
@@ -309,16 +286,16 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     SubmitCompositorFrame(&pass_list, surface_id);
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(3u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(3u, output_surface_->num_sent_frames());
     EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
               software_output_device_->damage_rect());
   }
@@ -334,16 +311,16 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     SubmitCompositorFrame(&pass_list, surface_id);
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(4u, output_surface_->num_sent_frames());
     EXPECT_TRUE(copy_called);
   }
 
@@ -356,7 +333,7 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     std::unique_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
     pass_list.swap(frame_data->render_pass_list);
 
@@ -366,22 +343,22 @@
 
     factory_.SubmitCompositorFrame(surface_id, std::move(frame),
                                    SurfaceFactory::DrawCallback());
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(4u, output_surface_->num_sent_frames());
   }
 
   // Resize should cause a swap if no frame was swapped at the previous size.
   {
-    scheduler.swapped = false;
-    display.Resize(gfx::Size(200, 200));
-    EXPECT_FALSE(scheduler.swapped);
-    EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->Resize(gfx::Size(200, 200));
+    EXPECT_FALSE(scheduler_->swapped);
+    EXPECT_EQ(4u, output_surface_->num_sent_frames());
 
     pass = RenderPass::Create();
     pass->output_rect = gfx::Rect(0, 0, 200, 200);
@@ -389,7 +366,7 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     std::unique_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
     pass_list.swap(frame_data->render_pass_list);
 
@@ -398,19 +375,18 @@
 
     factory_.SubmitCompositorFrame(surface_id, std::move(frame),
                                    SurfaceFactory::DrawCallback());
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.Resize(gfx::Size(100, 100));
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(5u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->Resize(gfx::Size(100, 100));
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(5u, output_surface_->num_sent_frames());
 
     // Latency info from previous frame should be sent now.
-    EXPECT_EQ(
-        1u,
-        output_surface_ptr_->last_sent_frame().metadata.latency_info.size());
+    EXPECT_EQ(1u,
+              output_surface_->last_sent_frame().metadata.latency_info.size());
   }
 
   {
@@ -421,23 +397,22 @@
     pass->id = RenderPassId(1, 1);
 
     pass_list.push_back(std::move(pass));
-    scheduler.ResetDamageForTest();
+    scheduler_->ResetDamageForTest();
     SubmitCompositorFrame(&pass_list, surface_id);
-    EXPECT_TRUE(scheduler.damaged);
-    EXPECT_FALSE(scheduler.display_resized_);
-    EXPECT_FALSE(scheduler.has_new_root_surface);
+    EXPECT_TRUE(scheduler_->damaged);
+    EXPECT_FALSE(scheduler_->display_resized_);
+    EXPECT_FALSE(scheduler_->has_new_root_surface);
 
-    scheduler.swapped = false;
-    display.DrawAndSwap();
-    EXPECT_TRUE(scheduler.swapped);
-    EXPECT_EQ(6u, output_surface_ptr_->num_sent_frames());
+    scheduler_->swapped = false;
+    display_->DrawAndSwap();
+    EXPECT_TRUE(scheduler_->swapped);
+    EXPECT_EQ(6u, output_surface_->num_sent_frames());
     EXPECT_EQ(gfx::Size(100, 100),
               software_output_device_->viewport_pixel_size());
     EXPECT_EQ(gfx::Rect(0, 0, 100, 100),
               software_output_device_->damage_rect());
-    EXPECT_EQ(
-        0u,
-        output_surface_ptr_->last_sent_frame().metadata.latency_info.size());
+    EXPECT_EQ(0u,
+              output_surface_->last_sent_frame().metadata.latency_info.size());
   }
 
   factory_.Destroy(surface_id);
@@ -449,26 +424,24 @@
 };
 
 TEST_F(DisplayTest, Finish) {
-  std::unique_ptr<MockedContext> context(new MockedContext());
-  MockedContext* context_ptr = context.get();
-  SetUpContext(std::move(context));
-
-  EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
-
   SurfaceId surface_id(id_allocator_.GenerateId());
 
-  StubDisplayClient client;
   RendererSettings settings;
   settings.partial_swap_enabled = true;
   settings.finish_rendering_on_resize = true;
-  TestDisplay display(&manager_, shared_bitmap_manager_.get(), nullptr,
-                      settings, surface_id.id_namespace(), task_runner_.get(),
-                      std::move(output_surface_));
-  display.Initialize(&client);
 
-  display.SetSurfaceId(surface_id, 1.f);
+  std::unique_ptr<MockedContext> context(new MockedContext());
+  MockedContext* context_ptr = context.get();
+  EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
 
-  display.Resize(gfx::Size(100, 100));
+  SetUpDisplay(settings, std::move(context));
+
+  StubDisplayClient client;
+  display_->Initialize(&client);
+
+  display_->SetSurfaceId(surface_id, 1.f);
+
+  display_->Resize(gfx::Size(100, 100));
   factory_.Create(surface_id);
 
   {
@@ -482,18 +455,18 @@
     SubmitCompositorFrame(&pass_list, surface_id);
   }
 
-  display.DrawAndSwap();
+  display_->DrawAndSwap();
 
   // First resize and draw shouldn't finish.
   testing::Mock::VerifyAndClearExpectations(context_ptr);
 
   EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM());
-  display.Resize(gfx::Size(150, 150));
+  display_->Resize(gfx::Size(150, 150));
   testing::Mock::VerifyAndClearExpectations(context_ptr);
 
   // Another resize without a swap doesn't need to finish.
   EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
-  display.Resize(gfx::Size(200, 200));
+  display_->Resize(gfx::Size(200, 200));
   testing::Mock::VerifyAndClearExpectations(context_ptr);
 
   EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
@@ -508,12 +481,12 @@
     SubmitCompositorFrame(&pass_list, surface_id);
   }
 
-  display.DrawAndSwap();
+  display_->DrawAndSwap();
 
   testing::Mock::VerifyAndClearExpectations(context_ptr);
 
   EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM());
-  display.Resize(gfx::Size(250, 250));
+  display_->Resize(gfx::Size(250, 250));
   testing::Mock::VerifyAndClearExpectations(context_ptr);
 
   factory_.Destroy(surface_id);
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index ca4e39c..b098614 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -101,10 +101,7 @@
 
   // Avoid initializing GL context here, as this should be sharing the
   // Display's context.
-  bool init = display_->Initialize(this);
-  // Since this class shares its GL context with the Display, Initialize should
-  // not be possible to fail.
-  DCHECK(init);
+  display_->Initialize(this);
   return true;
 }
 
diff --git a/cc/surfaces/surface_display_output_surface_unittest.cc b/cc/surfaces/surface_display_output_surface_unittest.cc
index 536a826..602ff1f 100644
--- a/cc/surfaces/surface_display_output_surface_unittest.cc
+++ b/cc/surfaces/surface_display_output_surface_unittest.cc
@@ -7,9 +7,11 @@
 #include <memory>
 
 #include "cc/output/renderer_settings.h"
+#include "cc/output/texture_mailbox_deleter.h"
 #include "cc/scheduler/begin_frame_source.h"
 #include "cc/scheduler/delay_based_time_source.h"
 #include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "cc/surfaces/surface_manager.h"
 #include "cc/test/fake_output_surface.h"
@@ -28,8 +30,6 @@
   SurfaceDisplayOutputSurfaceTest()
       : now_src_(new base::SimpleTestTickClock()),
         task_runner_(new OrderedSimpleTaskRunner(now_src_.get(), true)),
-        begin_frame_source_(new BackToBackBeginFrameSource(
-            base::MakeUnique<DelayBasedTimeSource>(task_runner_.get()))),
         allocator_(0),
         display_size_(1920, 1080),
         display_rect_(display_size_),
@@ -39,19 +39,25 @@
     std::unique_ptr<FakeOutputSurface> display_output_surface =
         FakeOutputSurface::Create3d();
     display_output_surface_ = display_output_surface.get();
-    display_output_surface_->set_max_frames_pending(2);
 
-    display_.reset(new Display(&surface_manager_, &bitmap_manager_,
-                               &gpu_memory_buffer_manager_, renderer_settings_,
-                               allocator_.id_namespace(), task_runner_.get(),
-                               std::move(display_output_surface)));
+    std::unique_ptr<BeginFrameSource> begin_frame_source(
+        new BackToBackBeginFrameSource(
+            base::MakeUnique<DelayBasedTimeSource>(task_runner_.get())));
+
+    int max_frames_pending = 2;
+    std::unique_ptr<DisplayScheduler> scheduler(new DisplayScheduler(
+        begin_frame_source.get(), task_runner_.get(), max_frames_pending));
+
+    display_.reset(new Display(
+        &surface_manager_, &bitmap_manager_, &gpu_memory_buffer_manager_,
+        RendererSettings(), allocator_.id_namespace(),
+        std::move(begin_frame_source), std::move(display_output_surface),
+        std::move(scheduler),
+        base::MakeUnique<TextureMailboxDeleter>(task_runner_.get())));
     delegated_output_surface_.reset(new SurfaceDisplayOutputSurface(
         &surface_manager_, &allocator_, display_.get(), context_provider_,
         nullptr));
 
-    // Set the Display's begin frame source like a real browser compositor
-    // output surface would.
-    display_->SetBeginFrameSource(begin_frame_source_.get());
     delegated_output_surface_->BindToClient(&delegated_output_surface_client_);
     display_->Resize(display_size_);
 
@@ -87,7 +93,6 @@
  protected:
   std::unique_ptr<base::SimpleTestTickClock> now_src_;
   scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
-  std::unique_ptr<BackToBackBeginFrameSource> begin_frame_source_;
   SurfaceIdAllocator allocator_;
 
   const gfx::Size display_size_;
@@ -95,7 +100,6 @@
   SurfaceManager surface_manager_;
   TestSharedBitmapManager bitmap_manager_;
   TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
-  RendererSettings renderer_settings_;
 
   scoped_refptr<TestContextProvider> context_provider_;
   FakeOutputSurface* display_output_surface_ = nullptr;
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 979165b11d9..416f614b 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -128,9 +128,8 @@
       new TestInProcessContextProvider(nullptr));
   scoped_refptr<TestInProcessContextProvider> worker(
       new TestInProcessContextProvider(compositor.get()));
-  output_surface_.reset(
-      new PixelTestOutputSurface(std::move(compositor), std::move(worker),
-                                 flipped_output_surface, nullptr));
+  output_surface_.reset(new PixelTestOutputSurface(
+      std::move(compositor), std::move(worker), flipped_output_surface));
   output_surface_->BindToClient(output_surface_client_.get());
 
   shared_bitmap_manager_.reset(new TestSharedBitmapManager);
@@ -176,7 +175,7 @@
 void PixelTest::SetUpSoftwareRenderer() {
   std::unique_ptr<SoftwareOutputDevice> device(
       new PixelTestSoftwareOutputDevice());
-  output_surface_.reset(new PixelTestOutputSurface(std::move(device), nullptr));
+  output_surface_.reset(new PixelTestOutputSurface(std::move(device)));
   output_surface_->BindToClient(output_surface_client_.get());
   shared_bitmap_manager_.reset(new TestSharedBitmapManager());
   bool delegated_sync_points_required = false;  // Meaningless for software.
diff --git a/cc/test/pixel_test_delegating_output_surface.cc b/cc/test/pixel_test_delegating_output_surface.cc
index 0a3bc10c4..a7ceef1 100644
--- a/cc/test/pixel_test_delegating_output_surface.cc
+++ b/cc/test/pixel_test_delegating_output_surface.cc
@@ -13,6 +13,8 @@
 #include "cc/output/begin_frame_args.h"
 #include "cc/output/compositor_frame_ack.h"
 #include "cc/output/direct_renderer.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/scheduler/delay_based_time_source.h"
 #include "cc/test/begin_frame_args_test.h"
 #include "cc/test/pixel_test_output_surface.h"
@@ -69,37 +71,38 @@
         new PixelTestSoftwareOutputDevice);
     software_output_device->set_surface_expansion_size(surface_expansion_size);
     output_surface = base::MakeUnique<PixelTestOutputSurface>(
-        std::move(software_output_device), nullptr);
+        std::move(software_output_device));
   } else {
     scoped_refptr<TestInProcessContextProvider> context(
         new TestInProcessContextProvider(nullptr));
     bool flipped_output_surface = false;
     output_surface = base::MakeUnique<PixelTestOutputSurface>(
-        std::move(context), nullptr, flipped_output_surface, nullptr);
+        std::move(context), nullptr, flipped_output_surface);
   }
   output_surface->set_surface_expansion_size(surface_expansion_size);
 
   auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
   CHECK(task_runner);
 
-  display_.reset(new Display(surface_manager_.get(), shared_bitmap_manager_,
-                             gpu_memory_buffer_manager_, RendererSettings(),
-                             surface_id_allocator_->id_namespace(), task_runner,
-                             std::move(output_surface)));
-  display_->SetEnlargePassTextureAmountForTesting(enlarge_pass_texture_amount_);
-
-  if (synchronous_composite_) {
-    bool init = display_->InitializeSynchronous(&display_client_);
-    CHECK(init);
-  } else {
-    begin_frame_source_.reset(new BackToBackBeginFrameSource(
+  std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source;
+  std::unique_ptr<DisplayScheduler> scheduler;
+  if (!synchronous_composite_) {
+    begin_frame_source.reset(new BackToBackBeginFrameSource(
         base::MakeUnique<DelayBasedTimeSource>(task_runner)));
-    display_->SetBeginFrameSource(begin_frame_source_.get());
-
-    bool init = display_->Initialize(&display_client_);
-    CHECK(init);
+    scheduler.reset(new DisplayScheduler(
+        begin_frame_source.get(), task_runner,
+        output_surface->capabilities().max_frames_pending));
   }
 
+  display_.reset(new Display(
+      surface_manager_.get(), shared_bitmap_manager_,
+      gpu_memory_buffer_manager_, RendererSettings(),
+      surface_id_allocator_->id_namespace(), std::move(begin_frame_source),
+      std::move(output_surface), std::move(scheduler),
+      base::MakeUnique<TextureMailboxDeleter>(task_runner)));
+  display_->SetEnlargePassTextureAmountForTesting(enlarge_pass_texture_amount_);
+
+  display_->Initialize(&display_client_);
   return true;
 }
 
diff --git a/cc/test/pixel_test_delegating_output_surface.h b/cc/test/pixel_test_delegating_output_surface.h
index 8738568..b468646 100644
--- a/cc/test/pixel_test_delegating_output_surface.h
+++ b/cc/test/pixel_test_delegating_output_surface.h
@@ -59,8 +59,6 @@
 
   gfx::Size enlarge_pass_texture_amount_;
 
-  std::unique_ptr<BackToBackBeginFrameSource> begin_frame_source_;
-
   // TODO(danakj): These don't to be stored in unique_ptrs when OutputSurface
   // is owned/destroyed on the compositor thread.
   std::unique_ptr<SurfaceManager> surface_manager_;
diff --git a/cc/test/pixel_test_output_surface.cc b/cc/test/pixel_test_output_surface.cc
index 96ab60d1..b13b46d3 100644
--- a/cc/test/pixel_test_output_surface.cc
+++ b/cc/test/pixel_test_output_surface.cc
@@ -7,7 +7,6 @@
 #include <utility>
 
 #include "cc/output/output_surface_client.h"
-#include "cc/scheduler/begin_frame_source.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -15,12 +14,10 @@
 PixelTestOutputSurface::PixelTestOutputSurface(
     scoped_refptr<ContextProvider> context_provider,
     scoped_refptr<ContextProvider> worker_context_provider,
-    bool flipped_output_surface,
-    std::unique_ptr<BeginFrameSource> begin_frame_source)
+    bool flipped_output_surface)
     : OutputSurface(std::move(context_provider),
                     std::move(worker_context_provider),
                     nullptr),
-      begin_frame_source_(std::move(begin_frame_source)),
       external_stencil_test_(false) {
   capabilities_.adjust_deadline_for_parent = false;
   capabilities_.flipped_output_surface = flipped_output_surface;
@@ -28,33 +25,18 @@
 
 PixelTestOutputSurface::PixelTestOutputSurface(
     scoped_refptr<ContextProvider> context_provider,
-    bool flipped_output_surface,
-    std::unique_ptr<BeginFrameSource> begin_frame_source)
+    bool flipped_output_surface)
     : PixelTestOutputSurface(std::move(context_provider),
                              nullptr,
-                             flipped_output_surface,
-                             std::move(begin_frame_source)) {}
+                             flipped_output_surface) {}
 
 PixelTestOutputSurface::PixelTestOutputSurface(
-    std::unique_ptr<SoftwareOutputDevice> software_device,
-    std::unique_ptr<BeginFrameSource> begin_frame_source)
+    std::unique_ptr<SoftwareOutputDevice> software_device)
     : OutputSurface(nullptr, nullptr, std::move(software_device)),
-      begin_frame_source_(std::move(begin_frame_source)),
       external_stencil_test_(false) {}
 
 PixelTestOutputSurface::~PixelTestOutputSurface() {}
 
-bool PixelTestOutputSurface::BindToClient(OutputSurfaceClient* client) {
-  if (!OutputSurface::BindToClient(client))
-    return false;
-
-  // TODO(enne): Once the renderer uses begin frame sources, this will
-  // always be valid.
-  if (begin_frame_source_)
-    client->SetBeginFrameSource(begin_frame_source_.get());
-  return true;
-}
-
 void PixelTestOutputSurface::Reshape(const gfx::Size& size,
                                      float scale_factor,
                                      bool has_alpha) {
diff --git a/cc/test/pixel_test_output_surface.h b/cc/test/pixel_test_output_surface.h
index 6cd4191..b18e69f 100644
--- a/cc/test/pixel_test_output_surface.h
+++ b/cc/test/pixel_test_output_surface.h
@@ -9,25 +9,19 @@
 
 namespace cc {
 
-class BeginFrameSource;
-
 class PixelTestOutputSurface : public OutputSurface {
  public:
   explicit PixelTestOutputSurface(
       scoped_refptr<ContextProvider> context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
-      bool flipped_output_surface,
-      std::unique_ptr<BeginFrameSource> begin_frame_source);
+      bool flipped_output_surface);
   explicit PixelTestOutputSurface(
       scoped_refptr<ContextProvider> context_provider,
-      bool flipped_output_surface,
-      std::unique_ptr<BeginFrameSource> begin_frame_source);
+      bool flipped_output_surface);
   explicit PixelTestOutputSurface(
-      std::unique_ptr<SoftwareOutputDevice> software_device,
-      std::unique_ptr<BeginFrameSource> begin_frame_source);
+      std::unique_ptr<SoftwareOutputDevice> software_device);
   ~PixelTestOutputSurface() override;
 
-  bool BindToClient(OutputSurfaceClient* client) override;
   void Reshape(const gfx::Size& size, float scale_factor, bool alpha) override;
   bool HasExternalStencilTest() const override;
   void SwapBuffers(CompositorFrame* frame) override;
@@ -40,7 +34,6 @@
   }
 
  private:
-  std::unique_ptr<BeginFrameSource> begin_frame_source_;
   gfx::Size surface_expansion_size_;
   bool external_stencil_test_;
 };
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc
index 5f029fb3..bcf5344 100644
--- a/cc/trees/damage_tracker_unittest.cc
+++ b/cc/trees/damage_tracker_unittest.cc
@@ -496,7 +496,7 @@
   LayerImpl* child = root->test_properties()->children[0];
 
   gfx::Transform transform;
-  transform.Translate3d(500.0, 500.0, 0.0);
+  transform.Translate3d(550.0, 500.0, 0.0);
   transform.ApplyPerspectiveDepth(1.0);
   transform.RotateAboutYAxis(45.0);
   transform.Translate3d(-50.0, -50.0, 0.0);
diff --git a/chrome/android/java/res/layout/custom_tabs_toolbar.xml b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
index d288218..c7ca2b7 100644
--- a/chrome/android/java/res/layout/custom_tabs_toolbar.xml
+++ b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
@@ -25,7 +25,8 @@
             android:contentDescription="@string/accessibility_toolbar_btn_site_info"
             android:scaleType="center"
             android:visibility="gone" />
-        <FrameLayout
+        <view
+            class="org.chromium.chrome.browser.toolbar.CustomTabToolbar$InterceptTouchLayout"
             android:id="@+id/title_url_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -54,7 +55,7 @@
                 android:singleLine="true"
                 android:paddingEnd="@dimen/toolbar_edge_padding"
                 android:textSize="@dimen/location_bar_url_text_size" />
-        </FrameLayout>
+        </view>
     </FrameLayout>
     <ImageButton
         android:id="@+id/action_button"
diff --git a/chrome/android/java/res/layout/payment_request.xml b/chrome/android/java/res/layout/payment_request.xml
index ed14f9e2..6886ad6a 100644
--- a/chrome/android/java/res/layout/payment_request.xml
+++ b/chrome/android/java/res/layout/payment_request.xml
@@ -82,28 +82,7 @@
             android:scaleType="center" />
     </FrameLayout>
 
-    <!-- Indeterminate spinny to show that things are processing. -->
-    <ProgressBar
-        android:id="@+id/waiting_progress"
-        android:layout_width="48dp"
-        android:layout_height="48dp"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginTop="@dimen/payments_section_largest_spacing"
-        android:layout_marginBottom="@dimen/payments_section_small_spacing" />
-
-    <!-- Message displayed to the user. -->
-    <TextView
-        android:id="@+id/message"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal"
-        android:layout_marginTop="@dimen/payments_section_small_spacing"
-        android:layout_marginStart="@dimen/payments_section_large_spacing"
-        android:layout_marginEnd="@dimen/payments_section_large_spacing"
-        android:layout_marginBottom="@dimen/payments_section_largest_spacing"
-        android:gravity="center_horizontal"
-        android:textColor="@color/descriptive_text_color"
-        android:textSize="16sp" />
+    <include layout="@layout/payment_request_spinny" />
 
     <!-- Request dialog: Payment information. -->
     <org.chromium.chrome.browser.payments.ui.FadingEdgeScrollView
diff --git a/chrome/android/java/res/layout/payment_request_spinny.xml b/chrome/android/java/res/layout/payment_request_spinny.xml
new file mode 100644
index 0000000..fc20fae
--- /dev/null
+++ b/chrome/android/java/res/layout/payment_request_spinny.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+
+<!-- Indeterminate spinny used to show that things are being loaded in the PaymentRequestUi.
+     Margins in this file are assigned so that it can be either included or inflated and have
+     the correct margins for the situation.  When included in the main bottom sheet, the
+     FrameLayout's margins are applied, but they are ignored when this is inflated without
+     a parent.
+  -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/payment_request_spinny"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginTop="@dimen/payments_section_large_spacing"
+    android:layout_marginBottom="@dimen/payments_section_large_spacing" >
+
+    <!-- Indeterminate spinny to show that things are processing. -->
+    <ProgressBar
+        android:id="@+id/waiting_progress"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_marginTop="16dp"
+        android:layout_gravity="center_horizontal|top" />
+
+    <!-- Message displayed to the user.
+         The top margin is computed assuming there's a 16dp margin above and below the progress bar,
+         which is itself 48dp tall.
+    -->
+    <TextView
+        android:id="@+id/message"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal"
+        android:layout_marginTop="80dp"
+        android:layout_marginStart="@dimen/payments_section_large_spacing"
+        android:layout_marginEnd="@dimen/payments_section_large_spacing"
+        android:layout_marginBottom="@dimen/payments_section_large_spacing" 
+        android:gravity="center_horizontal"
+        android:textColor="@color/descriptive_text_color"
+        android:textSize="16sp" />
+
+</FrameLayout>
diff --git a/chrome/android/java/res/menu/custom_tabs_menu.xml b/chrome/android/java/res/menu/custom_tabs_menu.xml
index d5fbd9e..287cf2823 100644
--- a/chrome/android/java/res/menu/custom_tabs_menu.xml
+++ b/chrome/android/java/res/menu/custom_tabs_menu.xml
@@ -39,4 +39,7 @@
         <item android:id="@+id/open_in_browser_id"
             android:title=""
             android:orderInCategory="2" />
+        <item android:id="@+id/read_it_later_id"
+            android:title="@string/read_it_later"
+            android:orderInCategory="2" />
 </menu>
\ No newline at end of file
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index aa8db40..2ef6a2d 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -343,11 +343,17 @@
     <!-- Clear browsing data preferences dimensions -->
     <dimen name="clear_browsing_data_checkbox_height">56dp</dimen>
 
-    <!-- Payments UI -->
+    <!-- Payments UI
+         * payments_section_checking_spacing:
+           The spec says that the "Checking" text should be 32dp above the bottom of its section.
+           We improvise by using 6dp because sections also have a 10dp padding, so we end up with
+           a 16dp bottom margin on the "Checking" text + 10dp section padding + 6dp leftover.
+    -->
     <dimen name="payments_section_vertical_spacing">10dp</dimen>
     <dimen name="payments_section_small_spacing">8dp</dimen>
     <dimen name="payments_section_large_spacing">16dp</dimen>
     <dimen name="payments_section_largest_spacing">32dp</dimen>
+    <dimen name="payments_section_checking_spacing">6dp</dimen>
     <dimen name="payments_section_descriptive_item_spacing">40dp</dimen>
     <dimen name="payments_section_separator_height">1dp</dimen>
     <dimen name="payments_section_logo_height">36dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
index 74bb493c..1d6f01f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -30,6 +30,7 @@
     }
 
     /** Whether we show an important sites dialog in the "Clear Browsing Data" flow. */
+    public static final String ANDROID_PAY_INTEGRATION_V1 = "AndroidPayIntegrationV1";
     public static final String IMPORTANT_SITES_IN_CBD = "ImportantSitesInCBD";
     public static final String MEDIA_STYLE_NOTIFICATION = "MediaStyleNotification";
     public static final String NTP_FAKE_OMNIBOX_TEXT = "NTPFakeOmniboxText";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 211eaf23..48f5a3c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1091,7 +1091,7 @@
         intent.setClass(this, targetActivity);
         intent.setFlags(MultiWindowUtils.FLAG_ACTIVITY_LAUNCH_ADJACENT);
 
-        tab.detachAndStartReparenting(intent, null, null);
+        tab.detachAndStartReparenting(intent, null, null, true);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 8214df2..c53db52 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -32,6 +32,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.IntentHandler;
@@ -585,7 +586,7 @@
                                 && TextUtils.equals(getPackageName(), creatorPackage)) {
                             RecordUserAction.record(
                                     "TaskManagement.OpenInChromeActionButtonClicked");
-                            if (openCurrentUrlInBrowser(false)) finishAndClose();
+                            if (openCurrentUrlInBrowser(false, true)) finishAndClose();
                         } else {
                             mIntentDataProvider.sendButtonPendingIntentWithUrl(
                                     getApplicationContext(), getActivityTab().getUrl());
@@ -646,9 +647,13 @@
                 && !mIntentDataProvider.shouldShowBookmarkMenuItem()) {
             return true;
         } else if (id == R.id.open_in_browser_id) {
-            openCurrentUrlInBrowser(false);
+            openCurrentUrlInBrowser(false, true);
             RecordUserAction.record("CustomTabsMenuOpenInChrome");
             return true;
+        } else if (id == R.id.read_it_later_id) {
+            openCurrentUrlInBrowser(false, false);
+            RecordUserAction.record("CustomTabsMenuReadItLater");
+            return true;
         } else if (id == R.id.find_in_page_id) {
             mFindToolbarManager.showToolbar();
             if (getContextualSearchManager() != null) {
@@ -703,10 +708,10 @@
     /**
      * Opens the URL currently being displayed in the Custom Tab in the regular browser.
      * @param forceReparenting Whether tab reparenting should be forced for testing.
-     *
+     * @param stayInChrome     Whether the user stays in Chrome after the tab is reparented.
      * @return Whether or not the tab was sent over successfully.
      */
-    boolean openCurrentUrlInBrowser(boolean forceReparenting) {
+    boolean openCurrentUrlInBrowser(boolean forceReparenting, boolean stayInChrome) {
         Tab tab = getActivityTab();
         if (tab == null) return false;
 
@@ -718,6 +723,10 @@
         Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.putExtra(ChromeLauncherActivity.EXTRA_IS_ALLOWED_TO_RETURN_TO_PARENT, false);
+        if (ChromeFeatureList.isEnabled("ReadItLaterInMenu")) {
+            // In this trial both "open in chrome" and "read it later" should target Chrome.
+            intent.setPackage(getPackageName());
+        }
 
         boolean willChromeHandleIntent = getIntentDataProvider().isOpenedByChrome();
         StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
@@ -740,7 +749,8 @@
             };
 
             mMainTab = null;
-            tab.detachAndStartReparenting(intent, startActivityOptions, finalizeCallback);
+            tab.detachAndStartReparenting(intent, startActivityOptions, finalizeCallback,
+                    stayInChrome);
         } else {
             // Temporarily allowing disk access while fixing. TODO: http://crbug.com/581860
             StrictMode.allowThreadDiskReads();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
index 0948e20a..b4751144 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java
@@ -16,6 +16,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.share.ShareHelper;
 import org.chromium.chrome.browser.tab.Tab;
@@ -104,11 +105,18 @@
             }
 
             MenuItem openInChromeItem = menu.findItem(R.id.open_in_browser_id);
-            try {
-                openInChromeItem.setTitle(mDefaultBrowserFetcher.get());
-            } catch (InterruptedException | ExecutionException e) {
-                openInChromeItem.setTitle(
-                        mActivity.getString(R.string.menu_open_in_product_default));
+            MenuItem readItLaterItem = menu.findItem(R.id.read_it_later_id);
+            if (ChromeFeatureList.isEnabled("ReadItLaterInMenu")) {
+                // In the read-it-later experiment, Chrome will be the only browser to open the link
+                openInChromeItem.setTitle(R.string.menu_open_in_chrome);
+            } else {
+                readItLaterItem.setVisible(false);
+                try {
+                    openInChromeItem.setTitle(mDefaultBrowserFetcher.get());
+                } catch (InterruptedException | ExecutionException e) {
+                    openInChromeItem.setTitle(
+                            mActivity.getString(R.string.menu_open_in_product_default));
+                }
             }
 
             // Add custom menu items. Make sure they are only added once.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
index 08509ab..68307c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnectionService.java
@@ -34,7 +34,7 @@
     @Override
     public boolean onUnbind(Intent intent) {
         super.onUnbind(intent);
-        mConnection.logCall("Service#onUnbind()", true);
+        if (mConnection != null) mConnection.logCall("Service#onUnbind()", true);
         return false; // No support for onRebind().
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java
index c0d0388..23dcb65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java
@@ -18,6 +18,7 @@
  */
 public class BackgroundOfflinerTask {
     private static final String TAG = "BGOfflinerTask";
+    private static final long DEFER_START_SECONDS = 5 * 60;
 
     public BackgroundOfflinerTask(BackgroundSchedulerProcessor bridge) {
         mBridge = bridge;
@@ -36,7 +37,12 @@
      */
     public boolean startBackgroundRequests(Context context, Bundle bundle,
                                            ChromeBackgroundServiceWaiter waiter) {
-        processBackgroundRequests(bundle, waiter);
+        // Set up backup scheduled task in case processing is killed before RequestCoordinator
+        // has a chance to reschedule base on remaining work.
+        BackgroundScheduler.schedule(context, DEFER_START_SECONDS);
+
+        // Now initiate processing.
+        processBackgroundRequests(bundle, OfflinePageUtils.getDeviceConditions(context), waiter);
 
         // Gather UMA data to measure how often the user's machine is amenable to background
         // loading when we wake to do a task.
@@ -53,7 +59,8 @@
     // startBackgroundRequests instead of this method.
     @VisibleForTesting
     public void processBackgroundRequests(
-            Bundle bundle, final ChromeBackgroundServiceWaiter waiter) {
+            Bundle bundle, DeviceConditions deviceConditions,
+            final ChromeBackgroundServiceWaiter waiter) {
         // TODO(petewil): Nothing is holding the Wake Lock.  We need some solution to
         // keep hold of it.  Options discussed so far are having a fresh set of functions
         // to grab and release a countdown latch, or holding onto the wake lock ourselves,
@@ -76,6 +83,6 @@
         };
 
         // Pass the activation on to the bridge to the C++ RequestCoordinator.
-        mBridge.startProcessing(callback);
+        mBridge.startProcessing(deviceConditions, callback);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java
index ca9b096..67b2f2d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java
@@ -23,6 +23,14 @@
      * For the given Triggering conditions, start a new GCM Network Manager request.
      */
     public static void schedule(Context context) {
+        schedule(context, 0 /* delayStartSecs */);
+    }
+
+    /**
+     * For the given Triggering conditions, start a new GCM Network Manager request allowed
+     * to run after {@code delayStartSecs} seconds.
+     */
+    public static void schedule(Context context, long delayStartSecs) {
         // Get the GCM Network Scheduler.
         GcmNetworkManager gcmNetworkManager = GcmNetworkManager.getInstance(context);
 
@@ -34,7 +42,7 @@
 
         Task task = new OneoffTask.Builder()
                 .setService(ChromeBackgroundService.class)
-                .setExecutionWindow(0, ONE_WEEK_IN_SECONDS)
+                .setExecutionWindow(delayStartSecs, ONE_WEEK_IN_SECONDS)
                 .setTag(OfflinePageUtils.TASK_TAG)
                 .setUpdateCurrent(true)
                 .setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java
index 6f785286..430f6b7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java
@@ -24,8 +24,11 @@
     // not receive a callback.
     // TODO(dougarnett): consider adding policy check api to let caller
     //     separately determine if not allowed by policy.
-    public static boolean startProcessing(Callback<Boolean> callback) {
-        return nativeStartProcessing(callback);
+    public static boolean startProcessing(
+            DeviceConditions deviceConditions, Callback<Boolean> callback) {
+        return nativeStartProcessing(deviceConditions.isPowerConnected(),
+                deviceConditions.getBatteryPercentage(), deviceConditions.getNetConnectionType(),
+                callback);
     }
 
     @CalledByNative
@@ -38,6 +41,6 @@
         BackgroundScheduler.unschedule(ContextUtils.getApplicationContext());
     }
 
-    private static native boolean nativeStartProcessing(
-            Callback<Boolean> callback);
+    private static native boolean nativeStartProcessing(boolean powerConnected,
+            int batteryPercentage, int netConnectionType, Callback<Boolean> callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java
index 0aa412fd..404e4ff 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerProcessorImpl.java
@@ -13,9 +13,8 @@
  */
 public class BackgroundSchedulerProcessorImpl implements BackgroundSchedulerProcessor {
     @Override
-    public boolean startProcessing(Callback<Boolean> callback) {
-
-        BackgroundSchedulerBridge.startProcessing(callback);
+    public boolean startProcessing(DeviceConditions deviceConditions, Callback<Boolean> callback) {
+        BackgroundSchedulerBridge.startProcessing(deviceConditions, callback);
 
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java
new file mode 100644
index 0000000..ff0e9ba
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java
@@ -0,0 +1,40 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.offlinepages;
+
+/** Device network and power conditions. */
+public class DeviceConditions {
+    private final boolean mPowerConnected;
+    private final int mBatteryPercentage;
+    private final int mNetConnectionType;
+
+    /**
+     * Creates set of device network and power conditions.
+     * @param powerConnected whether device is connected to power
+     * @param batteryPercentage percentage (0-100) of remaining battery power
+     * @param connectionType the org.chromium.net.ConnectionType value for the network connection
+     */
+    public DeviceConditions(boolean powerConnected, int batteryPercentage, int netConnectionType) {
+        mPowerConnected = powerConnected;
+        mBatteryPercentage = batteryPercentage;
+        mNetConnectionType = netConnectionType;
+    }
+
+    public boolean isPowerConnected() {
+        return mPowerConnected;
+    }
+
+    public int getBatteryPercentage() {
+        return mBatteryPercentage;
+    }
+
+    /**
+     * Returns the Chromium enum value for the network connection type. Connection type values are
+     * defined in org.chromium.net.ConnectionType.
+     */
+    public int getNetConnectionType() {
+        return mNetConnectionType;
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
index 9e195bc..3002a60 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java
@@ -201,28 +201,37 @@
         };
     }
 
+    public static DeviceConditions getDeviceConditions(Context context) {
+        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+        // Note this is a sticky intent, so we aren't really registering a receiver, just getting
+        // the sticky intent.  That means that we don't need to unregister the filter later.
+        Intent batteryStatus = context.registerReceiver(null, filter);
+        if (batteryStatus == null) return null;
+
+        return new DeviceConditions(isPowerConnected(batteryStatus),
+                batteryPercentage(batteryStatus),
+                NetworkChangeNotifier.getInstance().getCurrentConnectionType());
+    }
+
     /**
      * Records UMA data when the Offline Pages Background Load service awakens.
      * @param context android context
      */
     public static void recordWakeupUMA(Context context, long taskScheduledTimeMillis) {
-        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
-        // Note this is a sticky intent, so we aren't really registering a receiver, just getting
-        // the sticky intent.  That means that we don't need to unregister the filter later.
-        Intent batteryStatus = context.registerReceiver(null, filter);
-        if (batteryStatus == null) return;
+        DeviceConditions deviceConditions = getDeviceConditions(context);
+        if (deviceConditions == null) return;
 
         // Report charging state.
         RecordHistogram.recordBooleanHistogram(
-                "OfflinePages.Wakeup.ConnectedToPower", isPowerConnected(batteryStatus));
+                "OfflinePages.Wakeup.ConnectedToPower", deviceConditions.isPowerConnected());
 
         // Report battery percentage.
         RecordHistogram.recordPercentageHistogram(
-                "OfflinePages.Wakeup.BatteryPercentage", batteryPercentage(batteryStatus));
+                "OfflinePages.Wakeup.BatteryPercentage", deviceConditions.getBatteryPercentage());
 
         // Report the default network found (or none, if we aren't connected).
-        int connectionType = NetworkChangeNotifier.getInstance().getCurrentConnectionType();
-        Log.d(TAG, "Found single network of type " + connectionType);
+        int connectionType = deviceConditions.getNetConnectionType();
+        Log.d(TAG, "Found default network of type " + connectionType);
         RecordHistogram.recordEnumeratedHistogram("OfflinePages.Wakeup.NetworkAvailable",
                 connectionType, ConnectionType.CONNECTION_LAST + 1);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java
index 499f464..0fa674a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/interfaces/BackgroundSchedulerProcessor.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.offlinepages.interfaces;
 
 import org.chromium.base.Callback;
+import org.chromium.chrome.browser.offlinepages.DeviceConditions;
 
 /**
  * Interface to allow mocking out the BackgroundSchedulerProcessor, which must call static
@@ -17,5 +18,5 @@
      * terminated).  If processing was already active or not able to process for some other reason,
      * returns false and this calling instance will not receive a callback.
      */
-    boolean startProcessing(Callback<Boolean> callback);
+    boolean startProcessing(DeviceConditions deviceConditions, Callback<Boolean> callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
index 188cfd92..a212b08 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java
@@ -132,17 +132,16 @@
      * @param profile The profile to use for starting the AutocompleteController.
      * @param omniboxText The text displayed in the omnibox.
      * @param url The url of the currently loaded web page.
-     * @param isQueryInOmnibox Whether the location bar is currently showing a search query.
      * @param focusedFromFakebox Whether the user entered the omnibox by tapping the fakebox on the
      *                           native NTP. This should be false on all other pages.
      */
     public void startZeroSuggest(Profile profile, String omniboxText, String url,
-            boolean isQueryInOmnibox, boolean focusedFromFakebox) {
+            boolean focusedFromFakebox) {
         if (profile == null || TextUtils.isEmpty(url)) return;
         mNativeAutocompleteControllerAndroid = nativeInit(profile);
         if (mNativeAutocompleteControllerAndroid != 0) {
             nativeOnOmniboxFocused(mNativeAutocompleteControllerAndroid, omniboxText, url,
-                    isQueryInOmnibox, focusedFromFakebox);
+                    focusedFromFakebox);
         }
     }
 
@@ -233,12 +232,12 @@
      * @param webContents The web contents for the tab where the selected suggestion will be shown.
      */
     public void onSuggestionSelected(int selectedIndex, int type,
-            String currentPageUrl, boolean isQueryInOmnibox, boolean focusedFromFakebox,
-            long elapsedTimeSinceModified, int completedLength, WebContents webContents) {
+            String currentPageUrl, boolean focusedFromFakebox, long elapsedTimeSinceModified,
+            int completedLength, WebContents webContents) {
         // Don't natively log voice suggestion results as we add them in Java.
         if (type == OmniboxSuggestionType.VOICE_SUGGEST) return;
         nativeOnSuggestionSelected(mNativeAutocompleteControllerAndroid, selectedIndex,
-                currentPageUrl, isQueryInOmnibox, focusedFromFakebox, elapsedTimeSinceModified,
+                currentPageUrl, focusedFromFakebox, elapsedTimeSinceModified,
                 completedLength, webContents);
     }
 
@@ -323,12 +322,11 @@
     private native void nativeStop(long nativeAutocompleteControllerAndroid, boolean clearResults);
     private native void nativeResetSession(long nativeAutocompleteControllerAndroid);
     private native void nativeOnSuggestionSelected(long nativeAutocompleteControllerAndroid,
-            int selectedIndex, String currentPageUrl, boolean isQueryInOmnibox,
+            int selectedIndex, String currentPageUrl,
             boolean focusedFromFakebox, long elapsedTimeSinceModified,
             int completedLength, WebContents webContents);
     private native void nativeOnOmniboxFocused(long nativeAutocompleteControllerAndroid,
-            String omniboxText, String currentUrl, boolean isQueryInOmnibox,
-            boolean focusedFromFakebox);
+            String omniboxText, String currentUrl, boolean focusedFromFakebox);
     private native void nativeDeleteSuggestion(long nativeAutocompleteControllerAndroid,
             int selectedIndex);
     private native String nativeUpdateMatchDestinationURLWithQueryFormulationTime(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 70c7f10d..bc5aa2a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -179,9 +179,6 @@
 
     private boolean mIgnoreOmniboxItemSelection = true;
 
-    // True if we are showing the search query instead of the url.
-    private boolean mQueryInTheOmnibox = false;
-
     private String mOriginalUrl = "";
 
     private WindowAndroid mWindowAndroid;
@@ -933,7 +930,6 @@
         changeLocationBarIcon(
                 (!DeviceFormFactor.isTablet(getContext()) || !hasFocus) && isSecurityButtonShown());
         mUrlBar.setCursorVisible(hasFocus);
-        if (mQueryInTheOmnibox) mUrlBar.setSelection(mUrlBar.getSelectionEnd());
 
         if (!mUrlFocusedWithoutAnimations) handleUrlFocusAnimation(hasFocus);
 
@@ -1008,7 +1004,7 @@
                 && currentTab != null
                 && !currentTab.isIncognito()) {
             mAutocomplete.startZeroSuggest(currentTab.getProfile(), mUrlBar.getQueryText(),
-                    currentTab.getUrl(), mQueryInTheOmnibox, mUrlFocusedFromFakebox);
+                    currentTab.getUrl(), mUrlFocusedFromFakebox);
         }
     }
 
@@ -1072,12 +1068,7 @@
      * it is set to the default one.
      */
     private void updateCustomSelectionActionModeCallback() {
-        if (mQueryInTheOmnibox) {
-            mUrlBar.setCustomSelectionActionModeCallback(
-                    mActionModeController.getActionModeCallback());
-        } else {
-            mUrlBar.setCustomSelectionActionModeCallback(mDefaultActionModeCallbackForTextEdit);
-        }
+        mUrlBar.setCustomSelectionActionModeCallback(mDefaultActionModeCallbackForTextEdit);
     }
 
     @Override
@@ -1161,8 +1152,6 @@
             // If there are suggestions showing, show the icon for the default suggestion.
             type = suggestionTypeToNavigationButtonType(
                     mSuggestionItems.get(0).getSuggestion());
-        } else if (mQueryInTheOmnibox) {
-            type = NavigationButtonType.MAGNIFIER;
         } else if (!mUrlHasFocus && getCurrentTab() != null && getCurrentTab().isOfflinePage()) {
             type = NavigationButtonType.OFFLINE;
         } else if (isTablet) {
@@ -1172,13 +1161,6 @@
         if (type != mNavigationButtonType) setNavigationButtonType(type);
     }
 
-    /**
-     * @return Whether the query is shown in the omnibox instead of the url.
-     */
-    public boolean showingQueryInTheOmnibox() {
-        return mQueryInTheOmnibox;
-    }
-
     private int getSecurityLevel() {
         if (getCurrentTab() == null) return ConnectionSecurityLevel.NONE;
         return getCurrentTab().getSecurityLevel();
@@ -1213,15 +1195,6 @@
      */
     @Override
     public void updateSecurityIcon(int securityLevel) {
-        if (mQueryInTheOmnibox) {
-            if (securityLevel == ConnectionSecurityLevel.SECURE
-                    || securityLevel == ConnectionSecurityLevel.EV_SECURE) {
-                securityLevel = ConnectionSecurityLevel.NONE;
-            } else if (securityLevel == ConnectionSecurityLevel.SECURITY_WARNING
-                    || securityLevel == ConnectionSecurityLevel.SECURITY_ERROR) {
-                setUrlToPageUrl();
-            }
-        }
         int id = getSecurityIconResource(securityLevel, !shouldEmphasizeHttpsScheme());
         // ImageView#setImageResource is no-op if given resource is the current one.
         if (id == 0) {
@@ -1250,7 +1223,7 @@
     }
 
     private void emphasizeUrl() {
-        if (!mQueryInTheOmnibox) mUrlBar.emphasizeUrl();
+        mUrlBar.emphasizeUrl();
     }
 
     @Override
@@ -1611,19 +1584,7 @@
                 : "updateSuggestionUrlIfNeeded called before native initialization";
 
         String updatedUrl = null;
-        // Only replace URL queries for corpus search refinements, this does not work well
-        // for regular web searches.
-        // TODO(mariakhomenko): improve efficiency by just checking whether corpus exists.
-        if (mQueryInTheOmnibox && !suggestion.isUrlSuggestion()
-                && !TextUtils.isEmpty(mToolbarDataProvider.getCorpusChipText())) {
-            String query = suggestion.getFillIntoEdit();
-            Tab currentTab = getCurrentTab();
-            if (currentTab != null && !TextUtils.isEmpty(currentTab.getUrl())
-                    && !TextUtils.isEmpty(query)) {
-                updatedUrl = TemplateUrlService.getInstance().replaceSearchTermsInUrl(
-                        query, currentTab.getUrl());
-            }
-        } else if (suggestion.getType() != OmniboxSuggestionType.VOICE_SUGGEST) {
+        if (suggestion.getType() != OmniboxSuggestionType.VOICE_SUGGEST) {
             // TODO(mariakhomenko): Ideally we want to update match destination URL with new aqs
             // for query in the omnibox and voice suggestions, but it's currently difficult to do.
             long elapsedTimeSinceInputChange = mNewOmniboxEditSessionTimestamp > 0
@@ -2004,8 +1965,6 @@
             }
         }
 
-        mQueryInTheOmnibox = false;
-
         if (getCurrentTab() == null) {
             setUrlBarText("", null);
             return;
@@ -2024,26 +1983,10 @@
             return;
         }
 
-        boolean showingQuery = false;
-        String displayText = mToolbarDataProvider.getText();
-        if (!TextUtils.isEmpty(displayText) && mToolbarDataProvider.wouldReplaceURL()) {
-            if (getSecurityLevel() == ConnectionSecurityLevel.SECURITY_ERROR) {
-                assert false : "Search terms should not be shown for https error pages.";
-                displayText = url;
-            } else {
-                url = displayText.trim();
-                showingQuery = true;
-                mQueryInTheOmnibox = true;
-            }
-        }
-
-        if (setUrlBarText(url, displayText)) {
+        if (setUrlBarText(url, mToolbarDataProvider.getText())) {
             mUrlBar.deEmphasizeUrl();
             emphasizeUrl();
         }
-        if (showingQuery) {
-            updateNavigationButton();
-        }
         updateCustomSelectionActionModeCallback();
     }
 
@@ -2083,8 +2026,8 @@
         long elapsedTimeSinceModified = mNewOmniboxEditSessionTimestamp > 0
                 ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimestamp) : -1;
         mAutocomplete.onSuggestionSelected(matchPosition, type, currentPageUrl,
-                mQueryInTheOmnibox, mUrlFocusedFromFakebox, elapsedTimeSinceModified,
-                mUrlBar.getAutocompleteLength(), webContents);
+                mUrlFocusedFromFakebox, elapsedTimeSinceModified, mUrlBar.getAutocompleteLength(),
+                webContents);
         loadUrl(url, transition);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java
index a0dd459..66e8e1d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java
@@ -10,6 +10,8 @@
 import android.animation.ObjectAnimator;
 import android.app.Activity;
 import android.app.Dialog;
+import android.content.ClipData;
+import android.content.ClipboardManager;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -33,6 +35,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.widget.Button;
@@ -69,6 +72,7 @@
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.base.WindowAndroid.PermissionCallback;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
+import org.chromium.ui.widget.Toast;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -332,6 +336,18 @@
         mUrlTitle = (ElidedUrlTextView) mContainer.findViewById(R.id.website_settings_url);
         mUrlTitle.setProfile(mProfile);
         mUrlTitle.setOnClickListener(this);
+        // Long press the url text to copy it to the clipboard.
+        mUrlTitle.setOnLongClickListener(new OnLongClickListener() {
+            @Override
+            public boolean onLongClick(View v) {
+                ClipboardManager clipboard = (ClipboardManager) mContext
+                        .getSystemService(Context.CLIPBOARD_SERVICE);
+                ClipData clip = ClipData.newPlainText("url", mUrlTitle.getText());
+                clipboard.setPrimaryClip(clip);
+                Toast.makeText(mContext, R.string.url_copied, Toast.LENGTH_SHORT).show();
+                return true;
+            }
+        });
 
         mUrlConnectionMessage = (TextView) mContainer
                 .findViewById(R.id.website_settings_connection_message);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 09988fb..2bbe04f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -38,7 +38,7 @@
 import org.chromium.mojom.payments.PaymentRequest;
 import org.chromium.mojom.payments.PaymentRequestClient;
 import org.chromium.mojom.payments.PaymentResponse;
-import org.chromium.mojom.payments.ShippingOption;
+import org.chromium.mojom.payments.PaymentShippingOption;
 import org.chromium.ui.base.WindowAndroid;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -110,7 +110,7 @@
      * updated payment options from the website to determine whether shipping options have changed
      * due to user selecting a shipping address.
      */
-    private List<ShippingOption> mRawShippingOptions;
+    private List<PaymentShippingOption> mRawShippingOptions;
 
     /**
      * The UI model for the shipping options. Includes the label and sublabel for each shipping
@@ -446,7 +446,7 @@
      * @param formatter A formatter and validator for the currency amount value.
      * @return The UI representation of the shipping options or null if invalid.
      */
-    private static SectionInformation getValidatedShippingOptions(ShippingOption[] options,
+    private static SectionInformation getValidatedShippingOptions(PaymentShippingOption[] options,
             String totalCurrency, CurrencyStringFormatter formatter) {
         // Shipping options are optional.
         if (options == null || options.length == 0) {
@@ -454,7 +454,7 @@
         }
 
         for (int i = 0; i < options.length; i++) {
-            ShippingOption option = options[i];
+            PaymentShippingOption option = options[i];
 
             // Each "id", "label", "currency", and "value" should be non-empty.
             // Each "value" should be a valid amount value.
@@ -471,7 +471,7 @@
         List<PaymentOption> result = new ArrayList<>();
         int selectedItemIndex = SectionInformation.NO_SELECTION;
         for (int i = 0; i < options.length; i++) {
-            ShippingOption option = options[i];
+            PaymentShippingOption option = options[i];
             result.add(new PaymentOption(option.id, option.label,
                     formatter.format(option.amount.value), PaymentOption.NO_ICON));
             if (option.selected) selectedItemIndex = i;
@@ -676,7 +676,7 @@
 
         PaymentOption selectedShippingOption = mUiShippingOptions.getSelectedItem();
         if (selectedShippingOption != null && selectedShippingOption.getIdentifier() != null) {
-            response.shippingOptionId = selectedShippingOption.getIdentifier();
+            response.shippingOption = selectedShippingOption.getIdentifier();
         }
 
         mClient.onPaymentResponse(response);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
index 540512dc..080d9b64 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestSection.java
@@ -13,6 +13,7 @@
 import android.text.TextUtils.TruncateAt;
 import android.text.style.StyleSpan;
 import android.view.Gravity;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -20,7 +21,6 @@
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ProgressBar;
 import android.widget.RadioButton;
 import android.widget.TextView;
 
@@ -665,10 +665,7 @@
         private GridLayout mOptionLayout;
 
         /** A spinner to show when the user selection is being checked. */
-        private ProgressBar mCheckingProgress;
-
-        /** A message to show when the user selection is being checked. */
-        private TextView mCheckingMessage;
+        private View mCheckingProgress;
 
         /**
          * Constructs an OptionSection.
@@ -722,18 +719,7 @@
 
             mDescriptionView = new TextView(getContext());
 
-            mCheckingProgress = new ProgressBar(getContext());
-            mainSectionLayout.addView(mCheckingProgress, new LinearLayout.LayoutParams(
-                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-            mCheckingProgress.setVisibility(GONE);
-
-            mCheckingMessage = new TextView(getContext());
-            mCheckingMessage.setText(
-                    getContext().getString(R.string.payments_shipping_address_checking));
-            mCheckingMessage.setTextAlignment(TEXT_ALIGNMENT_CENTER);
-            mainSectionLayout.addView(mCheckingMessage, new LinearLayout.LayoutParams(
-                    LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
-            mCheckingMessage.setVisibility(GONE);
+            mCheckingProgress = createLoadingSpinner();
 
             mOptionLayout = new GridLayout(context);
             mOptionLayout.setColumnCount(3);
@@ -748,6 +734,39 @@
             updateOptionList(information, selectedItem);
         }
 
+        private View createLoadingSpinner() {
+            ViewGroup spinnyLayout = (ViewGroup) LayoutInflater.from(getContext()).inflate(
+                    R.layout.payment_request_spinny, null);
+
+            TextView textView = (TextView) spinnyLayout.findViewById(R.id.message);
+            textView.setText(getContext().getString(R.string.payments_checking_option));
+
+            return spinnyLayout;
+        }
+
+        private void setSpinnerVisibility(boolean visibility) {
+            if (visibility) {
+                if (mCheckingProgress.getParent() != null) return;
+
+                ViewGroup parent = (ViewGroup) mOptionLayout.getParent();
+                int optionLayoutIndex = parent.indexOfChild(mOptionLayout);
+                parent.addView(mCheckingProgress, optionLayoutIndex);
+
+                MarginLayoutParams params =
+                        (MarginLayoutParams) mCheckingProgress.getLayoutParams();
+                params.width = LayoutParams.MATCH_PARENT;
+                params.height = LayoutParams.WRAP_CONTENT;
+                params.bottomMargin = getContext().getResources().getDimensionPixelSize(
+                        R.dimen.payments_section_checking_spacing);
+                mCheckingProgress.requestLayout();
+            } else {
+                if (mCheckingProgress.getParent() == null) return;
+
+                ViewGroup parent = (ViewGroup) mCheckingProgress.getParent();
+                parent.removeView(mCheckingProgress);
+            }
+        }
+
         @Override
         public void setDisplayMode(int displayMode) {
             super.setDisplayMode(displayMode);
@@ -755,20 +774,17 @@
             if (displayMode == DISPLAY_MODE_FOCUSED) {
                 setIsSummaryAllowed(false);
                 mOptionLayout.setVisibility(VISIBLE);
-                mCheckingProgress.setVisibility(GONE);
-                mCheckingMessage.setVisibility(GONE);
+                setSpinnerVisibility(false);
                 setDescriptionVisibility(!TextUtils.isEmpty(mDescriptionView.getText()));
             } else if (displayMode == DISPLAY_MODE_CHECKING) {
                 setIsSummaryAllowed(false);
                 mOptionLayout.setVisibility(GONE);
-                mCheckingProgress.setVisibility(VISIBLE);
-                mCheckingMessage.setVisibility(VISIBLE);
+                setSpinnerVisibility(true);
                 setDescriptionVisibility(false);
             } else {
                 setIsSummaryAllowed(true);
                 mOptionLayout.setVisibility(GONE);
-                mCheckingProgress.setVisibility(GONE);
-                mCheckingMessage.setVisibility(GONE);
+                setSpinnerVisibility(false);
                 setDescriptionVisibility(false);
             }
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
index 8a972b23..c6ef347b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/PaymentRequestUI.java
@@ -305,8 +305,7 @@
                 // Hide the loading indicators and show the real sections.
                 mPaymentContainer.setVisibility(View.VISIBLE);
                 mButtonBar.setVisibility(View.VISIBLE);
-                mRequestView.removeView(mRequestView.findViewById(R.id.waiting_progress));
-                mRequestView.removeView(mRequestView.findViewById(R.id.message));
+                mRequestView.removeView(mRequestView.findViewById(R.id.payment_request_spinny));
                 mRequestView.addOnLayoutChangeListener(new SheetEnlargingAnimator(false));
             }
         });
@@ -496,6 +495,7 @@
         }
 
         if (mIsClientCheckingSelection) {
+            startSectionResizeAnimation();
             section.setDisplayMode(PaymentRequestSection.DISPLAY_MODE_CHECKING);
         } else {
             expand(null);
@@ -688,17 +688,7 @@
 
     /** Update the display status of each expandable section. */
     private void updateSectionVisibility() {
-        Runnable animationEndRunnable = new Runnable() {
-            @Override
-            public void run() {
-                mSectionAnimator = null;
-                notifyReadyToClose();
-                notifyReadyForInput();
-                notifyReadyToPay();
-            }
-        };
-        mSectionAnimator = new FocusAnimator(
-                mPaymentContainerLayout, mSelectedSection, animationEndRunnable);
+        startSectionResizeAnimation();
 
         mOrderSummarySection.setDisplayMode(mSelectedSection == mOrderSummarySection
                 ? PaymentRequestSection.DISPLAY_MODE_FOCUSED
@@ -757,6 +747,25 @@
     }
 
     /**
+     * Animates the different sections of the dialog expanding and contracting into their final
+     * positions.
+     */
+    private void startSectionResizeAnimation() {
+        Runnable animationEndRunnable = new Runnable() {
+            @Override
+            public void run() {
+                mSectionAnimator = null;
+                notifyReadyToClose();
+                notifyReadyForInput();
+                notifyReadyToPay();
+            }
+        };
+
+        mSectionAnimator =
+                new FocusAnimator(mPaymentContainerLayout, mSelectedSection, animationEndRunnable);
+    }
+
+    /**
      * Animates the whole dialog fading in and darkening everything else on screen.
      * This particular animation is not tracked because it is not meant to be cancellable.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 39b504c..90a01a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -1490,11 +1490,12 @@
      * @param startActivityOptions Options to pass to {@link Activity#startActivity(Intent, Bundle)}
      * @param finalizeCallback A callback that will be called after the tab is attached to the new
      *                         host activity in {@link #attachAndFinishReparenting}.
+     * @param stayInChrome Whether the user should stay in Chrome after the tab is reparented.
      * @return Whether reparenting succeeded. If false, the tab was not removed and the intent was
      *         not fired.
      */
     public boolean detachAndStartReparenting(Intent intent, Bundle startActivityOptions,
-            Runnable finalizeCallback) {
+            Runnable finalizeCallback, boolean stayInChrome) {
         ChromeActivity activity = getActivity();
         if (activity == null) return false;
 
@@ -1518,7 +1519,7 @@
             // ensure the global count of tabs is correct. See crbug.com/611806.
             intent.putExtra(IntentHandler.EXTRA_TAB_ID, mId);
             AsyncTabParamsManager.add(mId,
-                    new TabReparentingParams(this, intent, finalizeCallback));
+                    new TabReparentingParams(this, intent, finalizeCallback, stayInChrome));
 
             tabModelSelector.getModel(mIncognito).removeTab(this);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
index 02f7079..46668eba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/ChromeTabCreator.java
@@ -5,10 +5,12 @@
 package org.chromium.chrome.browser.tabmodel;
 
 import android.content.Intent;
+import android.os.Handler;
 import android.text.TextUtils;
 
 import org.chromium.base.SysUtils;
 import org.chromium.base.TraceEvent;
+import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.IntentHandler;
 import org.chromium.chrome.browser.TabState;
@@ -25,11 +27,13 @@
 import org.chromium.content_public.common.Referrer;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.widget.Toast;
 
 /**
  * This class creates various kinds of new tabs and adds them to the right {@link TabModel}.
  */
 public class ChromeTabCreator extends TabCreatorManager.TabCreator {
+    private static final int VISIBLE_DURATION_MS = 600;
 
     private final ChromeActivity mActivity;
     private final WindowAndroid mNativeWindow;
@@ -165,6 +169,20 @@
             }
 
             mTabModel.addTab(tab, position, type);
+
+            if (type == TabLaunchType.FROM_REPARENTING) {
+                TabReparentingParams params = (TabReparentingParams) asyncParams;
+                if (!params.shouldStayInChrome()) {
+                    new Handler().postDelayed(new Runnable() {
+                        @Override
+                        public void run() {
+                            mActivity.moveTaskToBack(true);
+                            Toast.makeText(mActivity, R.string.tab_sent_to_background,
+                                    Toast.LENGTH_LONG).show();
+                        }
+                    }, VISIBLE_DURATION_MS);
+                }
+            }
             return tab;
         } finally {
             TraceEvent.end("ChromeTabCreator.createNewTab");
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabReparentingParams.java b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabReparentingParams.java
index f046eb4..e9ae22f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabReparentingParams.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tabmodel/TabReparentingParams.java
@@ -17,15 +17,17 @@
     private final Tab mTabToReparent;
     private final Intent mOriginalIntent;
     private final Runnable mFinalizeCallback;
+    private final boolean mStayInChrome;
 
     /**
      * Basic constructor for {@link TabReparentingParams}.
      */
-    public TabReparentingParams(
-            Tab tabToReparent, Intent originalIntent, Runnable finalizeCallback) {
+    public TabReparentingParams(Tab tabToReparent, Intent originalIntent, Runnable finalizeCallback,
+            boolean stayInChrome) {
         mTabToReparent = tabToReparent;
         mOriginalIntent = originalIntent;
         mFinalizeCallback = finalizeCallback;
+        mStayInChrome = stayInChrome;
     }
 
     @Override
@@ -54,6 +56,13 @@
     }
 
     /**
+     * @return Whether the user should stay in Chrome after the tab is reparented.
+     */
+    public boolean shouldStayInChrome() {
+        return mStayInChrome;
+    }
+
+    /**
      * Carry out any remaining finalization to be done after the tab is reparented.
      */
     public void finalizeTabReparenting() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
index 99f63d76..cb994f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/CustomTabToolbar.java
@@ -26,6 +26,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.widget.FrameLayout;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -65,6 +66,23 @@
  */
 public class CustomTabToolbar extends ToolbarLayout implements LocationBar,
         View.OnLongClickListener {
+
+    /**
+     * A simple {@link FrameLayout} that prevents its children from getting touch events. This is
+     * especially useful to prevent {@link UrlBar} from running custom touch logic since it is
+     * read-only in custom tabs.
+     */
+    public static class InterceptTouchLayout extends FrameLayout {
+        public InterceptTouchLayout(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        public boolean onInterceptTouchEvent(MotionEvent ev) {
+            return true;
+        }
+    }
+
     private static final int BRAND_COLOR_TRANSITION_DURATION_MS = 250;
     private static final int TITLE_ANIM_DELAY_MS = 800;
     private static final int STATE_DOMAIN_ONLY = 0;
@@ -87,7 +105,6 @@
     private boolean mBrandColorTransitionActive;
 
     private CustomTabToolbarAnimationDelegate mAnimDelegate;
-    private long mInitializeTimeStamp;
     private int mState = STATE_DOMAIN_ONLY;
     private String mFirstUrl;
     private boolean mShowsOfflinePage = false;
@@ -116,10 +133,10 @@
         mUrlBar.setDelegate(this);
         mUrlBar.setEnabled(false);
         mUrlBar.setAllowFocus(false);
-        mUrlBar.setOnLongClickListener(this);
         mTitleBar = (TextView) findViewById(R.id.title_bar);
         mLocationBarFrameLayout = findViewById(R.id.location_bar_frame_layout);
         mTitleUrlContainer = findViewById(R.id.title_url_container);
+        mTitleUrlContainer.setOnLongClickListener(this);
         mSecurityButton = (ImageButton) findViewById(R.id.security_button);
         mSecurityIconType = ConnectionSecurityLevel.NONE;
         mCustomActionButton = (ImageButton) findViewById(R.id.action_button);
@@ -139,7 +156,6 @@
             ToolbarTabController tabController, AppMenuButtonHelper appMenuButtonHelper) {
         super.initialize(toolbarDataProvider, tabController, appMenuButtonHelper);
         updateVisualsForState();
-        mInitializeTimeStamp = System.currentTimeMillis();
     }
 
     @Override
@@ -642,7 +658,7 @@
             return showAccessibilityToast(v, getResources().getString(R.string.close_tab));
         } else if (v == mCustomActionButton) {
             return showAccessibilityToast(v, mCustomActionButton.getContentDescription());
-        } else if (v == mUrlBar) {
+        } else if (v == mTitleUrlContainer) {
             ClipboardManager clipboard = (ClipboardManager) getContext()
                     .getSystemService(Context.CLIPBOARD_SERVICE);
             ClipData clip = ClipData.newPlainText("url", mUrlBar.getText());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
index 5798e448..67c25af 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
@@ -27,21 +27,11 @@
     boolean isIncognito();
 
     /**
-     * @return The chip text from the search URL.
-     */
-    String getCorpusChipText();
-
-    /**
      * @return The formatted text (URL or search terms) for display.
      */
     String getText();
 
     /**
-     * @return Whether the text to display is a search query replacing the URL.
-     */
-    boolean wouldReplaceURL();
-
-    /**
      * @return The primary color to use for the background drawable.
      */
     int getPrimaryColor();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index 4fdb385..dfacc12 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -130,21 +130,11 @@
             }
 
             @Override
-            public boolean wouldReplaceURL() {
-                return false;
-            }
-
-            @Override
             public NewTabPage getNewTabPageForCurrentTab() {
                 return null;
             }
 
             @Override
-            public String getCorpusChipText() {
-                return null;
-            }
-
-            @Override
             public int getPrimaryColor() {
                 return 0;
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
index ed3dc09..e133984 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarModel.java
@@ -48,21 +48,7 @@
         return nativeGetText(mNativeToolbarModelAndroid);
     }
 
-    /** @return The chip text from the search URL. */
-    public String getCorpusChipText() {
-        if (mNativeToolbarModelAndroid == 0) return null;
-        return nativeGetCorpusChipText(mNativeToolbarModelAndroid);
-    }
-
-    /** @return Whether the URL is replaced by a search query. */
-    public boolean wouldReplaceURL() {
-        if (mNativeToolbarModelAndroid == 0) return false;
-        return nativeWouldReplaceURL(mNativeToolbarModelAndroid);
-    }
-
     private native long nativeInit(ToolbarModelDelegate delegate);
     private native void nativeDestroy(long nativeToolbarModelAndroid);
     private native String nativeGetText(long nativeToolbarModelAndroid);
-    private native String nativeGetCorpusChipText(long nativeToolbarModelAndroid);
-    private native boolean nativeWouldReplaceURL(long nativeToolbarModelAndroid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index b75e8c94..b51bfeb9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -1681,32 +1681,29 @@
 
         if (isLocationBarShownInNTP() && mNtpSearchBoxScrollPercent == 0f) return;
 
-        if (!FeatureUtilities.isDocumentMode(getContext())
-                || mPhoneLocationBar.showingQueryInTheOmnibox()) {
-            // The call to getLayout() can return null briefly during text changes, but as it
-            // is only needed for RTL calculations, we proceed if the location bar is showing
-            // LTR content.
-            boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mPhoneLocationBar);
-            if (!isLocationBarRtl || mUrlBar.getLayout() != null) {
-                int urlBarStartScrollX = 0;
-                if (isLocationBarRtl) {
-                    urlBarStartScrollX = (int) mUrlBar.getLayout().getPrimaryHorizontal(0);
-                    urlBarStartScrollX -= mUrlBar.getWidth();
-                }
+        // The call to getLayout() can return null briefly during text changes, but as it
+        // is only needed for RTL calculations, we proceed if the location bar is showing
+        // LTR content.
+        boolean isLocationBarRtl = ApiCompatibilityUtils.isLayoutRtl(mPhoneLocationBar);
+        if (!isLocationBarRtl || mUrlBar.getLayout() != null) {
+            int urlBarStartScrollX = 0;
+            if (isLocationBarRtl) {
+                urlBarStartScrollX = (int) mUrlBar.getLayout().getPrimaryHorizontal(0);
+                urlBarStartScrollX -= mUrlBar.getWidth();
+            }
 
-                // If the scroll position matches the current scroll position, do not trigger
-                // this animation as it will cause visible jumps when going from cleared text
-                // back to page URLs (despite it continually calling setScrollX with the same
-                // number).
-                if (mUrlBar.getScrollX() != urlBarStartScrollX) {
-                    animator = ObjectAnimator.ofInt(
-                            mUrlBar,
-                            buildUrlScrollProperty(mPhoneLocationBar, isLocationBarRtl),
-                            urlBarStartScrollX);
-                    animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-                    animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
-                    animators.add(animator);
-                }
+            // If the scroll position matches the current scroll position, do not trigger
+            // this animation as it will cause visible jumps when going from cleared text
+            // back to page URLs (despite it continually calling setScrollX with the same
+            // number).
+            if (mUrlBar.getScrollX() != urlBarStartScrollX) {
+                animator = ObjectAnimator.ofInt(
+                        mUrlBar,
+                        buildUrlScrollProperty(mPhoneLocationBar, isLocationBarRtl),
+                        urlBarStartScrollX);
+                animator.setDuration(URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+                animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+                animators.add(animator);
             }
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
index a01c924..49bdd28 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBar.java
@@ -266,6 +266,7 @@
             if (mAnimatingView != null) {
                 removeCallbacks(mStartIndeterminate);
                 mAnimatingView.cancelAnimation();
+                mTargetProgress = 0;
             }
             setAlpha(0.0f);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java
index 71a01accf..a48fc1c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ToolbarProgressBarAnimatingView.java
@@ -193,6 +193,7 @@
         animate().cancel();
         setAlpha(0.0f);
         mLastAnimatedFraction = 0.0f;
+        mProgressWidth = 0;
     }
 
     /**
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index cbe1ea4..0e31638f0 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2296,6 +2296,14 @@
 However, you aren’t invisible. Going incognito doesn’t hide your browsing from your employer, your internet service provider, or the websites you visit.
       </message>
 
+      <!-- Custom tabs -->
+      <message name="IDS_READ_IT_LATER" desc="Text describing an option for the user to save the tab to Chrome and read it in the future.">
+        Read it later in Chrome
+      </message>
+      <message name="IDS_TAB_SENT_TO_BACKGROUND" desc="A message to show that the tab has been sent to the background Chrome.">
+        Your tab is now in the background.
+      </message>
+
       <!-- Contextual Search -->
       <message name="IDS_CONTEXTUAL_SEARCH_NETWORK_UNAVAILABLE" desc="Tells the user the network is not accessible.">
         Unable to access the network
@@ -2537,7 +2545,7 @@
       <message name="IDS_PAYMENTS_SELECT_SHIPPING_ADDRESS_FOR_SHIPPING_METHODS" desc="Text implying that a user needs to pick a shipping address to see the shipping methods.">
         Select a shipping address to check shipping methods.
       </message>
-      <message name="IDS_PAYMENTS_SHIPPING_ADDRESS_CHECKING" desc="Text explaining that the shipping address is being checked and verified.">
+      <message name="IDS_PAYMENTS_CHECKING_OPTION" desc="Text explaining that the option the user selected is being checked and verified.">
         Checking
       </message>
       <message name="IDS_PAYMENTS_UNSUPPORTED_SHIPPING_ADDRESS" desc="Text implying that a user needs to pick a different shipping address, because the currently selected address is not supported.">
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 2be355b..349bf3eaa 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -515,6 +515,7 @@
   "java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageViewHolder.java",
   "java/src/org/chromium/chrome/browser/ntp/cards/SpacingListItem.java",
   "java/src/org/chromium/chrome/browser/ntp/cards/StatusListItem.java",
+  "java/src/org/chromium/chrome/browser/offlinepages/DeviceConditions.java",
   "java/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTask.java",
   "java/src/org/chromium/chrome/browser/offlinepages/BackgroundScheduler.java",
   "java/src/org/chromium/chrome/browser/offlinepages/BackgroundSchedulerBridge.java",
@@ -1116,7 +1117,6 @@
   "javatests/src/org/chromium/chrome/browser/omaha/UpdateMenuItemHelperTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java",
-  "javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/SuggestionAnswerTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java",
   "javatests/src/org/chromium/chrome/browser/omnibox/VoiceSuggestionProviderTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 27b5407..0cfb817 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -49,6 +49,7 @@
 import org.chromium.base.test.util.Restriction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.IntentHandler;
@@ -107,6 +108,7 @@
         }
     }
 
+    private static final String READ_IT_LATER_FEATURE = "ReadItLaterInMenu";
     private static final int MAX_MENU_CUSTOM_ITEMS = 5;
     private static final int NUM_CHROME_MENU_ITEMS = 3;
     private static final String
@@ -346,7 +348,8 @@
 
         openAppMenuAndAssertMenuShown();
         Menu menu = getActivity().getAppMenuHandler().getAppMenu().getMenu();
-        final int expectedMenuSize = numMenuEntries + NUM_CHROME_MENU_ITEMS;
+        final int expectedMenuSize = numMenuEntries + NUM_CHROME_MENU_ITEMS
+                + (ChromeFeatureList.isEnabled(READ_IT_LATER_FEATURE) ? 1 : 0);
         final int actualMenuSize = getActualMenuSize(menu);
 
         assertNotNull("App menu is not initialized: ", menu);
@@ -389,7 +392,8 @@
 
         openAppMenuAndAssertMenuShown();
         Menu menu = getActivity().getAppMenuHandler().getAppMenu().getMenu();
-        final int expectedMenuSize = MAX_MENU_CUSTOM_ITEMS + NUM_CHROME_MENU_ITEMS;
+        final int expectedMenuSize = MAX_MENU_CUSTOM_ITEMS + NUM_CHROME_MENU_ITEMS
+                + (ChromeFeatureList.isEnabled(READ_IT_LATER_FEATURE) ? 1 : 0);
         final int actualMenuSize = getActualMenuSize(menu);
         assertNotNull("App menu is not initialized: ", menu);
         assertEquals(expectedMenuSize, actualMenuSize);
@@ -433,27 +437,31 @@
     @SmallTest
     public void testOpenInBrowser() throws InterruptedException {
         startCustomTabActivityWithIntent(createMinimalCustomTabIntent());
-        IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
-        filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme());
-        final ActivityMonitor monitor = getInstrumentation().addMonitor(filter, null, false);
         openAppMenuAndAssertMenuShown();
-        final String menuItemTitle = mActivity.getString(R.string.menu_open_in_product_default);
-        ThreadUtils.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                MenuItem item = mActivity.getAppMenuHandler()
-                        .getAppMenu().getMenu().findItem(R.id.open_in_browser_id);
-                assertNotNull(item);
-                assertEquals(menuItemTitle, item.getTitle().toString());
-                mActivity.onMenuOrKeyboardAction(R.id.open_in_browser_id, false);
-            }
-        });
-        CriteriaHelper.pollInstrumentationThread(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return getInstrumentation().checkMonitorHit(monitor, 1);
-            }
-        });
+        if (ChromeFeatureList.isEnabled(READ_IT_LATER_FEATURE)) {
+            // TODO(ianwen): implement this test after read it later becomes a settled feature.
+        } else {
+            IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
+            filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme());
+            final ActivityMonitor monitor = getInstrumentation().addMonitor(filter, null, false);
+            final String menuItemTitle = mActivity.getString(R.string.menu_open_in_product_default);
+            ThreadUtils.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    MenuItem item = mActivity.getAppMenuHandler()
+                            .getAppMenu().getMenu().findItem(R.id.open_in_browser_id);
+                    assertNotNull(item);
+                    assertEquals(menuItemTitle, item.getTitle().toString());
+                    mActivity.onMenuOrKeyboardAction(R.id.open_in_browser_id, false);
+                }
+            });
+            CriteriaHelper.pollInstrumentationThread(new Criteria() {
+                @Override
+                public boolean isSatisfied() {
+                    return getInstrumentation().checkMonitorHit(monitor, 1);
+                }
+            });
+        }
     }
 
     /**
@@ -1287,7 +1295,7 @@
         ThreadUtils.postOnUiThread(new Runnable() {
             @Override
             public void run() {
-                mActivity.openCurrentUrlInBrowser(true);
+                mActivity.openCurrentUrlInBrowser(true, true);
                 assertNull(mActivity.getActivityTab());
             }
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java
deleted file mode 100644
index 7f91a64f..0000000
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/QueryInOmniboxTest.java
+++ /dev/null
@@ -1,339 +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.
-
-package org.chromium.chrome.browser.omnibox;
-
-import static org.chromium.chrome.test.util.OmniboxTestUtils.buildSuggestionMap;
-
-import android.os.Environment;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.text.Selection;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.View;
-import android.widget.ImageButton;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.Feature;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.ntp.NewTabPage;
-import org.chromium.chrome.browser.omnibox.AutocompleteController.OnSuggestionsReceivedListener;
-import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultItem;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
-import org.chromium.chrome.test.ChromeActivityTestCaseBase;
-import org.chromium.chrome.test.util.OmniboxTestUtils;
-import org.chromium.chrome.test.util.OmniboxTestUtils.SuggestionsResult;
-import org.chromium.chrome.test.util.OmniboxTestUtils.SuggestionsResultBuilder;
-import org.chromium.chrome.test.util.OmniboxTestUtils.TestAutocompleteController;
-import org.chromium.chrome.test.util.OmniboxTestUtils.TestSuggestionResultsBuilder;
-import org.chromium.content.browser.test.util.KeyUtils;
-import org.chromium.net.test.EmbeddedTestServer;
-
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.Callable;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Tests for Query in Omnibox.
- */
-public class QueryInOmniboxTest extends ChromeActivityTestCaseBase<ChromeActivity> {
-
-    private static final String QUERY_EXTRACTION_PARAM = "espv=1";
-    private static final String SEARCH_TERM = "Puppies";
-
-    private ImageButton mDeleteButton;
-    private LocationBarLayout mLocationBar;
-    private EmbeddedTestServer mTestServer;
-    private TestToolbarDataProvider mTestToolbarDataProvider;
-    private UrlBar mUrlBar;
-
-    public QueryInOmniboxTest() {
-        super(ChromeActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestServer = EmbeddedTestServer.createAndStartFileServer(
-                getInstrumentation().getContext(), Environment.getExternalStorageDirectory());
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mTestServer.stopAndDestroyServer();
-        super.tearDown();
-    }
-
-    /**
-     * Loading a google https url which is searching for queryText.
-     * @throws InterruptedException
-     */
-    private void loadUrlFromQueryText()
-            throws InterruptedException {
-        String url = mTestServer.getURL("/chrome/test/data/android/google.html?q="
-                + SEARCH_TERM + "&hl=en&client=chrome-mobile&"
-                + QUERY_EXTRACTION_PARAM + "&tbm=isch");
-        loadUrl(url);
-    }
-
-    /**
-     * @return The current UrlBar querytext.
-     */
-    private String getUrlBarQueryText() {
-        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<String>() {
-            @Override
-            public String call() throws Exception {
-                return TextUtils.isEmpty(mUrlBar.getQueryText()) ? "" :
-                        mUrlBar.getQueryText();
-            }
-        });
-    }
-
-    /**
-     * @return The current UrlBar text.
-     */
-    private CharSequence getUrlBarText() {
-        return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<CharSequence>() {
-            @Override
-            public CharSequence call() throws Exception {
-                return mUrlBar.getText();
-            }
-        });
-    }
-
-    /**
-     * Assert the urlbar is displaying the correct text
-     */
-    private void checkUrlBarText() {
-        assertEquals(SEARCH_TERM, getUrlBarQueryText());
-    }
-
-    @SmallTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testQueryInOmnibox() throws InterruptedException {
-        loadUrlFromQueryText();
-        checkUrlBarText();
-    }
-
-    @SmallTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testQueryInOmniboxOnFocus() throws InterruptedException {
-        loadUrlFromQueryText();
-        OmniboxTestUtils.toggleUrlBarFocus(mUrlBar, true);
-        checkUrlBarText();
-    }
-
-    @SmallTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testRefocusWithQueryInOmnibox() throws InterruptedException {
-        loadUrlFromQueryText();
-        assertEquals(SEARCH_TERM, getUrlBarQueryText());
-        assertFalse(OmniboxTestUtils.doesUrlBarHaveFocus(mUrlBar));
-        OmniboxTestUtils.checkUrlBarRefocus(mUrlBar, 5);
-    }
-
-    @MediumTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testDeleteButton() throws InterruptedException {
-        loadUrlFromQueryText();
-        OmniboxTestUtils.toggleUrlBarFocus(mUrlBar, true);
-        checkUrlBarText();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mDeleteButton.callOnClick();
-            }
-        });
-        assertTrue(getUrlBarQueryText().isEmpty());
-    }
-
-    @MediumTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testBackspaceDelete() throws InterruptedException {
-        loadUrlFromQueryText();
-        OmniboxTestUtils.toggleUrlBarFocus(mUrlBar, true);
-        checkUrlBarText();
-        // Backspace delete the entire querytext
-        for (int i = 0; i < SEARCH_TERM.length(); i++) {
-            final View v = mUrlBar;
-            KeyUtils.singleKeyEventView(getInstrumentation(), v, KeyEvent.KEYCODE_DEL);
-        }
-        // Query text should be gone
-        assertTrue(getUrlBarQueryText().isEmpty());
-    }
-
-    @MediumTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testShrinkingAutocompleteTextResults()
-            throws InterruptedException {
-        loadUrlFromQueryText();
-        OmniboxTestUtils.toggleUrlBarFocus(mUrlBar, true);
-        final String term = SEARCH_TERM + "i";
-        setupAutocompleteSuggestions(term);
-        CharSequence urlText = getUrlBarText();
-        assertEquals("URL Bar text not autocompleted as expected.",
-                SEARCH_TERM + "ingz", getUrlBarQueryText());
-        assertEquals(8, Selection.getSelectionStart(urlText));
-        assertEquals(11, Selection.getSelectionEnd(urlText));
-    }
-
-    @MediumTest
-    @Feature({"QueryinOmnibox", "Omnibox"})
-    public void testRefineSuggestion() throws InterruptedException {
-        loadUrlFromQueryText();
-        OmniboxTestUtils.toggleUrlBarFocus(mUrlBar, true);
-        final String term = SEARCH_TERM + "i";
-        setupAutocompleteSuggestions(term);
-        assertEquals(SEARCH_TERM + "ingz", getUrlBarQueryText());
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                OmniboxSuggestion refineView =
-                        ((OmniboxResultItem) mLocationBar.getSuggestionList()
-                                .getAdapter().getItem(1)).getSuggestion();
-                ((OmniboxResultsAdapter) mLocationBar.getSuggestionList()
-                        .getAdapter()).getSuggestionDelegate()
-                        .onRefineSuggestion(refineView);
-            }
-        });
-        CharSequence urlText = getUrlBarText();
-        assertEquals("Refine suggestion did not work as expected.",
-                SEARCH_TERM + "iblarg", getUrlBarQueryText());
-        assertEquals(urlText.length(), Selection.getSelectionStart(urlText));
-        assertEquals(urlText.length(), Selection.getSelectionEnd(urlText));
-    }
-
-    /**
-     * Setup Autocomplete suggestion map, add suggestionListener and autocomplete controller
-     * to the location bar.
-     * @param term The search term.
-     * @throws InterruptedException
-     */
-    private void setupAutocompleteSuggestions(final String term) throws InterruptedException {
-        final String suggestionFor = term.toLowerCase(Locale.US);
-        Map<String, List<SuggestionsResult>> suggestionsMap = buildSuggestionMap(
-                new TestSuggestionResultsBuilder()
-                        .setTextShownFor(suggestionFor)
-                        .addSuggestions(new SuggestionsResultBuilder()
-                                .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
-                                        term , null)
-                                .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
-                                        term + "ng", null)
-                                .setAutocompleteText("ng is awesome"))
-                        .addSuggestions(new SuggestionsResultBuilder()
-                                .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
-                                        term, null)
-                                .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
-                                        term + "z", null)
-                                .setAutocompleteText("ng is hard"))
-                        .addSuggestions(new SuggestionsResultBuilder()
-                                .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
-                                        term, null)
-                                .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
-                                        term + "blarg", null)
-                                .setAutocompleteText("ngz")));
-
-        final Object suggestionsProcessedSignal = new Object();
-        final AtomicInteger suggestionsLeft = new AtomicInteger(
-                suggestionsMap.get(suggestionFor).size());
-        OnSuggestionsReceivedListener suggestionsListener = new OnSuggestionsReceivedListener() {
-            @Override
-            public void onSuggestionsReceived(
-                    List<OmniboxSuggestion> suggestions, String inlineAutocompleteText) {
-                mLocationBar.onSuggestionsReceived(suggestions, inlineAutocompleteText);
-                synchronized (suggestionsProcessedSignal) {
-                    int remaining = suggestionsLeft.decrementAndGet();
-                    if (remaining == 0) {
-                        suggestionsProcessedSignal.notifyAll();
-                    } else if (remaining < 0) {
-                        fail("Unexpected suggestions received");
-                    }
-                }
-            }
-        };
-        final TestAutocompleteController controller = new TestAutocompleteController(
-                mLocationBar, suggestionsListener, suggestionsMap);
-
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                mLocationBar.setAutocompleteController(controller);
-                mUrlBar.append("i");
-            }
-        });
-        synchronized (suggestionsProcessedSignal) {
-            long endTime = SystemClock.uptimeMillis() + 3000;
-            while (suggestionsLeft.get() != 0) {
-                long waitTime = endTime - SystemClock.uptimeMillis();
-                if (waitTime <= 0) break;
-                suggestionsProcessedSignal.wait(waitTime);
-            }
-        }
-    }
-
-    @Override
-    public void startMainActivity() throws InterruptedException {
-        startMainActivityOnBlankPage();
-        mUrlBar = (UrlBar) getActivity().findViewById(R.id.url_bar);
-        mLocationBar = (LocationBarLayout) getActivity().findViewById(R.id.location_bar);
-        mTestToolbarDataProvider =
-                new TestToolbarDataProvider(mLocationBar.getToolbarDataProvider());
-        mLocationBar.setToolbarDataProvider(mTestToolbarDataProvider);
-        mDeleteButton = (ImageButton) getActivity().findViewById(R.id.delete_button);
-    }
-
-    private static class TestToolbarDataProvider implements ToolbarDataProvider {
-        private final ToolbarDataProvider mBaseProvider;
-
-        public TestToolbarDataProvider(ToolbarDataProvider baseProvider) {
-            mBaseProvider = baseProvider;
-        }
-
-        @Override
-        public Tab getTab() {
-            return mBaseProvider.getTab();
-        }
-
-        @Override
-        public NewTabPage getNewTabPageForCurrentTab() {
-            return mBaseProvider.getNewTabPageForCurrentTab();
-        }
-
-        @Override
-        public boolean isIncognito() {
-            return mBaseProvider.isIncognito();
-        }
-
-        @Override
-        public String getText() {
-            return SEARCH_TERM;
-        }
-
-        @Override
-        public boolean wouldReplaceURL() {
-            return true;
-        }
-
-        @Override
-        public int getPrimaryColor() {
-            return mBaseProvider.getPrimaryColor();
-        }
-
-        @Override
-        public boolean isUsingBrandColor() {
-            return mBaseProvider.isUsingBrandColor();
-        }
-
-        @Override
-        public String getCorpusChipText() {
-            return null;
-        }
-    }
-}
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java
index 3ce2f58..c677f13 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/BackgroundOfflinerTaskTest.java
@@ -4,6 +4,9 @@
 
 package org.chromium.chrome.browser.offlinepages;
 
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
 import android.os.Bundle;
@@ -11,10 +14,12 @@
 import org.chromium.base.BaseChromiumApplication;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.ChromeBackgroundServiceWaiter;
+import org.chromium.net.ConnectionType;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
 import org.robolectric.annotation.Config;
 
 /**
@@ -22,7 +27,8 @@
  */
 @RunWith(LocalRobolectricTestRunner.class)
 @Config(manifest = Config.NONE,
-        application = BaseChromiumApplication.class)
+        application = BaseChromiumApplication.class,
+        shadows = { ShadowGcmNetworkManager.class })
 public class BackgroundOfflinerTaskTest {
     private Bundle mTaskExtras;
     private long mTestTime;
@@ -42,16 +48,34 @@
         BackgroundOfflinerTask task =
                 new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
         ChromeBackgroundServiceWaiter waiter = new ChromeBackgroundServiceWaiter(1);
-        task.processBackgroundRequests(mTaskExtras, waiter);
+        DeviceConditions deviceConditions =
+                new DeviceConditions(false, 51, ConnectionType.CONNECTION_WIFI);
+        task.processBackgroundRequests(mTaskExtras, deviceConditions, waiter);
 
         // Check with ShadowBackgroundBackgroundSchedulerProcessor that startProcessing got called.
         assertTrue(mStubBackgroundSchedulerProcessor.getStartProcessingCalled());
+        assertSame(deviceConditions, mStubBackgroundSchedulerProcessor.getDeviceConditions());
 
         // TODO(dougarnett): Call processor callback and verify waiter signaled.
     }
 
     @Test
     @Feature({"OfflinePages"})
+    public void testStartBackgroundRequests() {
+        BackgroundOfflinerTask task = new BackgroundOfflinerTask(mStubBackgroundSchedulerProcessor);
+        ChromeBackgroundServiceWaiter waiter = new ChromeBackgroundServiceWaiter(1);
+        assertNull("Nothing scheduled", ShadowGcmNetworkManager.getScheduledTask());
+        assertTrue(task.startBackgroundRequests(Robolectric.application, mTaskExtras, waiter));
+
+        // Check that the backup task was scheduled.
+        assertNotNull("Backup task scheduled", ShadowGcmNetworkManager.getScheduledTask());
+
+        // Check with ShadowBackgroundBackgroundSchedulerProcessor that startProcessing got called.
+        assertTrue(mStubBackgroundSchedulerProcessor.getStartProcessingCalled());
+    }
+
+    @Test
+    @Feature({"OfflinePages"})
     public void testCallback() {
         // TODO(petewil): Implement the test
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java
index accc8aa..eeab851d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/StubBackgroundSchedulerProcessor.java
@@ -11,15 +11,21 @@
  * Custom stub for our own BackgroundSchedulerRequestProcessor.
  */
 public class StubBackgroundSchedulerProcessor implements BackgroundSchedulerProcessor {
-    private boolean mStartProcessingCalled = false;
+    private boolean mStartProcessingCalled;
+    private DeviceConditions mDeviceConditions;
 
     public boolean getStartProcessingCalled() {
         return mStartProcessingCalled;
     }
 
+    public DeviceConditions getDeviceConditions() {
+        return mDeviceConditions;
+    }
+
     @Override
-    public boolean startProcessing(Callback<Boolean> callback) {
+    public boolean startProcessing(DeviceConditions deviceConditions, Callback<Boolean> callback) {
         mStartProcessingCalled = true;
+        mDeviceConditions = deviceConditions;
         return true;
     }
 }
diff --git a/chrome/app/chrome_exe_main_win.cc b/chrome/app/chrome_exe_main_win.cc
index 6eeb475..bed0790 100644
--- a/chrome/app/chrome_exe_main_win.cc
+++ b/chrome/app/chrome_exe_main_win.cc
@@ -229,8 +229,7 @@
   // except for the browser process. Any new process type will have to assign
   // itself a prefetch id. See kPrefetchArgument* constants in
   // content_switches.cc for details.
-  DCHECK(!startup_metric_utils::GetPreReadOptions().use_prefetch_argument ||
-         process_type.empty() ||
+  DCHECK(process_type.empty() ||
          HasValidWindowsPrefetchArgument(*command_line));
 
   if (process_type == crash_reporter::switches::kCrashpadHandler) {
diff --git a/chrome/app/chrome_watcher_command_line_win.cc b/chrome/app/chrome_watcher_command_line_win.cc
index 6858de6e..493ff56d 100644
--- a/chrome/app/chrome_watcher_command_line_win.cc
+++ b/chrome/app/chrome_watcher_command_line_win.cc
@@ -15,7 +15,6 @@
 #include "base/strings/stringprintf.h"
 #include "base/win/win_util.h"
 #include "chrome/common/chrome_switches.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "content/public/common/content_switches.h"
 
 namespace {
@@ -157,8 +156,7 @@
   AppendHandleSwitch(kParentHandleSwitch, parent_process, &command_line);
 
 #if defined(OS_WIN)
-  if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument)
-    command_line.AppendArg(switches::kPrefetchArgumentWatcher);
+  command_line.AppendArg(switches::kPrefetchArgumentWatcher);
 #endif  // defined(OS_WIN)
 
   return command_line;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index d646194..faa2d14 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -2398,11 +2398,11 @@
   <message name="IDS_FLAGS_EXPERIMENTAL_ACCESSIBILITY_FEATURES_DESCRIPTION" desc="Description of the about:flag option for experimental accessibility features.">
     Enable additional accessibility features in the Settings page.
   </message>
-  <message name="IDS_FLAGS_ENABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_NAME" desc="Name of the about:flag option for enabling EnableSystemTimezoneAutomaticDetection policy.">
+  <message name="IDS_FLAGS_DISABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_NAME" desc="Name of the about:flag option for disabling EnableSystemTimezoneAutomaticDetection policy.">
     SystemTimezoneAutomaticDetection policy support
   </message>
-  <message name="IDS_FLAGS_ENABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_DESCRIPTION" desc="Description of the about:flag option for enabling EnableSystemTimezoneAutomaticDetection policy.">
-    Enable system timezone automatic detection device policy.
+  <message name="IDS_FLAGS_DISABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_DESCRIPTION" desc="Description of the about:flag option for disabling EnableSystemTimezoneAutomaticDetection policy.">
+    Disable system timezone automatic detection device policy.
   </message>
   <message name="IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_BUTTON_LABEL" desc="Label for the button opening display settings tab.">
     Display settings
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 110112c..3b447f4 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5755,6 +5755,12 @@
         Enable web pages to use experimental WebAssembly.
       </message>
       <if expr="is_android">
+        <message name="IDS_FLAGS_ENABLE_READ_IT_LATER_IN_MENU_NAME" desc="Title for the flag to use system download manager.">
+          Enable read it later in app menu.
+        </message>
+        <message name="IDS_FLAGS_ENABLE_READ_IT_LATER_IN_MENU_DESCRIPTION" desc="Description for the flag to show read it later in menu.">
+          Allow "read it later" to show in the menu, and users can select it to save the tab to Chrome in background.
+        </message>
         <message name="IDS_FLAGS_ENABLE_SYSTEM_DOWNLOAD_MANAGER_NAME" desc="Title for the flag to use system download manager.">
           Use system download manager when applicable.
         </message>
@@ -13600,6 +13606,10 @@
                    desc="Title text for the 'uninstall' context menu item of an app list item.">
             Uninstall...
           </message>
+          <message name="IDS_APP_LIST_REMOVE_SHORTCUT"
+                   desc="Title text for the 'remove' context menu item of an app list shortcut item.">
+            Remove
+          </message>
           <message name="IDS_APP_LIST_NEW_WINDOW" desc="The text label of the New Window menu item">
             New window
           </message>
@@ -13636,6 +13646,10 @@
                    desc="Title text for the 'uninstall' context menu item of an app list item.">
             Uninstall...
           </message>
+          <message name="IDS_APP_LIST_REMOVE_SHORTCUT"
+                   desc="Title text for the 'remove' context menu item of an app list shortcut item.">
+            Remove
+          </message>
           <message name="IDS_APP_LIST_NEW_WINDOW" desc="The text label of the New Window menu item">
             New Window
           </message>
@@ -14954,6 +14968,12 @@
       <message name="IDS_FLAGS_OFFLINING_RECENT_PAGES_DESCRIPTION" desc="Description for the flag to enable offlining of recently visited pages.">
         Enable storing recently visited pages locally for offline use. Requires Offline Pages to be enabled.
       </message>
+      <message name="IDS_FLAGS_OFFLINE_PAGES_CT_NAME" desc="Name for the flag to enable offlining CT features.">
+        Enable Offline Pages CT features.
+      </message>
+      <message name="IDS_FLAGS_OFFLINE_PAGES_CT_DESCRIPTION" desc="Description for the flag to enable offline pages CT features.">
+        Enable Offline Pages CT features.
+      </message>
     </if>
 
     <if expr="not is_android and not is_ios and _google_chrome">
@@ -15022,6 +15042,51 @@
         Enable VR shell if available for this device.
       </message>
     </if>
-    </messages>
-  </release>
+
+    <!-- PaymentRequest -->
+    <if expr="is_android">
+      <message name="IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_NAME" desc="Name of the flag to enable the first version of Android Pay integration">
+        Enable Android Pay v1
+      </message>
+      <message name="IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_DESCRIPTION" desc="Description for the flag to enable the first version of Android Pay integration">
+        Enable integration with Android Pay using the first version of the API
+      </message>
+    </if>
+
+   <!-- Safe Browsing Subresource Filter UI strings. -->
+    <if expr="use_titlecase">
+      <message name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_OK" desc="In Title Case: button which dismisses the Content blocked prompt without performing any actions.">
+        Got It
+      </message>
+    </if>
+    <if expr="not use_titlecase">
+      <message name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_OK" desc="Button which dismisses the Content blocked prompt without performing any actions.">
+        Got it
+      </message>
+    </if>
+    <if expr="use_titlecase">
+      <message name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_RELOAD" desc="In Title Case: Button which reloads the page in order to also show content that was previously blocked.">
+        Load Full Site
+      </message>
+    </if>
+    <if expr="not use_titlecase">
+      <message name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_RELOAD" desc="Button which reloads the page in order to also show content that was previously blocked.">
+        Load full site
+      </message>
+    </if>
+    <if expr="use_titlecase">
+      <message  name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_TITLE" desc="In Title Case: title of the prompt which is shown to inform the user when Chrome blocks some potentially deceptive content on the site. This happens as an additional layer of protection when users proceed through the Safe Browsing interstitial to view the site regardless.">
+        Content Blocked
+      </message>
+    </if>
+    <if expr="not use_titlecase">
+      <message  name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_TITLE" desc="Title of the prompt which is shown to inform the user when Chrome blocks some potentially deceptive content on the site. This happens as an additional layer of protection when users proceed through the Safe Browsing interstitial to view the site regardless.">
+        Content blocked
+      </message>
+    </if>
+    <message  name="IDS_FILTERED_DECEPTIVE_CONTENT_PROMPT_EXPLANATION" desc="Explanation text for the prompt which is shown to the user after clicking through Safe Browsing interstitial.">
+      Chrome has blocked parts of this site to protect you from potentially deceptive content.
+    </message>
+   </messages>
+ </release>
 </grit>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index e966ebd..f75d048 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -104,7 +104,7 @@
 #endif
 
 #if defined(USE_ASH)
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #endif
 
 #if defined(USE_OZONE)
@@ -795,6 +795,10 @@
          chromeos::switches::kDisableNetworkPortalNotification)},
 #endif
 #if defined(OS_ANDROID)
+    {"enable-read-it-later-in-menu",
+     IDS_FLAGS_ENABLE_READ_IT_LATER_IN_MENU_NAME,
+     IDS_FLAGS_ENABLE_READ_IT_LATER_IN_MENU_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kReadItLaterInMenu)},
     {"enable-system-download-manager",
      IDS_FLAGS_ENABLE_SYSTEM_DOWNLOAD_MANAGER_NAME,
      IDS_FLAGS_ENABLE_SYSTEM_DOWNLOAD_MANAGER_DESCRIPTION, kOsAndroid,
@@ -1826,6 +1830,9 @@
     {"offlining-recent-pages", IDS_FLAGS_OFFLINING_RECENT_PAGES_NAME,
      IDS_FLAGS_OFFLINING_RECENT_PAGES_DESCRIPTION, kOsAndroid,
      FEATURE_VALUE_TYPE(offline_pages::kOffliningRecentPagesFeature)},
+    {"offline-pages-ct", IDS_FLAGS_OFFLINE_PAGES_CT_NAME,
+     IDS_FLAGS_OFFLINE_PAGES_CT_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(offline_pages::kOfflinePagesCTFeature)},
 #endif  // defined(OS_ANDROID)
     {"protect-sync-credential", IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_NAME,
      IDS_FLAGS_PROTECT_SYNC_CREDENTIAL_DESCRIPTION, kOsAll,
@@ -1848,11 +1855,11 @@
     {"opt-in-ime-menu", IDS_FLAGS_ENABLE_IME_MENU_NAME,
      IDS_FLAGS_ENABLE_IME_MENU_DESCRIPTION, kOsCrOS,
      FEATURE_VALUE_TYPE(features::kOptInImeMenu)},
-    {"enable-system-timezone-automatic-detection",
-     IDS_FLAGS_ENABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_NAME,
-     IDS_FLAGS_ENABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_DESCRIPTION, kOsCrOS,
+    {"disable-system-timezone-automatic-detection",
+     IDS_FLAGS_DISABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_NAME,
+     IDS_FLAGS_DISABLE_SYSTEM_TIMEZONE_AUTOMATIC_DETECTION_DESCRIPTION, kOsCrOS,
      SINGLE_VALUE_TYPE(
-         chromeos::switches::kEnableSystemTimezoneAutomaticDetectionPolicy)},
+         chromeos::switches::kDisableSystemTimezoneAutomaticDetectionPolicy)},
     {"enable-native-cups",  // FLAGS:RECORD_UMA
      IDS_FLAGS_ENABLE_NATIVE_CUPS_NAME,
      IDS_FLAGS_ENABLE_NATIVE_CUPS_DESCRIPTION, kOsCrOS,
@@ -1908,12 +1915,16 @@
      IDS_FLAGS_ENABLE_VR_SHELL_DESCRIPTION, kOsAndroid,
      ENABLE_DISABLE_VALUE_TYPE(switches::kEnableVrShell,
                                switches::kDisableVrShell)},
+    {"enable-android-pay-integration-v1",
+     IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_NAME,
+     IDS_FLAGS_ENABLE_ANDROID_PAY_INTEGRATION_V1_DESCRIPTION, kOsAndroid,
+     FEATURE_VALUE_TYPE(chrome::android::kAndroidPayIntegrationV1)},
 #endif
-
     {"enable-weak-memorycache",
      IDS_FLAGS_ENABLE_WEAK_MEMORYCACHE_NAME,
      IDS_FLAGS_ENABLE_WEAK_MEMORYCACHE_DESCRIPTION, kOsAll,
      FEATURE_VALUE_TYPE(features::kWeakMemoryCache)},
+
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index 1f19b85d..a180a54 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -24,11 +24,12 @@
 namespace {
 
 // Array of features exposed through the Java ChromeFeatureList API. Entries in
-// this array may either refer to features defined in this file (above) or in
-// other locations in the code base (e.g. chrome/, components/, etc).
+// this array may either refer to features defined in the header of this file or
+// in other locations in the code base (e.g. chrome/, components/, etc).
 const base::Feature* kFeaturesExposedToJava[] = {
     &features::kCredentialManagementAPI,
     &features::kSimplifiedFullscreenUI,
+    &kAndroidPayIntegrationV1,
     &kImportantSitesInCBD,
     &kMediaStyleNotification,
     &kNTPFakeOmniboxTextFeature,
@@ -37,8 +38,10 @@
     &kNTPSnippetsFeature,
     &kNTPToolbarFeature,
     &kPhysicalWebFeature,
+    &kReadItLaterInMenu,
     &kSystemDownloadManager,
     &offline_pages::kOfflinePagesBackgroundLoadingFeature,
+    &offline_pages::kOfflinePagesCTFeature,  // See crbug.com/620421.
 };
 
 }  // namespace
@@ -69,10 +72,18 @@
   "NTPFakeOmniboxText", base::FEATURE_DISABLED_BY_DEFAULT
 };
 
+const base::Feature kAndroidPayIntegrationV1 {
+  "AndroidPayIntegrationV1", base::FEATURE_ENABLED_BY_DEFAULT
+};
+
 const base::Feature kPhysicalWebFeature {
   "PhysicalWeb", base::FEATURE_ENABLED_BY_DEFAULT
 };
 
+const base::Feature kReadItLaterInMenu {
+  "ReadItLaterInMenu", base::FEATURE_DISABLED_BY_DEFAULT
+};
+
 const base::Feature kSystemDownloadManager {
   "SystemDownloadManager", base::FEATURE_ENABLED_BY_DEFAULT
 };
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index a95cd502..bed0dc6c 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -12,6 +12,7 @@
 namespace chrome {
 namespace android {
 
+extern const base::Feature kAndroidPayIntegrationV1;
 extern const base::Feature kImportantSitesInCBD;
 extern const base::Feature kMediaStyleNotification;
 extern const base::Feature kNTPMaterialDesign;
@@ -20,6 +21,7 @@
 extern const base::Feature kNTPToolbarFeature;
 extern const base::Feature kNTPFakeOmniboxTextFeature;
 extern const base::Feature kPhysicalWebFeature;
+extern const base::Feature kReadItLaterInMenu;
 extern const base::Feature kSystemDownloadManager;
 
 bool RegisterChromeFeatureListJni(JNIEnv* env);
diff --git a/chrome/browser/android/offline_pages/background_scheduler_bridge.cc b/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
index 5b8fcba..4e4de65 100644
--- a/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
+++ b/chrome/browser/android/offline_pages/background_scheduler_bridge.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/android/offline_pages/request_coordinator_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
+#include "components/offline_pages/background/device_conditions.h"
 #include "components/offline_pages/background/request_coordinator.h"
 #include "jni/BackgroundSchedulerBridge_jni.h"
 
@@ -28,10 +29,12 @@
 }  // namespace
 
 // JNI call to start request processing.
-static jboolean StartProcessing(
-    JNIEnv* env,
-    const JavaParamRef<jclass>& jcaller,
-    const JavaParamRef<jobject>& j_callback_obj) {
+static jboolean StartProcessing(JNIEnv* env,
+                                const JavaParamRef<jclass>& jcaller,
+                                const jboolean j_power_connected,
+                                const jint j_battery_percentage,
+                                const jint j_net_connection_type,
+                                const JavaParamRef<jobject>& j_callback_obj) {
   ScopedJavaGlobalRef<jobject> j_callback_ref;
   j_callback_ref.Reset(env, j_callback_obj);
 
@@ -42,14 +45,12 @@
       RequestCoordinatorFactory::GetInstance()->
       GetForBrowserContext(profile);
   DVLOG(2) << "resource_coordinator: " << coordinator;
-  coordinator->StartProcessing(
-      base::Bind(&ProcessingDoneCallback, j_callback_ref));
-
-
-  base::Bind(&ProcessingDoneCallback, j_callback_ref);
-  // TODO(dougarnett): lookup/create RequestCoordinator KeyedService
-  // and call StartProcessing on it with bound j_callback_obj.
-  return false;
+  DeviceConditions device_conditions(
+      j_power_connected, j_battery_percentage,
+      static_cast<net::NetworkChangeNotifier::ConnectionType>(
+          j_net_connection_type));
+  return coordinator->StartProcessing(
+      device_conditions, base::Bind(&ProcessingDoneCallback, j_callback_ref));
 }
 
 void BackgroundSchedulerBridge::Schedule(
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper.cc b/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
index 9f1f868..f7a4ac72 100644
--- a/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
+++ b/chrome/browser/android/offline_pages/offline_page_tab_helper.cc
@@ -6,9 +6,12 @@
 
 #include "base/bind.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/android/offline_pages/offline_page_utils.h"
+#include "components/offline_pages/offline_page_model.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -53,6 +56,12 @@
   // operations.
   weak_ptr_factory_.InvalidateWeakPtrs();
 
+  // Since this is a new navigation, we will reset the cached offline page,
+  // unless we are currently looking at an offline page.
+  GURL navigated_url = navigation_handle->GetURL();
+  if (offline_page_ && navigated_url != offline_page_->GetOfflineURL())
+    offline_page_ = nullptr;
+
   // Ignore navigations that are forward or back transitions in the nav stack
   // which are not at the head of the stack.
   const content::NavigationController& controller =
@@ -64,16 +73,22 @@
   }
 
   content::BrowserContext* context = web_contents()->GetBrowserContext();
-  GURL navigated_url = navigation_handle->GetURL();
-  auto redirect_url_callback =
-      base::Bind(&OfflinePageTabHelper::GotRedirectURLForStartedNavigation,
-                 weak_ptr_factory_.GetWeakPtr(), navigated_url);
+  OfflinePageModel* offline_page_model =
+      OfflinePageModelFactory::GetForBrowserContext(context);
+  if (!offline_page_model)
+    return;
+
   if (net::NetworkChangeNotifier::IsOffline()) {
-    OfflinePageUtils::GetOfflineURLForOnlineURL(context, navigated_url,
-                                                redirect_url_callback);
+    offline_page_model->GetBestPageForOnlineURL(
+        navigated_url,
+        base::Bind(&OfflinePageTabHelper::TryRedirectToOffline,
+                   weak_ptr_factory_.GetWeakPtr(),
+                   RedirectReason::DISCONNECTED_NETWORK, navigated_url));
   } else {
-    OfflinePageUtils::GetOnlineURLForOfflineURL(context, navigated_url,
-                                                redirect_url_callback);
+    offline_page_model->GetPageByOfflineURL(
+        navigated_url,
+        base::Bind(&OfflinePageTabHelper::RedirectToOnline,
+                   weak_ptr_factory_.GetWeakPtr(), navigated_url));
   }
 }
 
@@ -110,41 +125,32 @@
     return;
   }
 
+  OfflinePageModel* offline_page_model =
+      OfflinePageModelFactory::GetForBrowserContext(browser_context);
+  if (!offline_page_model)
+    return;
+
   // Otherwise, get the offline URL for this url, and attempt a redirect if
   // necessary.
-  OfflinePageUtils::GetOfflineURLForOnlineURL(
-      browser_context, navigated_url,
-      base::Bind(&OfflinePageTabHelper::GotRedirectURLForSupportedErrorCode,
-                 weak_ptr_factory_.GetWeakPtr(),
-                 navigation_handle->GetPageTransition(), navigated_url));
+  RedirectReason reason =
+      navigation_handle->GetPageTransition() == ui::PAGE_TRANSITION_FORWARD_BACK
+          ? RedirectReason::FLAKY_NETWORK_FORWARD_BACK
+          : RedirectReason::FLAKY_NETWORK;
+  offline_page_model->GetBestPageForOnlineURL(
+      navigated_url,
+      base::Bind(&OfflinePageTabHelper::TryRedirectToOffline,
+                 weak_ptr_factory_.GetWeakPtr(), reason, navigated_url));
 }
 
-void OfflinePageTabHelper::GotRedirectURLForSupportedErrorCode(
-    ui::PageTransition transition,
-    const GURL& from_url,
-    const GURL& redirect_url) {
-  // If we didn't find an offline URL, or we are doing a forward/back
-  // transition, don't redirect.
-  bool do_redirect =
-      redirect_url.is_valid() && transition != ui::PAGE_TRANSITION_FORWARD_BACK;
-  UMA_HISTOGRAM_BOOLEAN("OfflinePages.ShowOfflinePageOnBadNetwork",
-                        do_redirect);
-  if (!do_redirect)
-    return;
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&OfflinePageTabHelper::Redirect,
-                 weak_ptr_factory_.GetWeakPtr(), from_url, redirect_url));
-}
-
-void OfflinePageTabHelper::GotRedirectURLForStartedNavigation(
-    const GURL& from_url,
-    const GURL& redirect_url) {
+void OfflinePageTabHelper::RedirectToOnline(
+    const GURL& navigated_url,
+    const OfflinePageItem* offline_page) {
   // Bails out if no redirection is needed.
-  if (!redirect_url.is_valid())
+  if (!offline_page)
     return;
 
+  GURL redirect_url = offline_page->url;
+
   const content::NavigationController& controller =
       web_contents()->GetController();
 
@@ -155,20 +161,50 @@
     return;
   }
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&OfflinePageTabHelper::Redirect,
-                 weak_ptr_factory_.GetWeakPtr(), from_url, redirect_url));
+  Redirect(navigated_url, redirect_url);
+  // Clear the offline page since we are redirecting to online.
+  offline_page_ = nullptr;
+
+  UMA_HISTOGRAM_COUNTS("OfflinePages.RedirectToOnlineCount", 1);
 }
 
-void OfflinePageTabHelper::Redirect(
-    const GURL& from_url, const GURL& to_url) {
-  if (to_url.SchemeIsFile()) {
-    UMA_HISTOGRAM_COUNTS("OfflinePages.RedirectToOfflineCount", 1);
+void OfflinePageTabHelper::TryRedirectToOffline(
+    RedirectReason redirect_reason,
+    const GURL& from_url,
+    const OfflinePageItem* offline_page) {
+  if (!offline_page)
+    return;
+
+  GURL redirect_url = offline_page->GetOfflineURL();
+
+  if (!redirect_url.is_valid())
+    return;
+
+  if (redirect_reason == RedirectReason::FLAKY_NETWORK ||
+      redirect_reason == RedirectReason::FLAKY_NETWORK_FORWARD_BACK) {
+    UMA_HISTOGRAM_BOOLEAN("OfflinePages.ShowOfflinePageOnBadNetwork",
+                          redirect_reason == RedirectReason::FLAKY_NETWORK);
+    // Don't actually want to redirect on a forward/back nav.
+    if (redirect_reason == RedirectReason::FLAKY_NETWORK_FORWARD_BACK)
+      return;
   } else {
-    UMA_HISTOGRAM_COUNTS("OfflinePages.RedirectToOnlineCount", 1);
+    const content::NavigationController& controller =
+        web_contents()->GetController();
+
+    // Avoids looping between online and offline redirections.
+    content::NavigationEntry* entry = controller.GetPendingEntry();
+    if (entry && !entry->GetRedirectChain().empty() &&
+        entry->GetRedirectChain().back() == redirect_url) {
+      return;
+    }
   }
 
+  Redirect(from_url, redirect_url);
+  offline_page_ = base::MakeUnique<OfflinePageItem>(*offline_page);
+  UMA_HISTOGRAM_COUNTS("OfflinePages.RedirectToOfflineCount", 1);
+}
+
+void OfflinePageTabHelper::Redirect(const GURL& from_url, const GURL& to_url) {
   content::NavigationController::LoadURLParams load_params(to_url);
   load_params.transition_type = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
   load_params.redirect_chain.push_back(from_url);
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper.h b/chrome/browser/android/offline_pages/offline_page_tab_helper.h
index b635051..7e3d35d 100644
--- a/chrome/browser/android/offline_pages/offline_page_tab_helper.h
+++ b/chrome/browser/android/offline_pages/offline_page_tab_helper.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/offline_pages/offline_page_types.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "url/gurl.h"
@@ -17,6 +18,8 @@
 
 namespace offline_pages {
 
+struct OfflinePageItem;
+
 // Per-tab class to manage switch between online version and offline version.
 class OfflinePageTabHelper :
     public content::WebContentsObserver,
@@ -24,7 +27,15 @@
  public:
   ~OfflinePageTabHelper() override;
 
+  const OfflinePageItem* offline_page() { return offline_page_.get(); }
+
  private:
+  enum class RedirectReason {
+    DISCONNECTED_NETWORK,
+    FLAKY_NETWORK,
+    FLAKY_NETWORK_FORWARD_BACK
+  };
+
   friend class content::WebContentsUserData<OfflinePageTabHelper>;
   friend class OfflinePageTabHelperTest;
   FRIEND_TEST_ALL_PREFIXES(OfflinePageTabHelperTest,
@@ -38,14 +49,18 @@
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
 
-  void GotRedirectURLForSupportedErrorCode(ui::PageTransition transition,
-                                           const GURL& from_url,
-                                           const GURL& redirect_url);
-  void GotRedirectURLForStartedNavigation(const GURL& from_url,
-                                          const GURL& redirect_url);
+  void RedirectToOnline(const GURL& from_url,
+                        const OfflinePageItem* offline_page);
+  void TryRedirectToOffline(RedirectReason redirect_reason,
+                            const GURL& from_url,
+                            const OfflinePageItem* offline_page);
 
   void Redirect(const GURL& from_url, const GURL& to_url);
 
+  // Iff the tab we are associated with is redirected to an offline page,
+  // |offline_page_| will be non-null.  This can be used to synchronously ask
+  // about the offline state of the current web contents.
+  std::unique_ptr<OfflinePageItem> offline_page_;
   base::WeakPtrFactory<OfflinePageTabHelper> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(OfflinePageTabHelper);
diff --git a/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc b/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
index 152a0c1..30e3eb8 100644
--- a/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
+++ b/chrome/browser/android/offline_pages/offline_page_tab_helper_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
+#include "chrome/browser/android/offline_pages/offline_page_utils.h"
 #include "chrome/browser/android/offline_pages/test_offline_page_model_builder.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "components/offline_pages/client_namespace_constants.h"
@@ -80,8 +81,8 @@
     return offline_page_tab_helper_;
   }
 
-  const GURL& online_url() const { return online_url_; }
-  const GURL& offline_url() const { return offline_url_; }
+  const GURL& online_url() const { return offline_page_item_->url; }
+  GURL offline_url() const { return offline_page_item_->GetOfflineURL(); }
 
   const base::HistogramTester& histograms() const { return histogram_tester_; }
 
@@ -98,8 +99,7 @@
   std::unique_ptr<TestNetworkChangeNotifier> network_change_notifier_;
   OfflinePageTabHelper* offline_page_tab_helper_;  // Not owned.
 
-  GURL online_url_;
-  GURL offline_url_;
+  std::unique_ptr<OfflinePageItem> offline_page_item_;
 
   base::HistogramTester histogram_tester_;
 
@@ -193,8 +193,7 @@
 void OfflinePageTabHelperTest::OnGetPageByOfflineIdDone(
     const OfflinePageItem* result) {
   DCHECK(result);
-  online_url_ = result->url;
-  offline_url_ = result->GetOfflineURL();
+  offline_page_item_.reset(new OfflinePageItem(*result));
 }
 
 TEST_F(OfflinePageTabHelperTest, SwitchToOnlineFromOfflineOnNetwork) {
@@ -223,6 +222,25 @@
   histograms().ExpectTotalCount(kRedirectToOnlineHistogram, 0);
 }
 
+TEST_F(OfflinePageTabHelperTest, TestCurrentOfflinePage) {
+  SimulateHasNetworkConnectivity(false);
+
+  StartLoad(online_url());
+  // Gives a chance to run delayed task to do redirection.
+  RunUntilIdle();
+
+  const OfflinePageItem* item =
+      OfflinePageUtils::GetOfflinePageFromWebContents(web_contents());
+  EXPECT_EQ(offline_url(), item->GetOfflineURL());
+  EXPECT_EQ(online_url(), item->url);
+
+  SimulateHasNetworkConnectivity(true);
+  StartLoad(offline_url());
+  RunUntilIdle();
+  item = OfflinePageUtils::GetOfflinePageFromWebContents(web_contents());
+  EXPECT_EQ(nullptr, item);
+}
+
 TEST_F(OfflinePageTabHelperTest, SwitchToOfflineFromOnlineOnError) {
   SimulateHasNetworkConnectivity(true);
 
diff --git a/chrome/browser/android/offline_pages/offline_page_utils.cc b/chrome/browser/android/offline_pages/offline_page_utils.cc
index a7635af..82f5ff7 100644
--- a/chrome/browser/android/offline_pages/offline_page_utils.cc
+++ b/chrome/browser/android/offline_pages/offline_page_utils.cc
@@ -12,10 +12,12 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
+#include "chrome/browser/android/offline_pages/offline_page_tab_helper.h"
 #include "components/offline_pages/offline_page_feature.h"
 #include "components/offline_pages/offline_page_item.h"
 #include "components/offline_pages/offline_page_model.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/web_contents.h"
 #include "url/gurl.h"
 
 namespace offline_pages {
@@ -167,4 +169,11 @@
   offline_page_model->MarkPageAccessed(offline_page->offline_id);
 }
 
+const OfflinePageItem* OfflinePageUtils::GetOfflinePageFromWebContents(
+    content::WebContents* web_contents) {
+  OfflinePageTabHelper* tab_helper =
+      OfflinePageTabHelper::FromWebContents(web_contents);
+  return tab_helper ? tab_helper->offline_page() : nullptr;
+}
+
 }  // namespace offline_pages
diff --git a/chrome/browser/android/offline_pages/offline_page_utils.h b/chrome/browser/android/offline_pages/offline_page_utils.h
index bdda54ae7..a09715d8 100644
--- a/chrome/browser/android/offline_pages/offline_page_utils.h
+++ b/chrome/browser/android/offline_pages/offline_page_utils.h
@@ -13,6 +13,7 @@
 
 namespace content {
 class BrowserContext;
+class WebContents;
 }
 
 namespace offline_pages {
@@ -53,6 +54,12 @@
   // Marks that the offline page related to the |offline_url| has been accessed.
   static void MarkPageAccessed(content::BrowserContext* browser_context,
                                const GURL& offline_url);
+
+  // Gets the offline page corresponding to the given web contents.  The
+  // returned pointer is owned by the web_contents and may be deleted by user
+  // navigation, so it is unsafe to store a copy of the returned pointer.
+  static const OfflinePageItem* GetOfflinePageFromWebContents(
+      content::WebContents* web_contents);
 };
 
 }  // namespace offline_pages
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
index cd552dc..06d33da 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -177,7 +177,6 @@
     const JavaParamRef<jobject>& obj,
     const JavaParamRef<jstring>& j_omnibox_text,
     const JavaParamRef<jstring>& j_current_url,
-    jboolean is_query_in_omnibox,
     jboolean focused_from_fakebox) {
   if (!autocomplete_controller_)
     return;
@@ -193,7 +192,7 @@
 
   input_ = AutocompleteInput(
       omnibox_text, base::string16::npos, std::string(), current_url,
-      ClassifyPage(current_url, is_query_in_omnibox, focused_from_fakebox),
+      ClassifyPage(current_url, focused_from_fakebox),
       false, false, true, true, true,
       ChromeAutocompleteSchemeClassifier(profile_));
   autocomplete_controller_->Start(input_);
@@ -218,7 +217,6 @@
     const JavaParamRef<jobject>& obj,
     jint selected_index,
     const JavaParamRef<jstring>& j_current_url,
-    jboolean is_query_in_omnibox,
     jboolean focused_from_fakebox,
     jlong elapsed_time_since_first_modified,
     jint completed_length,
@@ -226,7 +224,7 @@
   base::string16 url = ConvertJavaStringToUTF16(env, j_current_url);
   const GURL current_url = GURL(url);
   OmniboxEventProto::PageClassification current_page_classification =
-      ClassifyPage(current_url, is_query_in_omnibox, focused_from_fakebox);
+      ClassifyPage(current_url, focused_from_fakebox);
   const base::TimeTicks& now(base::TimeTicks::Now());
   content::WebContents* web_contents =
       content::WebContents::FromJavaWebContents(j_web_contents);
@@ -408,7 +406,6 @@
 
 OmniboxEventProto::PageClassification
 AutocompleteControllerAndroid::ClassifyPage(const GURL& gurl,
-                                            bool is_query_in_omnibox,
                                             bool focused_from_fakebox) const {
   if (!gurl.is_valid())
     return OmniboxEventProto::INVALID_SPEC;
@@ -432,9 +429,6 @@
   if (url == profile_->GetPrefs()->GetString(prefs::kHomePage))
     return OmniboxEventProto::HOME_PAGE;
 
-  if (is_query_in_omnibox)
-    return OmniboxEventProto::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT;
-
   bool is_search_url = TemplateURLServiceFactory::GetForProfile(profile_)->
       IsSearchResultsPageFromDefaultSearchProvider(gurl);
   if (is_search_url)
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.h b/chrome/browser/android/omnibox/autocomplete_controller_android.h
index e8bd5c6..c8c3c24 100644
--- a/chrome/browser/android/omnibox/autocomplete_controller_android.h
+++ b/chrome/browser/android/omnibox/autocomplete_controller_android.h
@@ -52,7 +52,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       const base::android::JavaParamRef<jstring>& j_omnibox_text,
       const base::android::JavaParamRef<jstring>& j_current_url,
-      jboolean is_query_in_omnibox,
       jboolean focused_from_fakebox);
   void Stop(JNIEnv* env,
             const base::android::JavaParamRef<jobject>& obj,
@@ -64,7 +63,6 @@
       const base::android::JavaParamRef<jobject>& obj,
       jint selected_index,
       const base::android::JavaParamRef<jstring>& j_current_url,
-      jboolean is_query_in_omnibox,
       jboolean focused_from_fakebox,
       jlong elapsed_time_since_first_modified,
       jint completed_length,
@@ -120,7 +118,6 @@
   // Classifies the type of page we are on.
   metrics::OmniboxEventProto::PageClassification ClassifyPage(
       const GURL& gurl,
-      bool is_query_in_omnibox,
       bool focused_from_fakebox) const;
 
   base::android::ScopedJavaLocalRef<jobject> BuildOmniboxSuggestion(
diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h
index dc5e290..ee4b615 100644
--- a/chrome/browser/browser_process.h
+++ b/chrome/browser/browser_process.h
@@ -46,6 +46,10 @@
 class SafeBrowsingService;
 }
 
+namespace subresource_filter {
+class RulesetService;
+}
+
 namespace variations {
 class VariationsService;
 }
@@ -222,6 +226,11 @@
   virtual safe_browsing::ClientSideDetectionService*
       safe_browsing_detection_service() = 0;
 
+  // Returns the service providing versioned storage for rules used by the Safe
+  // Browsing subresource filter.
+  virtual subresource_filter::RulesetService*
+  subresource_filter_ruleset_service() = 0;
+
 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
   // This will start a timer that, if Chrome is in persistent mode, will check
   // whether an update is available, and if that's the case, restart the
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 48e6dd0..ff4ac047 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -98,6 +98,8 @@
 #include "components/prefs/pref_service.h"
 #include "components/safe_json/safe_json_parser.h"
 #include "components/signin/core/common/profile_management_switches.h"
+#include "components/subresource_filter/core/browser/ruleset_service.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
 #include "components/translate/core/browser/translate_download_manager.h"
 #include "components/update_client/update_query_params.h"
 #include "components/web_resource/web_resource_pref_names.h"
@@ -119,7 +121,6 @@
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "ui/views/focus/view_storage.h"
 #elif defined(OS_MACOSX)
 #include "chrome/browser/chrome_browser_main_mac.h"
@@ -195,6 +196,7 @@
       created_notification_ui_manager_(false),
       created_notification_bridge_(false),
       created_safe_browsing_service_(false),
+      created_subresource_filter_ruleset_service_(false),
       shutting_down_(false),
       tearing_down_(false),
       download_status_updater_(new DownloadStatusUpdater),
@@ -856,6 +858,14 @@
   return NULL;
 }
 
+subresource_filter::RulesetService*
+BrowserProcessImpl::subresource_filter_ruleset_service() {
+  DCHECK(CalledOnValidThread());
+  if (!created_subresource_filter_ruleset_service_)
+    CreateSubresourceFilterRulesetService();
+  return subresource_filter_ruleset_service_.get();
+}
+
 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
 void BrowserProcessImpl::StartAutoupdateTimer() {
   autoupdate_timer_.Start(FROM_HERE,
@@ -1127,6 +1137,25 @@
   safe_browsing_service_->Initialize();
 }
 
+void BrowserProcessImpl::CreateSubresourceFilterRulesetService() {
+  DCHECK(!subresource_filter_ruleset_service_);
+  created_subresource_filter_ruleset_service_ = true;
+
+  base::SequencedWorkerPool* blocking_pool =
+      content::BrowserThread::GetBlockingPool();
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner(
+      blocking_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+          blocking_pool->GetSequenceToken(),
+          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+
+  base::FilePath user_data_dir;
+  PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  subresource_filter_ruleset_service_.reset(
+      new subresource_filter::RulesetService(
+          local_state(), blocking_task_runner,
+          user_data_dir.Append(subresource_filter::kRulesetBaseDirectoryName)));
+}
+
 void BrowserProcessImpl::CreateGCMDriver() {
   DCHECK(!gcm_driver_);
 
@@ -1288,8 +1317,7 @@
   }
 
 #if defined(OS_WIN)
-  if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument)
-    new_cl->AppendArg(switches::kPrefetchArgumentBrowserBackground);
+  new_cl->AppendArg(switches::kPrefetchArgumentBrowserBackground);
 #endif  // defined(OS_WIN)
 
   DLOG(WARNING) << "Shutting down current instance of the browser.";
diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h
index d0c8b094..3004564 100644
--- a/chrome/browser/browser_process_impl.h
+++ b/chrome/browser/browser_process_impl.h
@@ -129,6 +129,8 @@
   safe_browsing::SafeBrowsingService* safe_browsing_service() override;
   safe_browsing::ClientSideDetectionService* safe_browsing_detection_service()
       override;
+  subresource_filter::RulesetService* subresource_filter_ruleset_service()
+      override;
 
 #if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
   void StartAutoupdateTimer() override;
@@ -172,6 +174,7 @@
   void CreateBackgroundPrintingManager();
   void CreateSafeBrowsingService();
   void CreateSafeBrowsingDetectionService();
+  void CreateSubresourceFilterRulesetService();
   void CreateStatusTray();
   void CreateBackgroundModeManager();
   void CreateGCMDriver();
@@ -253,6 +256,10 @@
   bool created_safe_browsing_service_;
   scoped_refptr<safe_browsing::SafeBrowsingService> safe_browsing_service_;
 
+  bool created_subresource_filter_ruleset_service_;
+  std::unique_ptr<subresource_filter::RulesetService>
+      subresource_filter_ruleset_service_;
+
   bool shutting_down_;
 
   bool tearing_down_;
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index c91dcb8..f10ed1c 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -183,6 +183,7 @@
         <include name="IDR_OFFLINE_INTERNALS_HTML" file="resources\offline_pages\offline_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
         <include name="IDR_OFFLINE_INTERNALS_CSS" file="resources\offline_pages\offline_internals.css" type="BINDATA" />
         <include name="IDR_OFFLINE_INTERNALS_JS" file="resources\offline_pages\offline_internals.js" type="BINDATA" />
+        <include name="IDR_OFFLINE_INTERNALS_BROWSER_PROXY_JS" file="resources\offline_pages\offline_internals_browser_proxy.js" type="BINDATA" />
         <include name="IDR_POPULAR_SITES_INTERNALS_HTML" file="resources\popular_sites_internals.html" allowexternalscript="true" compress="gzip" type="BINDATA" />
         <include name="IDR_POPULAR_SITES_INTERNALS_CSS" file="resources\popular_sites_internals.css" compress="gzip" type="BINDATA" />
         <include name="IDR_POPULAR_SITES_INTERNALS_JS" file="resources\popular_sites_internals.js" compress="gzip" type="BINDATA" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 192cb11..f788b6f 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -181,7 +181,6 @@
 #include "base/strings/string_tokenizer.h"
 #include "base/win/windows_version.h"
 #include "chrome/browser/chrome_browser_main_win.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "sandbox/win/src/sandbox_policy.h"
 #elif defined(OS_MACOSX)
 #include "chrome/browser/chrome_browser_main_mac.h"
@@ -2716,10 +2715,6 @@
 
   return false;
 }
-
-bool ChromeContentBrowserClient::ShouldUseWindowsPrefetchArgument() const {
-  return startup_metric_utils::GetPreReadOptions().use_prefetch_argument;
-}
 #endif  // defined(OS_WIN)
 
 void ChromeContentBrowserClient::RegisterRenderProcessMojoServices(
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index 7a835bbf..030b92df 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -271,7 +271,6 @@
       int sandbox_type) const override;
   bool IsWin32kLockdownEnabledForMimeType(
       const std::string& mime_type) const override;
-  bool ShouldUseWindowsPrefetchArgument() const override;
 #endif
   void RegisterRenderProcessMojoServices(
       content::ServiceRegistry* registry,
diff --git a/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.cc
index c0892bdb..bc163f1 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.cc
@@ -34,14 +34,6 @@
 }  // namespace
 
 AccessibilityHighlightManager::AccessibilityHighlightManager() {
-  ash::Shell* shell = ash::Shell::GetInstance();
-  shell->AddPreTargetHandler(this);
-  shell->cursor_manager()->AddObserver(this);
-  registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
-                 content::NotificationService::AllSources());
-  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
-  ui::InputMethod* input_method = GetInputMethod(root_window);
-  input_method->AddObserver(this);
   focus_rect_ = OffscreenRect();
   cursor_point_ = OffscreenPoint();
   caret_point_ = OffscreenPoint();
@@ -52,19 +44,19 @@
   if (!ash::Shell::HasInstance())
     return;
 
+  AccessibilityFocusRingController::GetInstance()->SetFocusRing(
+      std::vector<gfx::Rect>(),
+      AccessibilityFocusRingController::FADE_OUT_FOCUS_RING);
+  AccessibilityFocusRingController::GetInstance()->SetCaretRing(
+      OffscreenPoint());
+  AccessibilityFocusRingController::GetInstance()->SetCursorRing(
+      OffscreenPoint());
+
   ash::Shell* shell = ash::Shell::GetInstance();
-  if (shell) {
+  if (shell && registered_observers_) {
     shell->RemovePreTargetHandler(this);
     shell->cursor_manager()->RemoveObserver(this);
 
-    AccessibilityFocusRingController::GetInstance()->SetFocusRing(
-        std::vector<gfx::Rect>(),
-        AccessibilityFocusRingController::FADE_OUT_FOCUS_RING);
-    AccessibilityFocusRingController::GetInstance()->SetCaretRing(
-        OffscreenPoint());
-    AccessibilityFocusRingController::GetInstance()->SetCursorRing(
-        OffscreenPoint());
-
     aura::Window* root_window = shell->GetPrimaryRootWindow();
     ui::InputMethod* input_method = GetInputMethod(root_window);
     input_method->RemoveObserver(this);
@@ -86,6 +78,18 @@
   UpdateFocusAndCaretHighlights();
 }
 
+void AccessibilityHighlightManager::RegisterObservers() {
+  ash::Shell* shell = ash::Shell::GetInstance();
+  shell->AddPreTargetHandler(this);
+  shell->cursor_manager()->AddObserver(this);
+  registrar_.Add(this, content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
+                 content::NotificationService::AllSources());
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
+  ui::InputMethod* input_method = GetInputMethod(root_window);
+  input_method->AddObserver(this);
+  registered_observers_ = true;
+}
+
 void AccessibilityHighlightManager::OnMouseEvent(ui::MouseEvent* event) {
   if (event->type() == ui::ET_MOUSE_MOVED) {
     cursor_point_ = event->root_location();
@@ -130,6 +134,10 @@
   UpdateCursorHighlight();
 }
 
+bool AccessibilityHighlightManager::IsCursorVisible() {
+  return ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible();
+}
+
 void AccessibilityHighlightManager::UpdateFocusAndCaretHighlights() {
   auto controller = AccessibilityFocusRingController::GetInstance();
 
@@ -161,7 +169,7 @@
   if (!cursor_)
     point = OffscreenPoint();
 
-  if (!ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible())
+  if (!IsCursorVisible())
     point = OffscreenPoint();
 
   AccessibilityFocusRingController::GetInstance()->SetCursorRing(point);
diff --git a/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h b/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h
index 72ad086..89c5324b 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h
@@ -33,7 +33,9 @@
   void HighlightCursor(bool cursor);
   void HighlightCaret(bool caret);
 
- private:
+  void RegisterObservers();
+
+ protected:
   // ui::EventHandler overrides:
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnKeyEvent(ui::KeyEvent* event) override;
@@ -55,6 +57,9 @@
   // aura::client::CursorClientObserver
   void OnCursorVisibilityChanged(bool is_visible) override;
 
+  virtual bool IsCursorVisible();
+
+ private:
   void UpdateFocusAndCaretHighlights();
   void UpdateCursorHighlight();
 
@@ -68,6 +73,7 @@
   bool caret_visible_ = false;
   gfx::Point caret_point_;
 
+  bool registered_observers_ = false;
   content::NotificationRegistrar registrar_;
 
   DISALLOW_COPY_AND_ASSIGN(AccessibilityHighlightManager);
diff --git a/chrome/browser/chromeos/accessibility/accessibility_highlight_manager_browsertest.cc b/chrome/browser/chromeos/accessibility/accessibility_highlight_manager_browsertest.cc
new file mode 100644
index 0000000..6af77cd
--- /dev/null
+++ b/chrome/browser/chromeos/accessibility/accessibility_highlight_manager_browsertest.cc
@@ -0,0 +1,221 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h"
+
+#include "ash/shell.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/chromeos_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/focused_node_details.h"
+#include "content/public/browser/notification_types.h"
+#include "ui/aura/window.h"
+#include "ui/base/ime/dummy_text_input_client.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/text_input_client.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/events/event_utils.h"
+#include "ui/gfx/image/image.h"
+#include "ui/snapshot/snapshot.h"
+
+namespace chromeos {
+namespace {
+
+class MockTextInputClient : public ui::DummyTextInputClient {
+ public:
+  MockTextInputClient() : ui::DummyTextInputClient(ui::TEXT_INPUT_TYPE_TEXT) {}
+
+  void SetCaretBounds(const gfx::Rect& bounds) { caret_bounds_ = bounds; }
+
+ private:
+  gfx::Rect GetCaretBounds() const override { return caret_bounds_; }
+
+  gfx::Rect caret_bounds_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockTextInputClient);
+};
+
+class TestAccessibilityHighlightManager : public AccessibilityHighlightManager {
+ public:
+  TestAccessibilityHighlightManager() {}
+
+  void OnCaretBoundsChanged(const ui::TextInputClient* client) override {
+    AccessibilityHighlightManager::OnCaretBoundsChanged(client);
+  }
+  void OnMouseEvent(ui::MouseEvent* event) override {
+    AccessibilityHighlightManager::OnMouseEvent(event);
+  }
+  void Observe(int type,
+               const content::NotificationSource& source,
+               const content::NotificationDetails& details) override {
+    AccessibilityHighlightManager::Observe(type, source, details);
+  }
+
+ private:
+  bool IsCursorVisible() override { return true; }
+
+  DISALLOW_COPY_AND_ASSIGN(TestAccessibilityHighlightManager);
+};
+
+}  // namespace
+
+class AccessibilityHighlightManagerTest : public InProcessBrowserTest {
+ protected:
+  AccessibilityHighlightManagerTest() {}
+  ~AccessibilityHighlightManagerTest() override {}
+
+  void SetUp() override {
+    AccessibilityFocusRingController::GetInstance()->SetNoFadeForTesting();
+    InProcessBrowserTest::SetUp();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(::switches::kEnablePixelOutputInTests);
+  }
+
+  void CaptureBeforeImage(const gfx::Rect& bounds) {
+    Capture(bounds);
+    image_.AsBitmap().deepCopyTo(&before_bmp_);
+  }
+
+  void CaptureAfterImage(const gfx::Rect& bounds) {
+    Capture(bounds);
+    image_.AsBitmap().deepCopyTo(&after_bmp_);
+  }
+
+  void ComputeImageStats() {
+    diff_count_ = 0;
+    double accum[4] = {0, 0, 0, 0};
+    SkAutoLockPixels lock_before(before_bmp_);
+    SkAutoLockPixels lock_after(after_bmp_);
+    for (int x = 0; x < before_bmp_.width(); ++x) {
+      for (int y = 0; y < before_bmp_.height(); ++y) {
+        SkColor before_color = before_bmp_.getColor(x, y);
+        SkColor after_color = after_bmp_.getColor(x, y);
+        if (before_color != after_color) {
+          diff_count_++;
+          accum[0] += SkColorGetB(after_color);
+          accum[1] += SkColorGetG(after_color);
+          accum[2] += SkColorGetR(after_color);
+          accum[3] += SkColorGetA(after_color);
+        }
+      }
+    }
+    average_diff_color_ =
+        SkColorSetARGB(static_cast<unsigned char>(accum[3] / diff_count_),
+                       static_cast<unsigned char>(accum[2] / diff_count_),
+                       static_cast<unsigned char>(accum[1] / diff_count_),
+                       static_cast<unsigned char>(accum[0] / diff_count_));
+  }
+
+  int diff_count() { return diff_count_; }
+  SkColor average_diff_color() { return average_diff_color_; }
+
+ private:
+  void GotSnapshot(const gfx::Image& image) {
+    image_ = image;
+    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
+                                     run_loop_quitter_);
+  }
+
+  void Capture(const gfx::Rect& bounds) {
+    aura::Window* window = ash::Shell::GetPrimaryRootWindow();
+    ui::GrabWindowSnapshotAndScaleAsync(
+        window, bounds, bounds.size(),
+        content::BrowserThread::GetBlockingPool(),
+        base::Bind(&AccessibilityHighlightManagerTest::GotSnapshot, this));
+    base::RunLoop run_loop;
+    run_loop_quitter_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+  base::Closure run_loop_quitter_;
+  gfx::Image image_;
+  SkBitmap before_bmp_;
+  SkBitmap after_bmp_;
+  int diff_count_;
+  SkColor average_diff_color_;
+
+  DISALLOW_COPY_AND_ASSIGN(AccessibilityHighlightManagerTest);
+};
+
+IN_PROC_BROWSER_TEST_F(AccessibilityHighlightManagerTest,
+                       TestCaretRingDrawsBluePixels) {
+  gfx::Rect capture_bounds(200, 300, 100, 100);
+  gfx::Rect caret_bounds(230, 330, 1, 25);
+
+  CaptureBeforeImage(capture_bounds);
+
+  TestAccessibilityHighlightManager manager;
+  manager.HighlightCaret(true);
+  MockTextInputClient text_input_client;
+  text_input_client.SetCaretBounds(caret_bounds);
+  manager.OnCaretBoundsChanged(&text_input_client);
+
+  CaptureAfterImage(capture_bounds);
+  ComputeImageStats();
+
+  // This is a smoke test to assert that something is drawn in the right
+  // part of the screen of approximately the right size and color.
+  // There's deliberately some tolerance for tiny errors.
+  EXPECT_NEAR(1487, diff_count(), 50);
+  EXPECT_NEAR(175, SkColorGetR(average_diff_color()), 5);
+  EXPECT_NEAR(175, SkColorGetG(average_diff_color()), 5);
+  EXPECT_NEAR(255, SkColorGetB(average_diff_color()), 5);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityHighlightManagerTest,
+                       TestCursorRingDrawsRedPixels) {
+  gfx::Rect capture_bounds(200, 300, 100, 100);
+  gfx::Point cursor_point(250, 350);
+
+  CaptureBeforeImage(capture_bounds);
+
+  TestAccessibilityHighlightManager manager;
+  manager.HighlightCursor(true);
+  ui::MouseEvent mouse_move(ui::ET_MOUSE_MOVED, cursor_point, cursor_point,
+                            ui::EventTimeForNow(), 0, 0);
+  manager.OnMouseEvent(&mouse_move);
+  CaptureAfterImage(capture_bounds);
+  ComputeImageStats();
+
+  // This is a smoke test to assert that something is drawn in the right
+  // part of the screen of approximately the right size and color.
+  // There's deliberately some tolerance for tiny errors.
+  EXPECT_NEAR(1521, diff_count(), 50);
+  EXPECT_NEAR(255, SkColorGetR(average_diff_color()), 5);
+  EXPECT_NEAR(176, SkColorGetG(average_diff_color()), 5);
+  EXPECT_NEAR(176, SkColorGetB(average_diff_color()), 5);
+}
+
+IN_PROC_BROWSER_TEST_F(AccessibilityHighlightManagerTest,
+                       TestFocusRingDrawsOrangePixels) {
+  gfx::Rect capture_bounds(200, 300, 100, 100);
+  gfx::Rect focus_bounds(230, 330, 40, 40);
+
+  CaptureBeforeImage(capture_bounds);
+
+  TestAccessibilityHighlightManager manager;
+  manager.HighlightFocus(true);
+  content::FocusedNodeDetails details{false, focus_bounds};
+  manager.Observe(content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE,
+                  content::Source<AccessibilityHighlightManagerTest>(this),
+                  content::Details<content::FocusedNodeDetails>(&details));
+  CaptureAfterImage(capture_bounds);
+  ComputeImageStats();
+
+  // This is a smoke test to assert that something is drawn in the right
+  // part of the screen of approximately the right size and color.
+  // There's deliberately some tolerance for tiny errors.
+  EXPECT_NEAR(1608, diff_count(), 50);
+  EXPECT_NEAR(255, SkColorGetR(average_diff_color()), 5);
+  EXPECT_NEAR(201, SkColorGetG(average_diff_color()), 5);
+  EXPECT_NEAR(152, SkColorGetB(average_diff_color()), 5);
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index f9d5281..7af0b09 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -1095,8 +1095,10 @@
     return;
   }
 
-  if (!accessibility_highlight_manager_)
+  if (!accessibility_highlight_manager_) {
     accessibility_highlight_manager_.reset(new AccessibilityHighlightManager());
+    accessibility_highlight_manager_->RegisterObservers();
+  }
 
   accessibility_highlight_manager_->HighlightFocus(focus_highlight_enabled_);
   accessibility_highlight_manager_->HighlightCaret(caret_highlight_enabled_);
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index 27bb8b4..edd09d6 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -10,7 +10,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/callback.h"
diff --git a/chrome/browser/chromeos/extensions/gfx_utils.cc b/chrome/browser/chromeos/extensions/gfx_utils.cc
new file mode 100644
index 0000000..fc69b1f
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/gfx_utils.cc
@@ -0,0 +1,64 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/extensions/gfx_utils.h"
+
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "extensions/browser/extension_registry.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/chromeos/resources/grit/ui_chromeos_resources.h"
+#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_operations.h"
+
+namespace extensions {
+namespace util {
+
+bool MaybeApplyChromeBadge(content::BrowserContext* context,
+                           const std::string& extension_id,
+                           gfx::ImageSkia* icon_out) {
+  DCHECK(context);
+  DCHECK(icon_out);
+
+  Profile* profile = Profile::FromBrowserContext(context);
+  // Only apply Chrome badge for the primary profile.
+  if (!chromeos::ProfileHelper::IsPrimaryProfile(profile) ||
+      !multi_user_util::IsProfileFromActiveUser(profile)) {
+    return false;
+  }
+
+  arc::ArcAuthService* arc_auth_service = arc::ArcAuthService::Get();
+  if (!arc_auth_service ||
+      arc_auth_service->state() != arc::ArcAuthService::State::ACTIVE) {
+    return false;
+  }
+
+  const ExtensionRegistry* registry = ExtensionRegistry::Get(context);
+  if (!registry)
+    return false;
+
+  const Extension* extension = registry->GetInstalledExtension(extension_id);
+  if (!extension || !extension->is_hosted_app())
+    return false;
+
+  gfx::ImageSkia* badge_image =
+      ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
+          IDR_ARC_DUAL_ICON_BADGE);
+  DCHECK(badge_image);
+
+  if (badge_image->size() != icon_out->size()) {
+    *badge_image = gfx::ImageSkiaOperations::CreateResizedImage(
+        *badge_image, skia::ImageOperations::RESIZE_BEST, icon_out->size());
+  }
+  *icon_out = gfx::ImageSkiaOperations::CreateSuperimposedImage(*icon_out,
+                                                                *badge_image);
+  return true;
+}
+
+}  // namespace util
+}  // namespace extensions
diff --git a/chrome/browser/chromeos/extensions/gfx_utils.h b/chrome/browser/chromeos/extensions/gfx_utils.h
new file mode 100644
index 0000000..64a5f7d
--- /dev/null
+++ b/chrome/browser/chromeos/extensions/gfx_utils.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXTENSIONS_GFX_UTILS_H_
+#define CHROME_BROWSER_CHROMEOS_EXTENSIONS_GFX_UTILS_H_
+
+#include <string>
+
+namespace content {
+class BrowserContext;
+}
+
+namespace gfx {
+class ImageSkia;
+}
+
+namespace extensions {
+namespace util {
+
+// May apply additional badge in order to distinguish dual apps from Chrome and
+// Android side.
+bool MaybeApplyChromeBadge(content::BrowserContext* context,
+                           const std::string& extension_id,
+                           gfx::ImageSkia* icon_out);
+
+}  // namespace util
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXTENSIONS_GFX_UTILS_H_
diff --git a/chrome/browser/chromeos/login/chrome_restart_request.cc b/chrome/browser/chromeos/login/chrome_restart_request.cc
index ca4d9dfc..10f2a1a8 100644
--- a/chrome/browser/chromeos/login/chrome_restart_request.cc
+++ b/chrome/browser/chromeos/login/chrome_restart_request.cc
@@ -6,7 +6,7 @@
 
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "base/base_switches.h"
 #include "base/command_line.h"
 #include "base/macros.h"
diff --git a/chrome/browser/chromeos/login/lock/screen_locker.cc b/chrome/browser/chromeos/login/lock/screen_locker.cc
index f6f9091..10ccad0 100644
--- a/chrome/browser/chromeos/login/lock/screen_locker.cc
+++ b/chrome/browser/chromeos/login/lock/screen_locker.cc
@@ -7,8 +7,8 @@
 #include <string>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/audio/sounds.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm/wm_event.h"
 #include "ash/desktop_background/desktop_background_controller.h"
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
index 70db052..a09e363 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -9,8 +9,8 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/shell.h"
 #include "base/bind.h"
 #include "base/command_line.h"
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc
index 7f5b8eb..20522d2 100644
--- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc
+++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc
@@ -6,7 +6,7 @@
 
 #include <stddef.h>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
diff --git a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
index 676d9c35..f35e00a 100644
--- a/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/profiles/profile_list_chromeos_unittest.cc
@@ -5,7 +5,7 @@
 #include <memory>
 #include <string>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
diff --git a/chrome/browser/chromeos/system/timezone_resolver_manager.cc b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
index 3ff7ff5..a25a76e 100644
--- a/chrome/browser/chromeos/system/timezone_resolver_manager.cc
+++ b/chrome/browser/chromeos/system/timezone_resolver_manager.cc
@@ -31,8 +31,8 @@
 // SystemTimezoneAutomaticDetectionPolicy.
 // Returns SHOULD_* if timezone resolver status is controlled by this policy.
 ServiceConfiguration GetServiceConfigurationFromAutomaticDetectionPolicy() {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kEnableSystemTimezoneAutomaticDetectionPolicy)) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kDisableSystemTimezoneAutomaticDetectionPolicy)) {
     return UNSPECIFIED;
   }
 
diff --git a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
index 50e9a3d..ca4915a 100644
--- a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
+++ b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
@@ -147,6 +147,15 @@
   OnLayerChange(&caret_animation_info_);
 }
 
+void AccessibilityFocusRingController::SetNoFadeForTesting() {
+  focus_animation_info_.fade_in_time = base::TimeDelta();
+  focus_animation_info_.fade_out_time = base::TimeDelta::FromHours(1);
+  cursor_animation_info_.fade_in_time = base::TimeDelta();
+  cursor_animation_info_.fade_out_time = base::TimeDelta::FromHours(1);
+  caret_animation_info_.fade_in_time = base::TimeDelta();
+  caret_animation_info_.fade_out_time = base::TimeDelta::FromHours(1);
+}
+
 void AccessibilityFocusRingController::RectsToRings(
     const std::vector<gfx::Rect>& src_rects,
     std::vector<AccessibilityFocusRing>* rings) const {
diff --git a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h
index 3f68eca..80feb5c 100644
--- a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h
+++ b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h
@@ -38,6 +38,9 @@
   // Draw a ring around the text caret. It fades out automatically.
   void SetCaretRing(const gfx::Point& location);
 
+  // Don't fade in / out, for testing.
+  void SetNoFadeForTesting();
+
  protected:
   AccessibilityFocusRingController();
   ~AccessibilityFocusRingController() override;
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index 898a96e..c6dc486 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -95,7 +95,7 @@
 #include "ui/base/ui_base_types.h"
 
 #if defined(USE_ASH)
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
 #include "extensions/browser/app_window/app_window_registry.h"
 #endif
diff --git a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
index f9ee301e..05f2868 100644
--- a/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/display_info_provider_chromeos_unittest.cc
@@ -6,7 +6,7 @@
 
 #include <stdint.h>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/display/display_manager.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/screen_util.h"
diff --git a/chrome/browser/extensions/extension_app_icon_loader.cc b/chrome/browser/extensions/extension_app_icon_loader.cc
index 4d292ba..fb941e5 100644
--- a/chrome/browser/extensions/extension_app_icon_loader.cc
+++ b/chrome/browser/extensions/extension_app_icon_loader.cc
@@ -15,6 +15,10 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/extensions/gfx_utils.h"
+#endif
+
 namespace {
 
 const extensions::Extension* GetExtensionByID(Profile* profile,
@@ -92,6 +96,10 @@
                                         const gfx::ImageSkia& icon) {
   gfx::ImageSkia image = icon;
 
+#if defined(OS_CHROMEOS)
+  util::MaybeApplyChromeBadge(profile(), id, &image);
+#endif
+
   if (!util::IsAppLaunchable(id, profile())) {
     const color_utils::HSL shift = {-1, 0, 0.6};
     image = gfx::ImageSkiaOperations::CreateHSLShiftedImage(image, shift);
diff --git a/chrome/browser/media/cast_transport_host_filter.cc b/chrome/browser/media/cast_transport_host_filter.cc
index 87080587..3e91f41 100644
--- a/chrome/browser/media/cast_transport_host_filter.cc
+++ b/chrome/browser/media/cast_transport_host_filter.cc
@@ -149,14 +149,14 @@
   if (!power_save_blocker_) {
     DVLOG(1) << ("Preventing the application from being suspended while one or "
                  "more transports are active for Cast Streaming.");
-    power_save_blocker_ = device::PowerSaveBlocker::CreateWithTaskRunners(
+    power_save_blocker_.reset(new device::PowerSaveBlocker(
         device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
         device::PowerSaveBlocker::kReasonOther,
         "Cast is streaming content to a remote receiver",
         content::BrowserThread::GetMessageLoopProxyForThread(
             content::BrowserThread::UI),
         content::BrowserThread::GetMessageLoopProxyForThread(
-            content::BrowserThread::FILE));
+            content::BrowserThread::FILE)));
   }
 
   if (id_map_.Lookup(channel_id)) {
diff --git a/chrome/browser/media/native_desktop_media_list.cc b/chrome/browser/media/native_desktop_media_list.cc
index 7849bbe..eaa8e0f 100644
--- a/chrome/browser/media/native_desktop_media_list.cc
+++ b/chrome/browser/media/native_desktop_media_list.cc
@@ -96,7 +96,8 @@
   typedef std::map<DesktopMediaID, uint32_t> ImageHashesMap;
 
   // webrtc::DesktopCapturer::Callback interface.
-  void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override;
 
   base::WeakPtr<NativeDesktopMediaList> media_list_;
 
@@ -225,9 +226,10 @@
                  media_list_));
 }
 
-void NativeDesktopMediaList::Worker::OnCaptureCompleted(
-    webrtc::DesktopFrame* frame) {
-  current_frame_.reset(frame);
+void NativeDesktopMediaList::Worker::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) {
+  current_frame_ = std::move(frame);
 }
 
 NativeDesktopMediaList::NativeDesktopMediaList(
diff --git a/chrome/browser/media/native_desktop_media_list_unittest.cc b/chrome/browser/media/native_desktop_media_list_unittest.cc
index 8cde654e..04ef29e 100644
--- a/chrome/browser/media/native_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/native_desktop_media_list_unittest.cc
@@ -67,10 +67,11 @@
 
   void Capture(const webrtc::DesktopRegion& region) override {
     DCHECK(callback_);
-    webrtc::DesktopFrame* frame =
-        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
+    std::unique_ptr<webrtc::DesktopFrame> frame(
+        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10)));
     memset(frame->data(), 0, frame->stride() * frame->size().height());
-    callback_->OnCaptureCompleted(frame);
+    callback_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
+                               std::move(frame));
   }
 
   bool GetScreenList(ScreenList* screens) override {
@@ -121,10 +122,11 @@
     std::map<WindowId, int8_t>::iterator it =
         frame_values_.find(selected_window_id_);
     int8_t value = (it != frame_values_.end()) ? it->second : 0;
-    webrtc::DesktopFrame* frame =
-        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10));
+    std::unique_ptr<webrtc::DesktopFrame> frame(
+        new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10)));
     memset(frame->data(), value, frame->stride() * frame->size().height());
-    callback_->OnCaptureCompleted(frame);
+    callback_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
+                               std::move(frame));
   }
 
   bool GetWindowList(WindowList* windows) override {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 7c57142e..7332387 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -3977,9 +3977,6 @@
     command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "hash");
     command_line->AppendSwitch(
         chromeos::switches::kAllowFailedPolicyFetchForTest);
-
-    command_line->AppendSwitch(
-        chromeos::switches::kEnableSystemTimezoneAutomaticDetectionPolicy);
   }
 
  protected:
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 2b9a793..14253050 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -90,6 +90,7 @@
 #include "components/search_engines/template_url_prepopulate_data.h"
 #include "components/ssl_config/ssl_config_service_manager.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
+#include "components/subresource_filter/core/browser/ruleset_service.h"
 #include "components/sync_driver/sync_prefs.h"
 #include "components/syncable_prefs/pref_service_syncable.h"
 #include "components/translate/core/browser/translate_prefs.h"
@@ -323,6 +324,7 @@
   RegisterScreenshotPrefs(registry);
   SigninManagerFactory::RegisterPrefs(registry);
   ssl_config::SSLConfigServiceManager::RegisterPrefs(registry);
+  subresource_filter::RulesetVersion::RegisterPrefs(registry);
   startup_metric_utils::RegisterPrefs(registry);
   update_client::RegisterPrefs(registry);
   web_resource::PromoResourceService::RegisterPrefs(registry);
diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc
index 459347c..f2297a8 100644
--- a/chrome/browser/prefs/command_line_pref_store.cc
+++ b/chrome/browser/prefs/command_line_pref_store.cc
@@ -10,7 +10,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/macros.h"
diff --git a/chrome/browser/resources/offline_pages/compiled_resources2.gyp b/chrome/browser/resources/offline_pages/compiled_resources2.gyp
index daa309b..559ed1a4 100644
--- a/chrome/browser/resources/offline_pages/compiled_resources2.gyp
+++ b/chrome/browser/resources/offline_pages/compiled_resources2.gyp
@@ -10,6 +10,14 @@
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
+        'offline_internals_browser_proxy',
+      ],
+      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'offline_internals_browser_proxy',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/offline_pages/offline_internals.html b/chrome/browser/resources/offline_pages/offline_internals.html
index 8668832de..e6bbde98 100644
--- a/chrome/browser/resources/offline_pages/offline_internals.html
+++ b/chrome/browser/resources/offline_pages/offline_internals.html
@@ -11,6 +11,7 @@
     <script src="chrome://resources/js/load_time_data.js"></script>
     <script src="chrome://resources/js/util.js"></script>
     <script src="strings.js"></script>
+    <script src="offline_internals_browser_proxy.js"></script>
     <script src="offline_internals.js"></script>
   </head>
   <body>
diff --git a/chrome/browser/resources/offline_pages/offline_internals.js b/chrome/browser/resources/offline_pages/offline_internals.js
index 1f417fd8a..fc0fcb4 100644
--- a/chrome/browser/resources/offline_pages/offline_internals.js
+++ b/chrome/browser/resources/offline_pages/offline_internals.js
@@ -2,32 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-/**
- * @typedef {{
- *   onlineUrl: string,
- *   creationTime: number,
- *   id: string,
- *   namespace: string,
- *   size: string,
- *   filePath: string,
- *   lastAccessTime: number,
- *   accessCount: number
- * }}
- */
-var OfflinePage;
-
-/**
- * @typedef {{
- *   status: string,
- *   onlineUrl: string,
- *   creationTime: number,
- *   id: string,
- *   namespace: string,
- *   lastAttempt: number
- * }}
- */
-var SavePageRequest;
-
 cr.define('offlineInternals', function() {
   'use strict';
 
@@ -37,6 +11,9 @@
   /** @type {!Array<SavePageRequest>} */
   var savePageRequests = [];
 
+  /** @type {offlineInternals.OfflineInternalsBrowserProxy} */
+  var browserProxy_;
+
   /**
    * Fill stored pages table.
    * @param {!Array<OfflinePage>} pages An array object representing
@@ -108,15 +85,15 @@
    * Refresh all displayed information.
    */
   function refreshAll() {
-    cr.sendWithPromise('getStoredPagesInfo').then(fillStoredPages);
-    cr.sendWithPromise('getRequestQueueInfo').then(fillRequestQueue);
+    browserProxy_.getStoredPages().then(fillStoredPages);
+    browserProxy_.getRequestQueue().then(fillRequestQueue);
   }
 
   /**
    * Delete all pages in the offline store.
    */
   function deleteAllPages() {
-    cr.sendWithPromise('deleteAllPages').then(pagesDeleted);
+    browserProxy_.deleteAllPages().then(pagesDeleted);
   }
 
   /**
@@ -125,17 +102,7 @@
    */
   function pagesDeleted(status) {
     $('page-actions-info').textContent = status;
-    cr.sendWithPromise('getStoredPagesInfo').then(fillStoredPages);
-  }
-
-  /**
-   * Helper function to JSON-escape and add quotes around a string.
-   * @param {string} strObj The obj to escape and add quotes around.
-   * @return {string} The escaped string.
-   */
-  function escapeString(strObj) {
-    // CSV single quotes are encoded as "". There can also be commas.
-    return '"' + strObj.replace(/"/g, '""') + '"';
+    browserProxy_.getStoredPages().then(fillStoredPages);
   }
 
   /**
@@ -165,7 +132,7 @@
         selectedIds.push(checkboxes[i].value);
     }
 
-    cr.sendWithPromise('deleteSelectedPages', selectedIds).then(pagesDeleted);
+    browserProxy_.deleteSelectedPages(selectedIds).then(pagesDeleted);
   }
 
   function initialize() {
@@ -173,6 +140,8 @@
     $('clear-selected').onclick = deleteSelectedPages;
     $('refresh').onclick = refreshAll;
     $('download').onclick = download;
+    browserProxy_ =
+        offlineInternals.OfflineInternalsBrowserProxyImpl.getInstance();
     refreshAll();
   }
 
diff --git a/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js b/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js
new file mode 100644
index 0000000..7ab1de4
--- /dev/null
+++ b/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js
@@ -0,0 +1,98 @@
+// 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.
+
+/**
+ * @typedef {{
+ *   onlineUrl: string,
+ *   creationTime: number,
+ *   id: string,
+ *   namespace: string,
+ *   size: string,
+ *   filePath: string,
+ *   lastAccessTime: number,
+ *   accessCount: number
+ * }}
+ */
+var OfflinePage;
+
+/**
+ * @typedef {{
+ *   status: string,
+ *   onlineUrl: string,
+ *   creationTime: number,
+ *   id: string,
+ *   namespace: string,
+ *   lastAttempt: number
+ * }}
+ */
+var SavePageRequest;
+
+cr.define('offlineInternals', function() {
+  /** @interface */
+  function OfflineInternalsBrowserProxy() {}
+
+  OfflineInternalsBrowserProxy.prototype = {
+    /**
+     * Gets current list of stored pages.
+     * @return {!Promise<!Array<OfflinePage>>} A promise firing when the
+     *     list is fetched.
+     */
+    getStoredPages: function() {},
+
+    /**
+     * Gets current offline queue requests.
+     * @return {!Promise<!Array<SavePageRequest>>} A promise firing when the
+     *     request queue is fetched.
+     */
+    getRequestQueue: function() {},
+
+    /**
+     * Deletes all the pages in stored pages.
+     * @return {!Promise<!string>} A promise firing when the pages are deleted.
+     */
+    deleteAllPages: function() {},
+
+    /**
+     * Deletes a set of pages from stored pages
+     * @param {!Array<string>} ids A list of page IDs to delete.
+     * @return {!Promise<!string>} A promise firing when the selected
+     *     pages are deleted.
+     */
+    deleteSelectedPages: function(ids) {},
+  };
+
+  /**
+   * @constructor
+   * @implements {offlineInternals.OfflineInternalsBrowserProxy}
+   */
+  function OfflineInternalsBrowserProxyImpl() {}
+  cr.addSingletonGetter(OfflineInternalsBrowserProxyImpl);
+
+  OfflineInternalsBrowserProxyImpl.prototype = {
+    /** @override */
+    getStoredPages: function() {
+      return cr.sendWithPromise('getStoredPages');
+    },
+
+    /** @override */
+    getRequestQueue: function() {
+      return cr.sendWithPromise('getRequestQueue');
+    },
+
+    /** @override */
+    deleteAllPages: function() {
+      return cr.sendWithPromise('deleteAllPages');
+    },
+
+    /** @override */
+    deleteSelectedPages: function(ids) {
+      return cr.sendWithPromise('deleteSelectedPages', ids);
+    }
+  };
+
+  return {
+    OfflineInternalsBrowserProxy: OfflineInternalsBrowserProxy,
+    OfflineInternalsBrowserProxyImpl: OfflineInternalsBrowserProxyImpl
+  };
+});
diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html
index 5e1dc30..dcf01a5 100644
--- a/chrome/browser/resources/settings/settings.html
+++ b/chrome/browser/resources/settings/settings.html
@@ -19,8 +19,51 @@
         :host {
           color: var(--paper-grey-800);
         }
+
+        #appeal {
+          align-items: center;
+          background: red;
+          display: flex;
+          left: 0;
+          position: fixed;
+          right: 0;
+          top: 0;
+          z-index: 9999;
+        }
+
+        #request {
+          flex: 1;
+          font-size: 1rem;
+          font-weight: bold;
+          padding: 12px 8px;
+        }
+
+        #request h1 {
+          font-size: 1.5rem;
+          margin: 0;
+        }
+
+        #request a {
+          color: rgb(100, 100, 255);
+        }
+
+        #close {
+          padding: 20px;
+        }
       </style>
       <settings-prefs id="prefs" prefs="{{prefs_}}"></settings-prefs>
+
+      <!-- TODO(dbeam): remove before launching ;). -->
+      <div id="appeal" hidden="[[appealClosed_]]">
+        <span id="request">
+          <h1>Please read: A personal appeal from the Chrome settings team.</h1>
+          <a href="https://goo.gl/gRBbFv">Please file bugs</a>
+          before you
+          <a href="chrome://settings-frame">go back to the old settings</a>.
+        </span>
+        <span id="close" tabindex=0 on-tap="onCloseAppealTap_">&#x2715;</span>
+      </div>
+
       <settings-ui id="ui" prefs="{{prefs_}}"></settings-ui>
     </template>
     <script src="/settings.js"></script>
diff --git a/chrome/browser/resources/settings/settings.js b/chrome/browser/resources/settings/settings.js
index 8de0323..d8dea562 100644
--- a/chrome/browser/resources/settings/settings.js
+++ b/chrome/browser/resources/settings/settings.js
@@ -16,4 +16,18 @@
   ready: function() {
     this.$.ui.directionDelegate = new settings.DirectionDelegateImpl;
   },
+
+  properties: {
+    appealClosed_: {
+      type: Boolean,
+      value: function() {
+        return !!(sessionStorage.appealClosed_ || localStorage.appealClosed_);
+      },
+    },
+  },
+
+  /** @private */
+  onCloseAppealTap_: function(e) {
+    sessionStorage.appealClosed_ = this.appealClosed_ = true;
+  },
 });
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 0d4b5917..f032f4c8 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -30,7 +30,6 @@
         --paper-menu-focused-item-after: {
           background: none;
         };
-        background: none;  /* Overrides <paper-menu> default. */
         color: var(--settings-nav-grey);
         font-size: 13px;
         padding: 0;
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 8c50440..9a4a3728 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -34,50 +34,6 @@
         position: relative;
       }
 
-      #drawer {
-        --paper-header-panel-shadow: {
-          /* Polymer's style transformation chokes on :host() and :not() (and
-           * many other things, it seems). Just hide the built-in shadow and
-           * duplicate its style. */
-          display: none;
-        };
-        /* Explicitly set this so that transitions work and look good. */
-        background-color: var(--settings-background-color);
-      }
-
-      #drawer .toolbar::after {
-        box-shadow: inset 0px 5px 6px -3px rgba(0, 0, 0, 0.4);
-        content: '';
-        display: block;
-        height: 6px;
-      }
-
-      #drawer,
-      #drawer .toolbar,
-      #drawer .toolbar::after {
-        transition: background-color .3s, color .3s, height .3s;
-      }
-
-      :host(:not(.narrowing)) [narrow] #drawer,
-      :host(:not(.narrowing)) [narrow] #drawer .toolbar,
-      :host(:not(.narrowing)) [narrow] #drawer .toolbar::after {
-        transition: none;  /* Transition only when removing [narrow]. */
-      }
-
-      :host(:not(.narrowing)) [narrow] #drawer,
-      :host(:not(.narrowing)) [narrow] #drawer .toolbar {
-        background-color: white;
-      }
-
-      :host(:not(.narrowing)) [narrow] #drawer .toolbar {
-        color: var(--settings-nav-grey);
-      }
-
-      :host(:not(.narrowing)) [narrow] #drawer .toolbar::after {
-        border-bottom: var(--settings-separator-line);
-        height: 0;
-      }
-
       paper-header-panel[main] paper-icon-button {
         --iron-icon-fill-color: var(--settings-title-bar-color);
       }
@@ -159,10 +115,11 @@
         };
       }
 
-      /* Prevent paper-toolbar from setting the margin-right to 24px. */
       paper-icon-button#menu-button {
+        /* Prevent the menu icon from changing size with the window size. */
         flex-shrink: 0;
-        /* TODO(dschuyler): this margin is on the right regardless of language
+        /* Prevent paper-toolbar from setting the margin-right to 24px.
+         * TODO(dschuyler): this margin is on the right regardless of language
          * direction (e.g. rtl). Make a patch for paper-toolbar in Polymer. */
         margin-right: 0;
       }
@@ -179,6 +136,15 @@
         display: none;
       }
 
+      .paper-header {
+        -webkit-padding-start: 24px;
+        align-items: center;
+        border-bottom: var(--settings-separator-line);
+        display: flex;
+        font-size: 123.08%; /* go to 16px from 13px */
+        min-height: 56px;
+      }
+
       .last {
         display: flex;
         justify-content: flex-end;
@@ -190,15 +156,13 @@
     </settings-router>
     <paper-drawer-panel drawer-width="256px" id="panel" narrow="{{isNarrow_}}"
         responsive-width="900px" force-narrow>
-      <paper-header-panel drawer id="drawer">
-        <paper-toolbar class="toolbar">
-          <div class="heading">$i18n{settings}</div>
-        </paper-toolbar>
+      <paper-header-panel mode="waterfall" drawer>
+        <div class="paper-header">$i18n{settings}</div>
         <settings-menu current-route="{{currentRoute}}" id="sideNav">
         </settings-menu>
       </paper-header-panel>
-      <paper-header-panel main>
-        <paper-toolbar class="toolbar">
+      <paper-header-panel mode="waterfall" main>
+        <paper-toolbar>
           <paper-icon-button icon="settings:menu" id="menu-button"
               paper-drawer-toggle>
           </paper-icon-button>
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 1249bb8..f963ada 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -28,28 +28,12 @@
   },
 
   listeners: {
-    'sideNav.iron-select': 'onIronSelect_',
-    'paper-responsive-change': 'onPaperResponsiveChange_',
+    'sideNav.iron-activate': 'onIronActivate_',
   },
 
-  /**
-   * @param {!CustomEvent} e
-   * @private
-   */
-  onIronSelect_: function(e) {
-    if (Polymer.dom(e).path.indexOf(this.$.panel) >= 0) {
-      this.classList.remove('narrowing');
-      this.$.panel.closeDrawer();
-    }
-  },
-
-  /**
-   * @param {!CustomEvent} e
-   * @private
-   */
-  onPaperResponsiveChange_: function(e) {
-    if (Polymer.dom(e).rootTarget == this.$.panel)
-      this.classList.toggle('narrowing', e.detail.narrow);
+  /** @private */
+  onIronActivate_: function() {
+    this.$.panel.closeDrawer();
   },
 
   /** @private */
diff --git a/chrome/browser/ui/android/toolbar/toolbar_model_android.cc b/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
index 9b0e951..c53fca1 100644
--- a/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
+++ b/chrome/browser/ui/android/toolbar/toolbar_model_android.cc
@@ -39,20 +39,6 @@
                                                  toolbar_model_->GetText());
 }
 
-ScopedJavaLocalRef<jstring> ToolbarModelAndroid::GetCorpusChipText(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return base::android::ConvertUTF16ToJavaString(
-      env,
-      toolbar_model_->GetCorpusNameForMobile());
-}
-
-jboolean ToolbarModelAndroid::WouldReplaceURL(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  return toolbar_model_->WouldReplaceURL();
-}
-
 content::WebContents* ToolbarModelAndroid::GetActiveWebContents() const {
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobject> jdelegate = weak_java_delegate_.get(env);
diff --git a/chrome/browser/ui/android/toolbar/toolbar_model_android.h b/chrome/browser/ui/android/toolbar/toolbar_model_android.h
index 3ee6839d..141cda0 100644
--- a/chrome/browser/ui/android/toolbar/toolbar_model_android.h
+++ b/chrome/browser/ui/android/toolbar/toolbar_model_android.h
@@ -28,11 +28,6 @@
   base::android::ScopedJavaLocalRef<jstring> GetText(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj);
-  base::android::ScopedJavaLocalRef<jstring> GetCorpusChipText(
-      JNIEnv* env,
-      const base::android::JavaParamRef<jobject>& obj);
-  jboolean WouldReplaceURL(JNIEnv* env,
-                           const base::android::JavaParamRef<jobject>& obj);
 
   // ChromeToolbarModelDelegate:
   content::WebContents* GetActiveWebContents() const override;
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon_loader.cc b/chrome/browser/ui/app_list/arc/arc_app_icon_loader.cc
index 8edb420..b87de787 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_icon_loader.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon_loader.cc
@@ -10,11 +10,9 @@
 
 ArcAppIconLoader::ArcAppIconLoader(Profile* profile,
                                    int icon_size,
-                                   PostEffect* post_effect,
                                    AppIconLoaderDelegate* delegate)
     : AppIconLoader(profile, icon_size, delegate),
-      arc_prefs_(ArcAppListPrefs::Get(profile)),
-      post_effect_(post_effect) {
+      arc_prefs_(ArcAppListPrefs::Get(profile)) {
   DCHECK(arc_prefs_);
   arc_prefs_->AddObserver(this);
 }
@@ -51,13 +49,7 @@
   if (it == icon_map_.end())
     return;
 
-  if (post_effect_) {
-    gfx::ImageSkia image = it->second->image_skia();
-    post_effect_->Apply(app_id, &image);
-    delegate()->OnAppImageUpdated(app_id, image);
-  } else {
-    delegate()->OnAppImageUpdated(app_id, it->second->image_skia());
-  }
+  delegate()->OnAppImageUpdated(app_id, it->second->image_skia());
 }
 
 void ArcAppIconLoader::OnIconUpdated(ArcAppIcon* icon) {
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon_loader.h b/chrome/browser/ui/app_list/arc/arc_app_icon_loader.h
index aa015a2..9176a1f9 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_icon_loader.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon_loader.h
@@ -20,18 +20,8 @@
                          public ArcAppListPrefs::Observer,
                          public ArcAppIcon::Observer {
  public:
-  // Interface to apply post effects
-  class PostEffect {
-   public:
-    virtual void Apply(const std::string& app_id, gfx::ImageSkia* image) = 0;
-
-   protected:
-    virtual ~PostEffect() {}
-  };
-
   ArcAppIconLoader(Profile* profile,
                    int icon_size,
-                   PostEffect* post_effects,
                    AppIconLoaderDelegate* delegate);
   ~ArcAppIconLoader() override;
 
@@ -52,9 +42,8 @@
  private:
   using AppIDToIconMap = std::map<std::string, std::unique_ptr<ArcAppIcon>>;
 
-  // Unowned pointers.
+  // Unowned pointer.
   ArcAppListPrefs* const arc_prefs_;
-  PostEffect* const post_effect_;
 
   AppIDToIconMap icon_map_;
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_launcher.cc b/chrome/browser/ui/app_list/arc/arc_app_launcher.cc
index 878e244..495d10dc 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_launcher.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_launcher.cc
@@ -16,7 +16,7 @@
   DCHECK(prefs);
 
   std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(app_id_);
-  if (app_info && app_info->ready)
+  if (app_info)
     LaunchApp();
   else
     prefs->AddObserver(this);
@@ -34,12 +34,7 @@
 void ArcAppLauncher::OnAppRegistered(
     const std::string& app_id,
     const ArcAppListPrefs::AppInfo& app_info) {
-  if (app_id == app_id_ && app_info.ready)
-    LaunchApp();
-}
-
-void ArcAppLauncher::OnAppReadyChanged(const std::string& app_id, bool ready) {
-  if (app_id == app_id_ && ready)
+  if (app_id == app_id_)
     LaunchApp();
 }
 
diff --git a/chrome/browser/ui/app_list/arc/arc_app_launcher.h b/chrome/browser/ui/app_list/arc/arc_app_launcher.h
index d475ae4..ea1a965 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_launcher.h
+++ b/chrome/browser/ui/app_list/arc/arc_app_launcher.h
@@ -28,7 +28,6 @@
   // ArcAppListPrefs::Observer:
   void OnAppRegistered(const std::string& app_id,
                        const ArcAppListPrefs::AppInfo& app_info) override;
-  void OnAppReadyChanged(const std::string& id, bool ready) override;
 
  private:
   void LaunchApp();
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index a7f9a6e..2dace8a5 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -13,7 +13,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task_runner_util.h"
-#include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/common/pref_names.h"
@@ -264,9 +263,7 @@
 
   const base::DictionaryValue* app = nullptr;
   const base::DictionaryValue* apps = prefs_->GetDictionary(prefs::kArcApps);
-  const std::string mapped_app_id =
-      (app_id == ArcSupportHost::kHostAppId) ? arc::kPlayStoreAppId : app_id;
-  if (!apps || !apps->GetDictionaryWithoutPathExpansion(mapped_app_id, &app))
+  if (!apps || !apps->GetDictionaryWithoutPathExpansion(app_id, &app))
     return std::unique_ptr<AppInfo>();
 
   std::string name;
@@ -293,7 +290,7 @@
 
   std::unique_ptr<AppInfo> app_info(
       new AppInfo(name, package_name, activity, last_launch_time, sticky,
-                  notifications_enabled, ready_apps_.count(mapped_app_id) > 0,
+                  notifications_enabled, ready_apps_.count(app_id) > 0,
                   arc::ShouldShowInLauncher(app_id)));
   return app_info;
 }
diff --git a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
index b1ad05d..67b430fd 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_unittest.cc
@@ -587,7 +587,6 @@
   FakeAppIconLoaderDelegate delegate;
   ArcAppIconLoader icon_loader(profile(),
                                app_list::kListIconSize,
-                               nullptr,
                                &delegate);
   EXPECT_EQ(0UL, delegate.update_image_cnt());
   icon_loader.FetchImage(app_id);
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index 8263306..5263c37 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -33,6 +33,10 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/image/canvas_image_source.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/extensions/gfx_utils.h"
+#endif
+
 using extensions::Extension;
 
 namespace {
@@ -169,6 +173,10 @@
     icon = icon_->image_skia();
     const bool enabled = extensions::util::IsAppLaunchable(extension_id(),
                                                            profile());
+#if defined(OS_CHROMEOS)
+    extensions::util::MaybeApplyChromeBadge(profile(), id(), &icon);
+#endif
+
     if (!enabled)
       icon = CreateDisabledIcon(icon);
 
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.cc b/chrome/browser/ui/app_list/extension_app_model_builder.cc
index 0571e17..52e8d528 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.cc
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.cc
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/app_list/app_list_controller_delegate.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 #include "chrome/browser/ui/app_list/extension_app_item.h"
+#include "chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h"
 #include "chrome/common/pref_names.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/extension_registry.h"
@@ -38,7 +39,6 @@
 
 ExtensionAppModelBuilder::~ExtensionAppModelBuilder() {
   OnShutdown();
-  OnShutdown(extension_registry_);
 }
 
 void ExtensionAppModelBuilder::InitializePrefChangeRegistrars() {
@@ -132,49 +132,54 @@
   model()->DeleteItem(extension_id);
 }
 
-void ExtensionAppModelBuilder::OnExtensionLoaded(
+void ExtensionAppModelBuilder::OnAppInstalled(
     content::BrowserContext* browser_context,
-    const extensions::Extension* extension) {
+    const std::string& app_id) {
+  extensions::ExtensionRegistry* extension_registry =
+      extensions::ExtensionRegistry::Get(profile());
+
+  const Extension* extension =
+      extension_registry ? extension_registry->GetInstalledExtension(app_id)
+                         : nullptr;
+  if (!extension) {
+    NOTREACHED();
+    return;
+  }
+
   if (!extensions::ui_util::ShouldDisplayInAppLauncher(extension, profile()))
     return;
 
-  DVLOG(2) << service() << ": OnExtensionLoaded: "
-           << extension->id().substr(0, 8);
-  ExtensionAppItem* existing_item = GetExtensionAppItem(extension->id());
+  DVLOG(2) << service() << ": OnAppInstalled: " << app_id.substr(0, 8);
+  ExtensionAppItem* existing_item = GetExtensionAppItem(app_id);
   if (existing_item) {
-    existing_item->Reload();
+    existing_item->UpdateIcon();
     if (service())
       service()->UpdateItem(existing_item);
     return;
   }
 
-  InsertApp(CreateAppItem(extension->id(),
-                          "",
-                          gfx::ImageSkia(),
+  InsertApp(CreateAppItem(app_id, "", gfx::ImageSkia(),
                           extension->is_platform_app()));
 }
 
-void ExtensionAppModelBuilder::OnExtensionUnloaded(
+void ExtensionAppModelBuilder::OnAppUpdated(
     content::BrowserContext* browser_context,
-    const extensions::Extension* extension,
-    extensions::UnloadedExtensionInfo::Reason reason) {
-  ExtensionAppItem* item = GetExtensionAppItem(extension->id());
+    const std::string& app_id) {
+  ExtensionAppItem* item = GetExtensionAppItem(app_id);
   if (!item)
     return;
   item->UpdateIcon();
 }
 
-void ExtensionAppModelBuilder::OnExtensionUninstalled(
+void ExtensionAppModelBuilder::OnAppUninstalled(
     content::BrowserContext* browser_context,
-    const extensions::Extension* extension,
-    extensions::UninstallReason reason) {
+    const std::string& app_id) {
   if (service()) {
-    DVLOG(2) << service() << ": OnExtensionUninstalled: "
-             << extension->id().substr(0, 8);
-    service()->RemoveUninstalledItem(extension->id());
+    DVLOG(2) << service() << ": OnAppUninstalled: " << app_id.substr(0, 8);
+    service()->RemoveUninstalledItem(app_id);
     return;
   }
-  model()->DeleteUninstalledItem(extension->id());
+  model()->DeleteUninstalledItem(app_id);
 }
 
 void ExtensionAppModelBuilder::OnDisabledExtensionUpdated(
@@ -192,16 +197,7 @@
     tracker_->RemoveObserver(this);
     tracker_ = nullptr;
   }
-}
-
-void ExtensionAppModelBuilder::OnShutdown(
-    extensions::ExtensionRegistry* registry) {
-  if (!extension_registry_)
-    return;
-
-  DCHECK_EQ(extension_registry_, registry);
-  extension_registry_->RemoveObserver(this);
-  extension_registry_ = nullptr;
+  app_updater_.reset();
 }
 
 std::unique_ptr<ExtensionAppItem> ExtensionAppModelBuilder::CreateAppItem(
@@ -220,7 +216,6 @@
   InitializePrefChangeRegistrars();
 
   tracker_ = controller()->GetInstallTrackerFor(profile());
-  extension_registry_ = extensions::ExtensionRegistry::Get(profile());
 
   PopulateApps();
 
@@ -228,8 +223,7 @@
   if (tracker_)
     tracker_->AddObserver(this);
 
-  if (extension_registry_)
-    extension_registry_->AddObserver(this);
+  app_updater_.reset(new LauncherExtensionAppUpdater(this, profile()));
 }
 
 void ExtensionAppModelBuilder::PopulateApps() {
diff --git a/chrome/browser/ui/app_list/extension_app_model_builder.h b/chrome/browser/ui/app_list/extension_app_model_builder.h
index d72d231c..35036d6c 100644
--- a/chrome/browser/ui/app_list/extension_app_model_builder.h
+++ b/chrome/browser/ui/app_list/extension_app_model_builder.h
@@ -7,17 +7,19 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
 #include "chrome/browser/extensions/install_observer.h"
 #include "chrome/browser/ui/app_list/app_list_model_builder.h"
+#include "chrome/browser/ui/ash/launcher/launcher_app_updater.h"
 #include "components/prefs/pref_change_registrar.h"
-#include "extensions/browser/extension_registry_observer.h"
 #include "ui/base/models/list_model_observer.h"
 
 class AppListControllerDelegate;
+class LauncherExtensionAppUpdater;
 class ExtensionAppItem;
 
 namespace extensions {
@@ -35,7 +37,7 @@
 // with information from |profile|.
 class ExtensionAppModelBuilder : public AppListModelBuilder,
                                  public extensions::InstallObserver,
-                                 public extensions::ExtensionRegistryObserver {
+                                 public LauncherAppUpdater::Delegate {
  public:
   explicit ExtensionAppModelBuilder(AppListControllerDelegate* controller);
   ~ExtensionAppModelBuilder() override;
@@ -55,17 +57,13 @@
       const extensions::Extension* extension) override;
   void OnShutdown() override;
 
-  // extensions::ExtensionRegistryObserver.
-  void OnExtensionLoaded(content::BrowserContext* browser_context,
-                         const extensions::Extension* extension) override;
-  void OnExtensionUnloaded(
-      content::BrowserContext* browser_context,
-      const extensions::Extension* extension,
-      extensions::UnloadedExtensionInfo::Reason reason) override;
-  void OnExtensionUninstalled(content::BrowserContext* browser_context,
-                              const extensions::Extension* extension,
-                              extensions::UninstallReason reason) override;
-  void OnShutdown(extensions::ExtensionRegistry* registry) override;
+  // LauncherAppUpdater::Delegate:
+  void OnAppInstalled(content::BrowserContext* browser_context,
+                      const std::string& app_id) override;
+  void OnAppUpdated(content::BrowserContext* browser_context,
+                    const std::string& app_id) override;
+  void OnAppUninstalled(content::BrowserContext* browser_context,
+                        const std::string& app_id) override;
 
   // AppListItemListObserver.
   void OnListItemMoved(size_t from_index,
@@ -105,8 +103,8 @@
   // We listen to this to show app installing progress.
   extensions::InstallTracker* tracker_ = nullptr;
 
-  // Listen extension's load, unload, uninstalled.
-  extensions::ExtensionRegistry* extension_registry_ = nullptr;
+  // Dispatches extension lifecycle events.
+  std::unique_ptr<LauncherExtensionAppUpdater> app_updater_;
 
   DISALLOW_COPY_AND_ASSIGN(ExtensionAppModelBuilder);
 };
diff --git a/chrome/browser/ui/app_list/search/arc_app_result.cc b/chrome/browser/ui/app_list/search/arc_app_result.cc
index 51c052c..c22141162 100644
--- a/chrome/browser/ui/app_list/search/arc_app_result.cc
+++ b/chrome/browser/ui/app_list/search/arc_app_result.cc
@@ -28,7 +28,6 @@
   set_id(id);
   icon_loader_.reset(new ArcAppIconLoader(profile,
                                           GetPreferredIconDimension(),
-                                          nullptr,
                                           this));
   icon_loader_->FetchImage(app_id);
 }
diff --git a/chrome/browser/ui/app_list/search/extension_app_result.cc b/chrome/browser/ui/app_list/search/extension_app_result.cc
index 964980d7..877fc96 100644
--- a/chrome/browser/ui/app_list/search/extension_app_result.cc
+++ b/chrome/browser/ui/app_list/search/extension_app_result.cc
@@ -24,6 +24,10 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/extensions/gfx_utils.h"
+#endif
+
 namespace app_list {
 
 ExtensionAppResult::ExtensionAppResult(Profile* profile,
@@ -137,6 +141,10 @@
 void ExtensionAppResult::UpdateIcon() {
   gfx::ImageSkia icon = icon_->image_skia();
 
+#if defined(OS_CHROMEOS)
+  extensions::util::MaybeApplyChromeBadge(profile(), app_id(), &icon);
+#endif
+
   if (!extensions::util::IsAppLaunchable(app_id(), profile())) {
     const color_utils::HSL shift = {-1, 0, 0.6};
     icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
diff --git a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
index 2536cc7..eff8f19 100644
--- a/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
+++ b/chrome/browser/ui/ash/accelerator_commands_browsertest.cc
@@ -4,8 +4,8 @@
 
 #include "ash/accelerators/accelerator_commands.h"
 
-#include "ash/ash_switches.h"
 #include "ash/aura/wm_window_aura.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/shell.h"
 #include "ash/wm/window_state_aura.h"
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 40d9394..b439934f 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/ui/ash/ash_init.h"
 
 #include "ash/accelerators/accelerator_controller.h"
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/magnifier/magnification_controller.h"
 #include "ash/magnifier/partial_magnification_controller.h"
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc
index ae23bc6d..8c393f1f 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.h"
+#include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/image/canvas_image_source.h"
@@ -22,11 +23,11 @@
  public:
   SpinningEffectSource(
       const base::WeakPtr<ArcAppDeferredLauncherController>& host,
-      const std::string& app_id,
+      const std::string& shelf_app_id,
       const gfx::ImageSkia& image)
       : gfx::CanvasImageSource(image.size(), false /* is opaque */),
         host_(host),
-        app_id_(app_id),
+        shelf_app_id_(shelf_app_id),
         image_(image) {}
 
   ~SpinningEffectSource() override {}
@@ -39,15 +40,15 @@
     canvas->DrawImageInt(image_, 0, 0);
 
     const int gap = kSpinningGapPercent * image_.width() / 100;
-    gfx::PaintThrobberSpinning(canvas,
-                               gfx::Rect(gap, gap, image_.width() - 2 * gap,
-                                         image_.height() - 2 * gap),
-                               SK_ColorWHITE, host_->GetActiveTime(app_id_));
+    gfx::PaintThrobberSpinning(
+        canvas, gfx::Rect(gap, gap, image_.width() - 2 * gap,
+                          image_.height() - 2 * gap),
+        SK_ColorWHITE, host_->GetActiveTime(shelf_app_id_));
   }
 
  private:
   base::WeakPtr<ArcAppDeferredLauncherController> host_;
-  const std::string app_id_;
+  const std::string shelf_app_id_;
   const gfx::ImageSkia image_;
 
   DISALLOW_COPY_AND_ASSIGN(SpinningEffectSource);
@@ -68,16 +69,17 @@
     ArcAppListPrefs::Get(observed_profile_)->RemoveObserver(this);
 }
 
-void ArcAppDeferredLauncherController::Apply(const std::string& app_id,
-                                             gfx::ImageSkia* image) {
+void ArcAppDeferredLauncherController::MaybeApplySpinningEffect(
+    const std::string& shelf_app_id,
+    gfx::ImageSkia* image) {
   DCHECK(image);
-  if (app_controller_map_.find(app_id) == app_controller_map_.end())
+  if (app_controller_map_.find(shelf_app_id) == app_controller_map_.end())
     return;
 
   const color_utils::HSL shift = {-1, 0, 0.25};
   *image = gfx::ImageSkia(
       new SpinningEffectSource(
-          weak_ptr_factory_.GetWeakPtr(), app_id,
+          weak_ptr_factory_.GetWeakPtr(), shelf_app_id,
           gfx::ImageSkiaOperations::CreateTransparentImage(
               gfx::ImageSkiaOperations::CreateHSLShiftedImage(*image, shift),
               0.5)),
@@ -85,25 +87,30 @@
 }
 
 void ArcAppDeferredLauncherController::Close(const std::string& app_id) {
-  AppControllerMap::const_iterator it = app_controller_map_.find(app_id);
+  const std::string shelf_app_id =
+      ArcAppWindowLauncherController::GetShelfAppIdFromArcAppId(app_id);
+  AppControllerMap::const_iterator it = app_controller_map_.find(shelf_app_id);
   if (it == app_controller_map_.end())
     return;
 
-  const ash::ShelfID shelf_id = owner_->GetShelfIDForAppID(app_id);
+  const ash::ShelfID shelf_id = owner_->GetShelfIDForAppID(shelf_app_id);
   const bool need_close_item =
       it->second == owner_->GetLauncherItemController(shelf_id);
   app_controller_map_.erase(it);
   if (need_close_item)
     owner_->CloseLauncherItem(shelf_id);
+  owner_->OnAppUpdated(owner_->GetProfile(), shelf_app_id);
 }
 
 void ArcAppDeferredLauncherController::OnAppReadyChanged(
     const std::string& app_id,
     bool ready) {
-  if (!ready)
+  if (!ready || app_controller_map_.empty())
     return;
 
-  AppControllerMap::const_iterator it = app_controller_map_.find(app_id);
+  const std::string shelf_app_id =
+      ArcAppWindowLauncherController::GetShelfAppIdFromArcAppId(app_id);
+  AppControllerMap::const_iterator it = app_controller_map_.find(shelf_app_id);
   if (it == app_controller_map_.end())
     return;
 
@@ -117,8 +124,8 @@
 }
 
 base::TimeDelta ArcAppDeferredLauncherController::GetActiveTime(
-    const std::string& app_id) const {
-  AppControllerMap::const_iterator it = app_controller_map_.find(app_id);
+    const std::string& shelf_app_id) const {
+  AppControllerMap::const_iterator it = app_controller_map_.find(shelf_app_id);
   if (it == app_controller_map_.end())
     return base::TimeDelta();
 
@@ -144,7 +151,7 @@
 void ArcAppDeferredLauncherController::RegisterDeferredLaunch(
     const std::string& app_id) {
   const std::string shelf_app_id =
-      app_id == arc::kPlayStoreAppId ? ArcSupportHost::kHostAppId : app_id;
+      ArcAppWindowLauncherController::GetShelfAppIdFromArcAppId(app_id);
   const ash::ShelfID shelf_id = owner_->GetShelfIDForAppID(shelf_app_id);
 
   if (shelf_id) {
@@ -158,7 +165,7 @@
   }
 
   ArcAppDeferredLauncherItemController* controller =
-      new ArcAppDeferredLauncherItemController(app_id, owner_,
+      new ArcAppDeferredLauncherItemController(shelf_app_id, owner_,
                                                weak_ptr_factory_.GetWeakPtr());
   if (shelf_id == 0) {
     owner_->CreateAppLauncherItem(controller, shelf_app_id,
@@ -171,5 +178,5 @@
   if (app_controller_map_.empty())
     RegisterNextUpdate();
 
-  app_controller_map_[app_id] = controller;
+  app_controller_map_[shelf_app_id] = controller;
 }
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h
index 656a0da..5fe37ac 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h
@@ -16,8 +16,7 @@
 class ArcAppDeferredLauncherItemController;
 class ChromeLauncherControllerImpl;
 
-class ArcAppDeferredLauncherController : public ArcAppListPrefs::Observer,
-                                         public ArcAppIconLoader::PostEffect {
+class ArcAppDeferredLauncherController : public ArcAppListPrefs::Observer {
  public:
   explicit ArcAppDeferredLauncherController(
       ChromeLauncherControllerImpl* owner);
@@ -25,11 +24,12 @@
 
   base::TimeDelta GetActiveTime(const std::string& app_id) const;
 
-  // Register deferred Arc app launch.
+  // Registers deferred Arc app launch.
   void RegisterDeferredLaunch(const std::string& app_id);
 
-  // ArcAppIconLoader::PostEffect:
-  void Apply(const std::string& app_id, gfx::ImageSkia* image) override;
+  // Applies spinning effect if requested app is handled by deferred controller.
+  void MaybeApplySpinningEffect(const std::string& app_id,
+                                gfx::ImageSkia* image);
 
   // ArcAppListPrefs::Observer:
   void OnAppReadyChanged(const std::string& app_id, bool ready) override;
diff --git a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
index 2f9c0b01..d3b35e83 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_item_controller.cc
@@ -8,6 +8,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_deferred_launcher_controller.h"
+#include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
 ArcAppDeferredLauncherItemController::ArcAppDeferredLauncherItemController(
@@ -36,8 +37,8 @@
   ArcAppListPrefs* arc_prefs =
       ArcAppListPrefs::Get(launcher_controller()->GetProfile());
   DCHECK(arc_prefs);
-  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
-      arc_prefs->GetApp(app_id());
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = arc_prefs->GetApp(
+      ArcAppWindowLauncherController::GetArcAppIdFromShelfAppId(app_id()));
   if (!app_info) {
     NOTREACHED();
     return base::string16();
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index 7951fd6..638dc61 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -33,9 +33,6 @@
   NON_ACTIVE,   // Fullscreen was not activated for an app.
 };
 
-std::string GetShelfAppId(const std::string& app_id) {
-  return app_id == arc::kPlayStoreAppId ? ArcSupportHost::kHostAppId : app_id;
-}
 }  // namespace
 
 class ArcAppWindowLauncherController::AppWindow : public ui::BaseWindow {
@@ -201,6 +198,20 @@
     StopObserving(observed_profile_);
 }
 
+// static
+std::string ArcAppWindowLauncherController::GetShelfAppIdFromArcAppId(
+    const std::string& arc_app_id) {
+  return arc_app_id == arc::kPlayStoreAppId ? ArcSupportHost::kHostAppId
+                                            : arc_app_id;
+}
+
+// static
+std::string ArcAppWindowLauncherController::GetArcAppIdFromShelfAppId(
+    const std::string& shelf_app_id) {
+  return shelf_app_id == ArcSupportHost::kHostAppId ? arc::kPlayStoreAppId
+                                                    : shelf_app_id;
+}
+
 void ArcAppWindowLauncherController::ActiveUserChanged(
     const std::string& user_email) {
   for (auto& it : task_id_to_app_window_) {
@@ -288,7 +299,9 @@
 }
 
 void ArcAppWindowLauncherController::OnAppRemoved(const std::string& app_id) {
-  AppControllerMap::const_iterator it = app_controller_map_.find(app_id);
+  const std::string shelf_app_id = GetShelfAppIdFromArcAppId(app_id);
+
+  AppControllerMap::const_iterator it = app_controller_map_.find(shelf_app_id);
   if (it == app_controller_map_.end())
     return;
 
@@ -303,7 +316,7 @@
   for (const auto task_id : task_ids_to_remove)
     OnTaskDestroyed(task_id);
 
-  DCHECK(app_controller_map_.find(app_id) == app_controller_map_.end());
+  DCHECK(app_controller_map_.find(shelf_app_id) == app_controller_map_.end());
 }
 
 void ArcAppWindowLauncherController::OnTaskCreated(
@@ -312,8 +325,8 @@
     const std::string& activity_name) {
   DCHECK(!GetAppWindowForTask(task_id));
 
-  const std::string app_id =
-      GetShelfAppId(ArcAppListPrefs::GetAppId(package_name, activity_name));
+  const std::string app_id = GetShelfAppIdFromArcAppId(
+      ArcAppListPrefs::GetAppId(package_name, activity_name));
 
   std::unique_ptr<AppWindow> app_window(new AppWindow(task_id, app_id, this));
   RegisterApp(app_window.get());
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
index f0b89751..cd70f28 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h
@@ -42,6 +42,12 @@
                                  ash::ShelfDelegate* shelf_delegate);
   ~ArcAppWindowLauncherController() override;
 
+  // Returns shelf app id. Play Store app is mapped to Arc platform host app.
+  static std::string GetShelfAppIdFromArcAppId(const std::string& arc_app_id);
+
+  // Returns Arc app id. Arc platform host app is mapped to Play Store app.
+  static std::string GetArcAppIdFromShelfAppId(const std::string& shelf_app_id);
+
   // AppWindowLauncherControllre:
   void ActiveUserChanged(const std::string& user_email) override;
   void AdditionalUserAddedToSession(Profile* profile) override;
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
index 10e3a73..410a7ef 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_item_controller.cc
@@ -7,6 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
+#include "chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_app_menu_item_v2app.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 
@@ -24,8 +25,8 @@
   ArcAppListPrefs* arc_prefs =
       ArcAppListPrefs::Get(launcher_controller()->GetProfile());
   DCHECK(arc_prefs);
-  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info =
-      arc_prefs->GetApp(app_id());
+  std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = arc_prefs->GetApp(
+      ArcAppWindowLauncherController::GetArcAppIdFromShelfAppId(app_id()));
   if (!app_info) {
     NOTREACHED();
     return base::string16();
diff --git a/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc
index d363e8f..12f0c34 100644
--- a/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.cc
@@ -6,6 +6,7 @@
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_launcher.h"
+#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_playstore_shortcut_launcher_item_controller.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -22,14 +23,24 @@
 ash::ShelfItemDelegate::PerformedAction
 ArcPlaystoreShortcutLauncherItemController::Activate(ash::LaunchSource source) {
   arc::ArcAuthService* auth_service = arc::ArcAuthService::Get();
+  ArcAppListPrefs* arc_app_prefs =
+      ArcAppListPrefs::Get(controller()->GetProfile());
+  DCHECK(auth_service);
+  DCHECK(arc_app_prefs);
   DCHECK(auth_service->IsAllowed());
 
   if (!auth_service->IsArcEnabled())
     auth_service->EnableArc();
 
   // Deferred launcher.
-  playstore_launcher_.reset(new ArcAppLauncher(controller()->GetProfile(),
-                                               arc::kPlayStoreAppId, true));
+  if (arc_app_prefs->IsRegistered(arc::kPlayStoreAppId)) {
+    // Known apps can be launched directly or deferred.
+    arc::LaunchApp(controller()->GetProfile(), arc::kPlayStoreAppId, true);
+  } else {
+    // Launch Play Store once its app appears.
+    playstore_launcher_.reset(new ArcAppLauncher(controller()->GetProfile(),
+                                                 arc::kPlayStoreAppId, true));
+  }
 
   return kNoAction;
 }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
index 0c4191b..9e0314ac 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.h
@@ -235,6 +235,9 @@
   virtual BrowserShortcutLauncherItemController*
   GetBrowserShortcutLauncherItemController() = 0;
 
+  // Apply the Chrome badge to the browser short cut icon if applicable.
+  virtual void MayUpdateBrowserShortcutItem() = 0;
+
   virtual LauncherItemController* GetLauncherItemController(
       const ash::ShelfID id) = 0;
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
index 2c8306b1b..201130f2 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.cc
@@ -8,7 +8,7 @@
 
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_item_delegate_manager.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/system/tray/system_tray_delegate.h"
@@ -29,6 +29,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/arc/arc_support_host.h"
+#include "chrome/browser/chromeos/extensions/gfx_utils.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/extensions/extension_app_icon_loader.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -947,6 +948,20 @@
   return nullptr;
 }
 
+void ChromeLauncherControllerImpl::MayUpdateBrowserShortcutItem() {
+  for (size_t index = 0; index < model_->items().size(); index++) {
+    ash::ShelfItem item = model_->items()[index];
+    if (item.type == ash::TYPE_BROWSER_SHORTCUT) {
+      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+      item.image = *rb.GetImageSkiaNamed(IDR_PRODUCT_LOGO_32);
+      extensions::util::MaybeApplyChromeBadge(
+          profile_, extension_misc::kChromeAppId, &item.image);
+      model_->Set(index, item);
+      break;
+    }
+  }
+}
+
 LauncherItemController* ChromeLauncherControllerImpl::GetLauncherItemController(
     const ash::ShelfID id) {
   if (!HasShelfIDToAppIDMapping(id))
@@ -1141,12 +1156,17 @@
 void ChromeLauncherControllerImpl::OnAppUpdated(
     content::BrowserContext* browser_context,
     const std::string& app_id) {
+  if (app_id == extension_misc::kChromeAppId) {
+    MayUpdateBrowserShortcutItem();
+    return;
+  }
+
   AppIconLoader* app_icon_loader = GetAppIconLoaderForApp(app_id);
   if (app_icon_loader)
     app_icon_loader->UpdateImage(app_id);
 }
 
-void ChromeLauncherControllerImpl::OnAppUninstalled(
+void ChromeLauncherControllerImpl::OnAppUninstalledPrepared(
     content::BrowserContext* browser_context,
     const std::string& app_id) {
   // Since we might have windowed apps of this type which might have
@@ -1349,6 +1369,8 @@
   // of iterators because of model mutations as part of the loop.
   std::vector<std::string>::const_iterator pref_app_id(pinned_apps.begin());
   for (; index < max_index && pref_app_id != pinned_apps.end(); ++index) {
+    // Update apps icon if applicable.
+    OnAppUpdated(profile_, *pref_app_id);
     // Check if we have an item which we need to handle.
     if (*pref_app_id == extension_misc::kChromeAppId ||
         *pref_app_id == ash::kPinnedAppsPlaceholder ||
@@ -1443,6 +1465,8 @@
 
   // Append unprocessed items from the pref to the end of the model.
   for (; pref_app_id != pinned_apps.end(); ++pref_app_id) {
+    // Update apps icon if applicable.
+    OnAppUpdated(profile_, *pref_app_id);
     // All items but the chrome and / or app list shortcut needs to be added.
     bool is_chrome = *pref_app_id == extension_misc::kChromeAppId;
     bool is_app_list = *pref_app_id == ash::kPinnedAppsPlaceholder;
@@ -1728,10 +1752,8 @@
   app_icon_loaders_.push_back(std::move(extension_app_icon_loader));
 
   if (arc::ArcAuthService::IsAllowedForProfile(profile_)) {
-    DCHECK(arc_deferred_launcher_.get());
-    std::unique_ptr<AppIconLoader> arc_app_icon_loader(
-        new ArcAppIconLoader(profile_, extension_misc::EXTENSION_ICON_SMALL,
-                             arc_deferred_launcher_.get(), this));
+    std::unique_ptr<AppIconLoader> arc_app_icon_loader(new ArcAppIconLoader(
+        profile_, extension_misc::EXTENSION_ICON_SMALL, this));
     app_icon_loaders_.push_back(std::move(arc_app_icon_loader));
   }
 
@@ -1885,6 +1907,8 @@
       continue;
     ash::ShelfItem item = model_->items()[index];
     item.image = image;
+    if (arc_deferred_launcher_)
+      arc_deferred_launcher_->MaybeApplySpinningEffect(id, &item.image);
     model_->Set(index, item);
     // It's possible we're waiting on more than one item, so don't break.
   }
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
index feb9eac7..160e4fe 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl.h
@@ -132,6 +132,7 @@
       content::WebContents* web_contents) const override;
   BrowserShortcutLauncherItemController*
   GetBrowserShortcutLauncherItemController() override;
+  void MayUpdateBrowserShortcutItem() override;
   LauncherItemController* GetLauncherItemController(
       const ash::ShelfID id) override;
   bool IsBrowserFromActiveUser(Browser* browser) override;
@@ -172,8 +173,8 @@
                       const std::string& app_id) override;
   void OnAppUpdated(content::BrowserContext* browser_context,
                     const std::string& app_id) override;
-  void OnAppUninstalled(content::BrowserContext* browser_context,
-                        const std::string& app_id) override;
+  void OnAppUninstalledPrepared(content::BrowserContext* browser_context,
+                                const std::string& app_id) override;
 
  protected:
   // Creates a new app shortcut item and controller on the shelf at |index|.
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
index 89dc087..3477966c 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -6,7 +6,7 @@
 
 #include <stddef.h>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_constants.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/wm/window_state.h"
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
index d6ae98a..e856164 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_unittest.cc
@@ -13,7 +13,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_item_delegate_manager.h"
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/shelf/shelf_model_observer.h"
@@ -2742,7 +2742,9 @@
   InitLauncherControllerWithBrowser();
   // App list and Browser shortcut ShelfItems are added.
   EXPECT_EQ(2, model_observer_->added());
-  EXPECT_EQ(1, model_observer_->changed());
+  // Browser shortcut item changed twice because the browser shortcut needs to
+  // be updated according to the ARC status when attaching profile.
+  EXPECT_EQ(2, model_observer_->changed());
 
   const std::string app_id = extension1_->id();
   // app_icon_loader is owned by ChromeLauncherControllerImpl.
@@ -2759,7 +2761,7 @@
       app_panel_controller, app_id, ash::STATUS_RUNNING);
   int panel_index = model_observer_->last_index();
   EXPECT_EQ(3, model_observer_->added());
-  EXPECT_EQ(1, model_observer_->changed());
+  EXPECT_EQ(2, model_observer_->changed());
   EXPECT_EQ(1, app_icon_loader->fetch_count());
   model_observer_->clear_counts();
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
index 6ad8b94b..9b38397 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.cc
@@ -227,6 +227,10 @@
   return nullptr;
 }
 
+void ChromeLauncherControllerMus::MayUpdateBrowserShortcutItem() {
+  NOTIMPLEMENTED();
+}
+
 LauncherItemController* ChromeLauncherControllerMus::GetLauncherItemController(
     const ash::ShelfID id) {
   NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
index 5ae8f3fb..0552251 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_mus.h
@@ -80,6 +80,7 @@
       content::WebContents* web_contents) const override;
   BrowserShortcutLauncherItemController*
   GetBrowserShortcutLauncherItemController() override;
+  void MayUpdateBrowserShortcutItem() override;
   LauncherItemController* GetLauncherItemController(
       const ash::ShelfID id) override;
   bool IsBrowserFromActiveUser(Browser* browser) override;
diff --git a/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc b/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc
index a6c0806b..8df9c679 100644
--- a/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_mash_shelf_controller.cc
@@ -95,7 +95,7 @@
 
   if (arc::ArcAuthService::IsAllowedForProfile(profile)) {
     std::unique_ptr<AppIconLoader> arc_app_icon_loader(new ArcAppIconLoader(
-        profile, extension_misc::EXTENSION_ICON_SMALL, nullptr, this));
+        profile, extension_misc::EXTENSION_ICON_SMALL, this));
     app_icon_loaders_.push_back(std::move(arc_app_icon_loader));
   }
 
diff --git a/chrome/browser/ui/ash/launcher/launcher_app_updater.h b/chrome/browser/ui/ash/launcher/launcher_app_updater.h
index ef8ae4b3..fb383e6 100644
--- a/chrome/browser/ui/ash/launcher/launcher_app_updater.h
+++ b/chrome/browser/ui/ash/launcher/launcher_app_updater.h
@@ -19,11 +19,14 @@
   class Delegate {
    public:
     virtual void OnAppInstalled(content::BrowserContext* browser_context,
-                                const std::string& app_id) = 0;
+                                const std::string& app_id) {}
     virtual void OnAppUpdated(content::BrowserContext* browser_context,
-                              const std::string& app_id) = 0;
+                              const std::string& app_id) {}
+    virtual void OnAppUninstalledPrepared(
+        content::BrowserContext* browser_context,
+        const std::string& app_id) {}
     virtual void OnAppUninstalled(content::BrowserContext* browser_context,
-                                  const std::string& app_id) = 0;
+                                  const std::string& app_id) {}
 
    protected:
     virtual ~Delegate() {}
diff --git a/chrome/browser/ui/ash/launcher/launcher_arc_app_updater.cc b/chrome/browser/ui/ash/launcher/launcher_arc_app_updater.cc
index 279b01df..503d910 100644
--- a/chrome/browser/ui/ash/launcher/launcher_arc_app_updater.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_arc_app_updater.cc
@@ -26,5 +26,6 @@
 }
 
 void LauncherArcAppUpdater::OnAppRemoved(const std::string& app_id) {
+  delegate()->OnAppUninstalledPrepared(browser_context(), app_id);
   delegate()->OnAppUninstalled(browser_context(), app_id);
 }
diff --git a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc
index adf3b07..4137de12 100644
--- a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc
@@ -4,17 +4,29 @@
 
 #include "chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h"
 
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/extensions/extension_constants.h"
 #include "extensions/browser/extension_registry.h"
 
 LauncherExtensionAppUpdater::LauncherExtensionAppUpdater(
     Delegate* delegate,
     content::BrowserContext* browser_context)
     : LauncherAppUpdater(delegate, browser_context) {
-  extensions::ExtensionRegistry::Get(browser_context)->AddObserver(this);
+  StartObservingExtensionRegistry();
+
+  arc::ArcAuthService* arc_auth_service = arc::ArcAuthService::Get();
+  // ArcAuthService may not be available for some unit tests.
+  if (arc_auth_service)
+    arc_auth_service->AddObserver(this);
 }
 
 LauncherExtensionAppUpdater::~LauncherExtensionAppUpdater() {
-  extensions::ExtensionRegistry::Get(browser_context())->RemoveObserver(this);
+  StopObservingExtensionRegistry();
+
+  arc::ArcAuthService* arc_auth_service = arc::ArcAuthService::Get();
+  if (arc_auth_service)
+    arc_auth_service->RemoveObserver(this);
 }
 
 void LauncherExtensionAppUpdater::OnExtensionLoaded(
@@ -28,7 +40,66 @@
     const extensions::Extension* extension,
     extensions::UnloadedExtensionInfo::Reason reason) {
   if (reason == extensions::UnloadedExtensionInfo::REASON_UNINSTALL)
-    delegate()->OnAppUninstalled(browser_context, extension->id());
+    delegate()->OnAppUninstalledPrepared(browser_context, extension->id());
   else
     delegate()->OnAppUpdated(browser_context, extension->id());
 }
+
+void LauncherExtensionAppUpdater::OnExtensionUninstalled(
+    content::BrowserContext* browser_context,
+    const extensions::Extension* extension,
+    extensions::UninstallReason reason) {
+  delegate()->OnAppUninstalled(browser_context, extension->id());
+}
+
+void LauncherExtensionAppUpdater::OnShutdown(
+    extensions::ExtensionRegistry* registry) {
+  DCHECK_EQ(extension_registry_, registry);
+  StopObservingExtensionRegistry();
+}
+
+void LauncherExtensionAppUpdater::OnOptInChanged(
+    arc::ArcAuthService::State state) {
+  if (!chromeos::ProfileHelper::IsPrimaryProfile(
+          Profile::FromBrowserContext(browser_context()))) {
+    return;
+  }
+  UpdateHostedApps();
+}
+
+void LauncherExtensionAppUpdater::StartObservingExtensionRegistry() {
+  DCHECK(!extension_registry_);
+  extension_registry_ = extensions::ExtensionRegistry::Get(browser_context());
+  extension_registry_->AddObserver(this);
+}
+
+void LauncherExtensionAppUpdater::StopObservingExtensionRegistry() {
+  if (!extension_registry_)
+    return;
+  extension_registry_->RemoveObserver(this);
+  extension_registry_ = nullptr;
+}
+
+void LauncherExtensionAppUpdater::UpdateHostedApps() {
+  if (!extension_registry_)
+    return;
+
+  UpdateHostedApps(extension_registry_->enabled_extensions());
+  UpdateHostedApps(extension_registry_->disabled_extensions());
+  UpdateHostedApps(extension_registry_->terminated_extensions());
+  UpdateHostedApp(extension_misc::kChromeAppId);
+}
+
+void LauncherExtensionAppUpdater::UpdateHostedApps(
+    const extensions::ExtensionSet& extensions) {
+  content::BrowserContext* context = browser_context();
+  extensions::ExtensionSet::const_iterator it;
+  for (it = extensions.begin(); it != extensions.end(); ++it) {
+    if ((*it)->is_hosted_app())
+      delegate()->OnAppUpdated(context, (*it)->id());
+  }
+}
+
+void LauncherExtensionAppUpdater::UpdateHostedApp(const std::string& app_id) {
+  delegate()->OnAppUpdated(browser_context(), app_id);
+}
diff --git a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h
index 8c11fff..b39b3b71 100644
--- a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h
+++ b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h
@@ -6,12 +6,18 @@
 #define CHROME_BROWSER_UI_ASH_LAUNCHER_LAUNCHER_EXTENSION_APP_UPDATER_H_
 
 #include "base/macros.h"
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
 #include "chrome/browser/ui/ash/launcher/launcher_app_updater.h"
 #include "extensions/browser/extension_registry_observer.h"
 
+namespace extensions {
+class ExtensionSet;
+}  // namespace extensions
+
 class LauncherExtensionAppUpdater
     : public LauncherAppUpdater,
-      public extensions::ExtensionRegistryObserver {
+      public extensions::ExtensionRegistryObserver,
+      public arc::ArcAuthService::Observer {
  public:
   LauncherExtensionAppUpdater(Delegate* delegate,
                               content::BrowserContext* browser_context);
@@ -24,8 +30,24 @@
       content::BrowserContext* browser_context,
       const extensions::Extension* extension,
       extensions::UnloadedExtensionInfo::Reason reason) override;
+  void OnExtensionUninstalled(content::BrowserContext* browser_context,
+                              const extensions::Extension* extension,
+                              extensions::UninstallReason reason) override;
+  void OnShutdown(extensions::ExtensionRegistry* registry) override;
+
+  // arc::ArcAuthService::Observer:
+  void OnOptInChanged(arc::ArcAuthService::State state) override;
 
  private:
+  void StartObservingExtensionRegistry();
+  void StopObservingExtensionRegistry();
+
+  void UpdateHostedApps();
+  void UpdateHostedApps(const extensions::ExtensionSet& extensions);
+  void UpdateHostedApp(const std::string& app_id);
+
+  extensions::ExtensionRegistry* extension_registry_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(LauncherExtensionAppUpdater);
 };
 
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
index 3eaa068..ee399f8 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/multi_profile_uma.h"
 #include "ash/shell.h"
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
index a8482797..ab3f08b 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/window_state.h"
diff --git a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
index 32fed2c..0c741b3 100644
--- a/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
+++ b/chrome/browser/ui/ash/system_tray_delegate_chromeos.cc
@@ -12,7 +12,7 @@
 #include <utility>
 #include <vector>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/session/session_state_delegate.h"
 #include "ash/common/session/session_state_observer.h"
 #include "ash/common/shell_window_ids.h"
diff --git a/chrome/browser/ui/ash/volume_controller_browsertest_chromeos.cc b/chrome/browser/ui/ash/volume_controller_browsertest_chromeos.cc
index b783723..d20dae1 100644
--- a/chrome/browser/ui/ash/volume_controller_browsertest_chromeos.cc
+++ b/chrome/browser/ui/ash/volume_controller_browsertest_chromeos.cc
@@ -5,8 +5,8 @@
 #include <memory>
 #include <vector>
 
-#include "ash/ash_switches.h"
 #include "ash/common/accessibility_delegate.h"
+#include "ash/common/ash_switches.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "chrome/browser/browser_process.h"
diff --git a/chrome/browser/ui/ash/volume_controller_chromeos.cc b/chrome/browser/ui/ash/volume_controller_chromeos.cc
index 1dc51a7..58e4478c 100644
--- a/chrome/browser/ui/ash/volume_controller_chromeos.cc
+++ b/chrome/browser/ui/ash/volume_controller_chromeos.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/ui/ash/volume_controller_chromeos.h"
 
-#include "ash/ash_switches.h"
 #include "ash/audio/sounds.h"
+#include "ash/common/ash_switches.h"
 #include "base/command_line.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/system_private/system_private_api.h"
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 14a9336..64ab742 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -229,7 +229,7 @@
 #endif
 
 #if defined(USE_ASH)
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/shell.h"
 #endif
 
diff --git a/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc b/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc
index 814babe..eb7e53ee 100644
--- a/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc
+++ b/chrome/browser/ui/libgtk2ui/native_theme_gtk2.cc
@@ -400,14 +400,11 @@
       return GetSystemColor(kColorId_TextfieldSelectionColor);
     case kColorId_ResultsTableNormalDimmedText:
     case kColorId_ResultsTableHoveredDimmedText:
-    case kColorId_ResultsTableNormalHeadline:
-    case kColorId_ResultsTableHoveredHeadline:
       return color_utils::AlphaBlend(
           GetSystemColor(kColorId_TextfieldDefaultColor),
           GetSystemColor(kColorId_TextfieldDefaultBackground),
           0x80);
     case kColorId_ResultsTableSelectedDimmedText:
-    case kColorId_ResultsTableSelectedHeadline:
       return color_utils::AlphaBlend(
           GetSystemColor(kColorId_TextfieldSelectionColor),
           GetSystemColor(kColorId_TextfieldDefaultBackground),
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
index 4ac5417..8a08bc8 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -4,8 +4,8 @@
 
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h"
 
-#include "ash/ash_switches.h"
 #include "ash/common/ash_constants.h"
+#include "ash/common/ash_switches.h"
 #include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
 #include "ash/frame/header_painter.h"
 #include "ash/shell.h"
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
index 91313a80..47b9016 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_ash_unittest.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_ash.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/shelf/shelf_types.h"
 #include "ash/root_window_controller.h"
 #include "ash/shelf/shelf_layout_manager.h"
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.cc b/chrome/browser/ui/views/infobars/confirm_infobar.cc
index c19ff78..2248818b 100644
--- a/chrome/browser/ui/views/infobars/confirm_infobar.cc
+++ b/chrome/browser/ui/views/infobars/confirm_infobar.cc
@@ -75,7 +75,7 @@
       if (ui::MaterialDesignController::IsModeMaterial()) {
         views::MdTextButton* button = CreateMdTextButton(
             this, delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_OK));
-        button->SetCallToAction(views::MdTextButton::STRONG_CALL_TO_ACTION);
+        button->SetCallToAction(true);
         ok_button_ = button;
       } else {
         ok_button_ = CreateTextButton(
@@ -96,8 +96,8 @@
             this,
             delegate->GetButtonLabel(ConfirmInfoBarDelegate::BUTTON_CANCEL));
         // Apply CTA only if the cancel button is the only button.
-        if (delegate->GetButtons() == ConfirmInfoBarDelegate::BUTTON_CANCEL)
-          button->SetCallToAction(views::MdTextButton::STRONG_CALL_TO_ACTION);
+        button->SetCallToAction(delegate->GetButtons() ==
+                                ConfirmInfoBarDelegate::BUTTON_CANCEL);
         cancel_button_ = button;
       } else {
         cancel_button_ = CreateTextButton(
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index 1d7bfea..e288c4af 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -624,8 +624,11 @@
 
 gfx::ImageSkia OmniboxResultView::GetVectorIcon(
     gfx::VectorIconId icon_id) const {
-  return gfx::CreateVectorIcon(icon_id, 16, color_utils::DeriveDefaultIconColor(
-                                                GetColor(GetState(), TEXT)));
+  // For selected rows, paint the icon the same color as the text.
+  SkColor color = GetColor(GetState(), TEXT);
+  if (GetState() != SELECTED)
+    color = color_utils::DeriveDefaultIconColor(color);
+  return gfx::CreateVectorIcon(icon_id, 16, color);
 }
 
 bool OmniboxResultView::ShowOnlyKeywordMatch() const {
diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
index 185de83..6f262f9 100644
--- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc
@@ -1672,7 +1672,7 @@
     views::View** signin_content_view) {
   views::WebView* web_view =
       SigninViewControllerDelegateViews::CreateGaiaWebView(
-          this, view_mode_, browser_->profile(), access_point_);
+          this, view_mode_, browser_, access_point_);
 
   int message_id;
   switch (view_mode_) {
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
index e2b73c38..7d95a66 100644
--- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
+++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.cc
@@ -10,9 +10,11 @@
 #include "chrome/browser/signin/signin_promo.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/common/url_constants.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/signin/core/common/profile_management_switches.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
 #include "content/public/browser/render_widget_host_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/views/controls/webview/webview.h"
@@ -76,7 +78,12 @@
 }
 
 void SigninViewControllerDelegateViews::ResizeNativeView(int height) {
-  content_view_->SetPreferredSize(gfx::Size(kModalDialogWidth, height));
+  int max_height = browser_
+      ->window()
+      ->GetWebContentsModalDialogHost()
+      ->GetMaximumDialogSize().height();
+  content_view_->SetPreferredSize(
+      gfx::Size(kModalDialogWidth, std::min(height, max_height)));
   content_view_->Layout();
 
   if (wait_for_size_) {
@@ -96,18 +103,24 @@
 views::WebView* SigninViewControllerDelegateViews::CreateGaiaWebView(
     content::WebContentsDelegate* delegate,
     profiles::BubbleViewMode mode,
-    Profile* profile,
+    Browser* browser,
     signin_metrics::AccessPoint access_point) {
   GURL url =
-      signin::GetSigninURLFromBubbleViewMode(profile, mode, access_point);
+      signin::GetSigninURLFromBubbleViewMode(
+          browser->profile(), mode, access_point);
 
+  int max_height = browser
+      ->window()
+      ->GetWebContentsModalDialogHost()
+      ->GetMaximumDialogSize().height();
   // Adds Gaia signin webview.
   const gfx::Size pref_size =
       switches::UsePasswordSeparatedSigninFlow()
-          ? gfx::Size(kModalDialogWidth, kFixedGaiaViewHeight)
+          ? gfx::Size(kModalDialogWidth,
+                      std::min(kFixedGaiaViewHeight, max_height))
           : gfx::Size(kPasswordCombinedFixedGaiaViewWidth,
                       kPasswordCombinedFixedGaiaViewHeight);
-  views::WebView* web_view = new views::WebView(profile);
+  views::WebView* web_view = new views::WebView(browser->profile());
   web_view->LoadInitialURL(url);
 
   if (delegate)
@@ -124,11 +137,17 @@
 
 views::WebView*
 SigninViewControllerDelegateViews::CreateSyncConfirmationWebView(
-    Profile* profile) {
-  views::WebView* web_view = new views::WebView(profile);
+    Browser* browser) {
+  views::WebView* web_view = new views::WebView(browser->profile());
   web_view->LoadInitialURL(GURL(chrome::kChromeUISyncConfirmationURL));
+
+  int max_height = browser
+      ->window()
+      ->GetWebContentsModalDialogHost()
+      ->GetMaximumDialogSize().height();
   web_view->SetPreferredSize(
-      gfx::Size(kModalDialogWidth, kSyncConfirmationDialogHeight));
+      gfx::Size(kModalDialogWidth,
+                std::min(kSyncConfirmationDialogHeight, max_height)));
 
   return web_view;
 }
@@ -142,7 +161,7 @@
   return new SigninViewControllerDelegateViews(
       signin_view_controller,
       SigninViewControllerDelegateViews::CreateGaiaWebView(
-          nullptr, mode, browser->profile(), access_point),
+          nullptr, mode, browser, access_point),
       browser, false);
 }
 
@@ -152,7 +171,6 @@
     Browser* browser) {
   return new SigninViewControllerDelegateViews(
       signin_view_controller,
-      SigninViewControllerDelegateViews::CreateSyncConfirmationWebView(
-          browser->profile()),
+      SigninViewControllerDelegateViews::CreateSyncConfirmationWebView(browser),
       browser, true);
 }
diff --git a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
index 277cf77..70c9665 100644
--- a/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
+++ b/chrome/browser/ui/views/profiles/signin_view_controller_delegate_views.h
@@ -47,10 +47,10 @@
   static views::WebView* CreateGaiaWebView(
       content::WebContentsDelegate* delegate,
       profiles::BubbleViewMode mode,
-      Profile* profile,
+      Browser* browser,
       signin_metrics::AccessPoint access_point);
 
-  static views::WebView* CreateSyncConfirmationWebView(Profile* profile);
+  static views::WebView* CreateSyncConfirmationWebView(Browser* browser);
 
   // views::DialogDelegateView:
   views::View* GetContentsView() override;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index da14ef3a..462a0cd 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -20,6 +20,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
+#include "chrome/browser/platform_util.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -188,7 +189,8 @@
   // Resize the two windows so they're right next to each other.
   gfx::Rect work_area =
       display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
+          ->GetDisplayNearestWindow(platform_util::GetViewForWindow(
+              browser()->window()->GetNativeWindow()))
           .work_area();
   gfx::Size half_size =
       gfx::Size(work_area.width() / 3 - 10, work_area.height() / 2 - 10);
@@ -256,7 +258,7 @@
 
 #endif
 
-#if !defined(OS_CHROMEOS)
+#if !defined(OS_CHROMEOS) && defined(USE_AURA)
 
 // Following classes verify a crash scenario. Specifically on Windows when focus
 // changes it can trigger capture being lost. This was causing a crash in tab
@@ -374,6 +376,12 @@
     event_generator_.reset(
         new ui::test::EventGenerator(ash::Shell::GetPrimaryRootWindow()));
 #endif
+#if defined(OS_MACOSX)
+    // Currently MacViews' browser windows are shown in the background and could
+    // be obscured by other windows if there are any. This should be fixed in
+    // order to be consistent with other platforms.
+    EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
+#endif  // OS_MACOSX
   }
 
   InputSource input_source() const {
@@ -852,9 +860,11 @@
   EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX)
 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
 // compositor. crbug.com/331924
+// TODO(tapted,mblsha): Disabled as the Mac IsMaximized() behavior is not
+// consistent with other platforms. crbug.com/603562
 #define MAYBE_DetachFromFullsizeWindow DISABLED_DetachFromFullsizeWindow
 #else
 #define MAYBE_DetachFromFullsizeWindow DetachFromFullsizeWindow
@@ -866,7 +876,8 @@
   // Resize the browser window so that it is as big as the work area.
   gfx::Rect work_area =
       display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(browser()->window()->GetNativeWindow())
+          ->GetDisplayNearestWindow(platform_util::GetViewForWindow(
+              browser()->window()->GetNativeWindow()))
           .work_area();
   browser()->window()->SetBounds(work_area);
   const gfx::Rect initial_bounds(browser()->window()->GetBounds());
@@ -920,9 +931,11 @@
   EXPECT_FALSE(tab_strip2->GetWidget()->HasCapture());
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+#if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_MACOSX)
 // TODO(sky,sad): Disabled as it fails due to resize locks with a real
 // compositor. crbug.com/331924
+// TODO(tapted,mblsha): Disabled as the Mac IsMaximized() behavior is not
+// consistent with other platforms. crbug.com/603562
 #define MAYBE_DetachToOwnWindowFromMaximizedWindow \
   DISABLED_DetachToOwnWindowFromMaximizedWindow
 #else
@@ -1282,6 +1295,7 @@
   TabStrip* tab_strip = GetTabStripForBrowser(browser());
   browser()->tab_strip_model()->AddTabAtToSelection(0);
   browser()->tab_strip_model()->AddTabAtToSelection(1);
+  const gfx::Rect initial_bounds = browser()->window()->GetBounds();
 
   // Move to the first tab and drag it enough so that it would normally
   // detach.
@@ -1305,6 +1319,14 @@
 
   // Remaining browser window should not be maximized
   EXPECT_FALSE(browser()->window()->IsMaximized());
+
+  const gfx::Rect final_bounds = browser()->window()->GetBounds();
+  // Size unchanged, but it should have moved down.
+  EXPECT_EQ(initial_bounds.size(), final_bounds.size());
+  EXPECT_EQ(initial_bounds.origin().x(), final_bounds.origin().x());
+  // TODO(mblsha): Fails on MacViews because of crbug.com/518740
+  // EXPECT_EQ(initial_bounds.origin().y() + GetDetachY(tab_strip),
+  //           final_bounds.origin().y());
 }
 
 namespace {
@@ -1580,14 +1602,8 @@
   ASSERT_TRUE(TabDragController::IsActive());
   ASSERT_EQ(2u, browser_list->size());
 
-  // Add another tab. This should trigger exiting the nested loop. Add at the
-  // to exercise past crash when model/tabstrip got out of sync (474082).
-  content::WindowedNotificationObserver observer(
-      content::NOTIFICATION_LOAD_STOP,
-      content::NotificationService::AllSources());
   chrome::AddTabAt(browser_list->GetLastActive(), GURL(url::kAboutBlankURL),
                    0, false);
-  observer.Wait();
 }
 
 }  // namespace
@@ -1612,12 +1628,20 @@
   gfx::Point tab_0_center(
       GetCenterInScreenCoordinates(tab_strip->tab_at(0)));
   ASSERT_TRUE(PressInput(tab_0_center));
+
+  // Add another tab. This should trigger exiting the nested loop. Add at the
+  // beginning to exercise past crash when model/tabstrip got out of sync.
+  // crbug.com/474082
+  content::WindowedNotificationObserver observer(
+      content::NOTIFICATION_LOAD_STOP,
+      content::NotificationService::AllSources());
   ASSERT_TRUE(DragInputToNotifyWhenDone(
       tab_0_center.x(), tab_0_center.y() + GetDetachY(tab_strip),
       base::Bind(&CancelOnNewTabWhenDraggingStep2, this, browser_list)));
-  QuitWhenNotDragging();
+  observer.Wait();
 
   // Should be two windows and not dragging.
+  ASSERT_FALSE(tab_strip->IsDragSessionActive());
   ASSERT_FALSE(TabDragController::IsActive());
   ASSERT_EQ(2u, browser_list->size());
   for (auto* browser : *BrowserList::GetInstance()) {
@@ -2201,6 +2225,7 @@
   }
 
   void QuitWhenNotDragging() {
+    DCHECK(TabDragController::IsActive());
     test::QuitWhenNotDraggingImpl();
     base::MessageLoop::current()->Run();
   }
diff --git a/chrome/browser/ui/views/tabs/window_finder_mac.mm b/chrome/browser/ui/views/tabs/window_finder_mac.mm
index 8c1a344f..ab9555d42 100644
--- a/chrome/browser/ui/views/tabs/window_finder_mac.mm
+++ b/chrome/browser/ui/views/tabs/window_finder_mac.mm
@@ -4,9 +4,32 @@
 
 #include "chrome/browser/ui/views/tabs/window_finder.h"
 
+#import <AppKit/AppKit.h>
+
+#include "ui/gfx/geometry/point.h"
+#import "ui/gfx/mac/coordinate_conversion.h"
+
 gfx::NativeWindow WindowFinder::GetLocalProcessWindowAtPoint(
     const gfx::Point& screen_point,
     const std::set<gfx::NativeWindow>& ignore) {
-  NOTIMPLEMENTED();
-  return NULL;
+  const NSPoint ns_point = gfx::ScreenPointToNSPoint(screen_point);
+
+  // Note: [NSApp orderedWindows] doesn't include NSPanels.
+  for (NSWindow* window : [NSApp orderedWindows]) {
+    if (ignore.count(window))
+      continue;
+
+    if (![window isOnActiveSpace])
+      continue;
+
+    // NativeWidgetMac::Close() calls -orderOut: on NSWindows before actually
+    // closing them.
+    if (![window isVisible])
+      continue;
+
+    if (NSPointInRect(ns_point, [window frame]))
+      return window;
+  }
+
+  return nil;
 }
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
index a5530f6..6ab2dace 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.cc
@@ -102,6 +102,12 @@
   return buttons;
 }
 
+int ToolbarActionsBarBubbleViews::GetDefaultDialogButton() const {
+  // TODO(estade): we should set a default where approprite. See
+  // http://crbug.com/621122
+  return ui::DIALOG_BUTTON_NONE;
+}
+
 base::string16 ToolbarActionsBarBubbleViews::GetDialogButtonLabel(
     ui::DialogButton button) const {
   return button == ui::DIALOG_BUTTON_OK ? delegate_->GetActionButtonText()
diff --git a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
index ff89116..260a0fd 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h
@@ -43,6 +43,7 @@
   bool Accept() override;
   bool Close() override;
   int GetDialogButtons() const override;
+  int GetDefaultDialogButton() const override;
   base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
   void Init() override;
 
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index e4ae4c2..2bd1259 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -256,6 +256,14 @@
       web_ui, service, dom_distiller::kDomDistillerScheme);
 }
 
+#if !defined(OS_ANDROID)
+template<>
+WebUIController* NewWebUI<settings::MdSettingsUI>(WebUI* web_ui,
+                                                  const GURL& url) {
+  return new settings::MdSettingsUI(web_ui, url);
+}
+#endif
+
 #if defined(ENABLE_EXTENSIONS)
 // Only create ExtensionWebUI for URLs that are allowed extension bindings,
 // hosted by actual tabs.
diff --git a/chrome/browser/ui/webui/offline_internals_ui.cc b/chrome/browser/ui/webui/offline_internals_ui.cc
index fe5f4ccc3..d992c0de 100644
--- a/chrome/browser/ui/webui/offline_internals_ui.cc
+++ b/chrome/browser/ui/webui/offline_internals_ui.cc
@@ -45,10 +45,10 @@
   void HandleDeleteSelectedPages(const base::ListValue* args);
 
   // Load Request Queue info.
-  void HandleGetRequestQueueInfo(const base::ListValue* args);
+  void HandleGetRequestQueue(const base::ListValue* args);
 
   // Load Stored pages info.
-  void HandleGetStoredPagesInfo(const base::ListValue* args);
+  void HandleGetStoredPages(const base::ListValue* args);
 
   // Callback for async GetAllPages calls.
   void HandleStoredPagesCallback(
@@ -218,7 +218,7 @@
   ResolveJavascriptCallback(base::StringValue(callback_id), save_page_requests);
 }
 
-void OfflineInternalsUIMessageHandler::HandleGetRequestQueueInfo(
+void OfflineInternalsUIMessageHandler::HandleGetRequestQueue(
     const base::ListValue* args) {
   AllowJavascript();
   std::string callback_id;
@@ -234,7 +234,7 @@
   }
 }
 
-void OfflineInternalsUIMessageHandler::HandleGetStoredPagesInfo(
+void OfflineInternalsUIMessageHandler::HandleGetStoredPages(
     const base::ListValue* args) {
   AllowJavascript();
   std::string callback_id;
@@ -260,12 +260,12 @@
       base::Bind(&OfflineInternalsUIMessageHandler::HandleDeleteSelectedPages,
                  weak_ptr_factory_.GetWeakPtr()));
   web_ui()->RegisterMessageCallback(
-      "getRequestQueueInfo",
-      base::Bind(&OfflineInternalsUIMessageHandler::HandleGetRequestQueueInfo,
+      "getRequestQueue",
+      base::Bind(&OfflineInternalsUIMessageHandler::HandleGetRequestQueue,
                  weak_ptr_factory_.GetWeakPtr()));
   web_ui()->RegisterMessageCallback(
-      "getStoredPagesInfo",
-      base::Bind(&OfflineInternalsUIMessageHandler::HandleGetStoredPagesInfo,
+      "getStoredPages",
+      base::Bind(&OfflineInternalsUIMessageHandler::HandleGetStoredPages,
                  weak_ptr_factory_.GetWeakPtr()));
 
   // Get the offline page model associated with this web ui.
@@ -290,6 +290,8 @@
                                IDR_OFFLINE_INTERNALS_CSS);
   html_source->AddResourcePath("offline_internals.js",
                                IDR_OFFLINE_INTERNALS_JS);
+  html_source->AddResourcePath("offline_internals_browser_proxy.js",
+                               IDR_OFFLINE_INTERNALS_BROWSER_PROXY_JS);
   html_source->SetDefaultResource(IDR_OFFLINE_INTERNALS_HTML);
 
   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index 0d435e05..64d2b45 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -111,7 +111,7 @@
 #endif
 
 #if defined(OS_CHROMEOS)
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/system/chromeos/devicetype_utils.h"
 #include "ash/desktop_background/user_wallpaper_delegate.h"
 #include "ash/shell.h"
@@ -1495,8 +1495,8 @@
 }
 
 void BrowserOptionsHandler::OnSystemTimezoneAutomaticDetectionPolicyChanged() {
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          chromeos::switches::kEnableSystemTimezoneAutomaticDetectionPolicy)) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          chromeos::switches::kDisableSystemTimezoneAutomaticDetectionPolicy)) {
     return;
   }
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.cc b/chrome/browser/ui/webui/settings/md_settings_ui.cc
index b0b6876..0cf7732 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.cc
@@ -53,7 +53,7 @@
 
 namespace settings {
 
-MdSettingsUI::MdSettingsUI(content::WebUI* web_ui)
+MdSettingsUI::MdSettingsUI(content::WebUI* web_ui, const GURL& url)
     : content::WebUIController(web_ui),
       WebContentsObserver(web_ui->GetWebContents()) {
   Profile* profile = Profile::FromWebUI(web_ui);
@@ -88,11 +88,6 @@
 
   // Host must be derived from the visible URL, since this might be serving
   // either chrome://settings or chrome://md-settings.
-  GURL url = web_ui->GetWebContents()->GetVisibleURL();
-
-  if (url.SchemeIs(content::kViewSourceScheme))
-    url = GURL(url.GetContent());
-
   CHECK(url.GetOrigin() == GURL(chrome::kChromeUISettingsURL).GetOrigin() ||
         url.GetOrigin() == GURL(chrome::kChromeUIMdSettingsURL).GetOrigin());
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui.h b/chrome/browser/ui/webui/settings/md_settings_ui.h
index 8c48fae..6f49d40 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui.h
+++ b/chrome/browser/ui/webui/settings/md_settings_ui.h
@@ -12,6 +12,8 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
 
+class GURL;
+
 namespace settings {
 
 class SettingsPageUIHandler;
@@ -20,7 +22,7 @@
 class MdSettingsUI : public content::WebUIController,
                      public content::WebContentsObserver {
  public:
-  explicit MdSettingsUI(content::WebUI* web_ui);
+  MdSettingsUI(content::WebUI* web_ui, const GURL& url);
   ~MdSettingsUI() override;
 
   // content::WebContentsObserver:
diff --git a/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc b/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
index 3407bfe..1cbaa43 100644
--- a/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_ui_browsertest.cc
@@ -4,16 +4,33 @@
 
 #include <string>
 
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_commands.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/test/browser_test_utils.h"
+#include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
 
 typedef InProcessBrowserTest MdSettingsBrowserTest;
 
+using ui_test_utils::NavigateToURL;
+using content::WaitForLoadStop;
+
 IN_PROC_BROWSER_TEST_F(MdSettingsBrowserTest, ViewSourceDoesntCrash) {
-  ui_test_utils::NavigateToURL(browser(),
+  NavigateToURL(browser(),
       GURL(content::kViewSourceScheme + std::string(":") +
            chrome::kChromeUIMdSettingsURL));
 }
+
+IN_PROC_BROWSER_TEST_F(MdSettingsBrowserTest, BackForwardDoesntCrash) {
+  NavigateToURL(browser(), GURL(chrome::kChromeUIMdSettingsURL));
+
+  NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL));
+
+  chrome::GoBack(browser(), CURRENT_TAB);
+  WaitForLoadStop(browser()->tab_strip_model()->GetActiveWebContents());
+}
diff --git a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
index ac540c0..a5935b63 100644
--- a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.cc
@@ -26,10 +26,6 @@
       remover_(nullptr),
       should_show_history_footer_(false),
       weak_ptr_factory_(this) {
-  PrefService* prefs = Profile::FromWebUI(webui)->GetPrefs();
-  clear_plugin_lso_data_enabled_.Init(prefs::kClearPluginLSODataEnabled, prefs);
-  pepper_flash_settings_enabled_.Init(prefs::kPepperFlashSettingsEnabled,
-                                      prefs);
   sync_service_ =
         ProfileSyncServiceFactory::GetForProfile(Profile::FromWebUI(webui));
 }
@@ -53,8 +49,9 @@
 
 void ClearBrowsingDataHandler::OnJavascriptAllowed() {
   PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
-  allow_deleting_browser_history_.Init(
-      prefs::kAllowDeletingBrowserHistory, prefs,
+  profile_pref_registrar_.Init(prefs);
+  profile_pref_registrar_.Add(
+      prefs::kAllowDeletingBrowserHistory,
       base::Bind(&ClearBrowsingDataHandler::OnBrowsingHistoryPrefChanged,
                  base::Unretained(this)));
 
@@ -63,7 +60,7 @@
 }
 
 void ClearBrowsingDataHandler::OnJavascriptDisallowed() {
-  allow_deleting_browser_history_.Destroy();
+  profile_pref_registrar_.RemoveAll();
   sync_service_observer_.RemoveAll();
 }
 
@@ -80,11 +77,11 @@
 
   int site_data_mask = BrowsingDataRemover::REMOVE_SITE_DATA;
   // Don't try to clear LSO data if it's not supported.
-  if (!*clear_plugin_lso_data_enabled_)
+  if (!prefs->GetBoolean(prefs::kClearPluginLSODataEnabled))
     site_data_mask &= ~BrowsingDataRemover::REMOVE_PLUGIN_DATA;
 
   int remove_mask = 0;
-  if (*allow_deleting_browser_history_) {
+  if (prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory)) {
     if (prefs->GetBoolean(prefs::kDeleteBrowsingHistory))
       remove_mask |= BrowsingDataRemover::REMOVE_HISTORY;
     if (prefs->GetBoolean(prefs::kDeleteDownloadHistory))
@@ -108,7 +105,7 @@
 
   // Clearing Content Licenses is only supported in Pepper Flash.
   if (prefs->GetBoolean(prefs::kDeauthorizeContentLicenses) &&
-      *pepper_flash_settings_enabled_) {
+      prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled)) {
     remove_mask |= BrowsingDataRemover::REMOVE_CONTENT_LICENSES;
   }
 
@@ -174,7 +171,9 @@
   CallJavascriptFunction(
       "cr.webUIListenerCallback",
       base::StringValue("browsing-history-pref-changed"),
-      base::FundamentalValue(*allow_deleting_browser_history_));
+      base::FundamentalValue(
+          Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
+              prefs::kAllowDeletingBrowserHistory)));
 }
 
 void ClearBrowsingDataHandler::HandleInitialize(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h
index 4a7c66d..a4a605d 100644
--- a/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_clear_browsing_data_handler.h
@@ -12,7 +12,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/browser_sync/browser/profile_sync_service.h"
-#include "components/prefs/pref_member.h"
+#include "components/prefs/pref_change_registrar.h"
 
 namespace base {
 class ListValue;
@@ -75,15 +75,8 @@
   // can only be one such request in-flight.
   std::string webui_callback_id_;
 
-  // Keeps track of whether clearing LSO data is supported.
-  BooleanPrefMember clear_plugin_lso_data_enabled_;
-
-  // Keeps track of whether Pepper Flash is enabled and thus Flapper-specific
-  // settings and removal options (e.g. Content Licenses) are available.
-  BooleanPrefMember pepper_flash_settings_enabled_;
-
-  // Keeps track of whether deleting browsing history and downloads is allowed.
-  BooleanPrefMember allow_deleting_browser_history_;
+  // Used to listen for pref changes to allow / disallow deleting browsing data.
+  PrefChangeRegistrar profile_pref_registrar_;
 
   // Whether the sentence about other forms of history stored in user's account
   // should be displayed in the footer. This value is retrieved asynchronously,
diff --git a/chrome/browser/ui/webui/settings/settings_default_browser_handler.cc b/chrome/browser/ui/webui/settings/settings_default_browser_handler.cc
index bee0953..4a976a4 100644
--- a/chrome/browser/ui/webui/settings/settings_default_browser_handler.cc
+++ b/chrome/browser/ui/webui/settings/settings_default_browser_handler.cc
@@ -17,8 +17,12 @@
 
 namespace {
 
-bool IsDisabledByPolicy(const BooleanPrefMember& pref) {
-  return pref.IsManaged() && !pref.GetValue();
+bool DefaultBrowserIsDisabledByPolicy() {
+  const PrefService::Preference* pref =
+      g_browser_process->local_state()->FindPreference(
+          prefs::kDefaultBrowserSettingEnabled);
+  DCHECK(pref);
+  return pref->IsManaged() && !pref->GetValue();
 }
 
 }  // namespace
@@ -44,14 +48,16 @@
 }
 
 void DefaultBrowserHandler::OnJavascriptAllowed() {
-  default_browser_policy_.Init(
-      prefs::kDefaultBrowserSettingEnabled, g_browser_process->local_state(),
+  PrefService* prefs = g_browser_process->local_state();
+  local_state_pref_registrar_.Init(prefs);
+  local_state_pref_registrar_.Add(
+      prefs::kDefaultBrowserSettingEnabled,
       base::Bind(&DefaultBrowserHandler::RequestDefaultBrowserState,
                  base::Unretained(this), nullptr));
 }
 
 void DefaultBrowserHandler::OnJavascriptDisallowed() {
-  default_browser_policy_.Destroy();
+  local_state_pref_registrar_.RemoveAll();
 }
 
 void DefaultBrowserHandler::RequestDefaultBrowserState(
@@ -62,7 +68,7 @@
 }
 
 void DefaultBrowserHandler::SetAsDefaultBrowser(const base::ListValue* args) {
-  CHECK(!IsDisabledByPolicy(default_browser_policy_));
+  CHECK(!DefaultBrowserIsDisabledByPolicy());
 
   base::RecordAction(base::UserMetricsAction("Options_SetAsDefaultBrowser"));
   UMA_HISTOGRAM_COUNTS("Settings.StartSetAsDefault", true);
@@ -85,7 +91,7 @@
   base::FundamentalValue is_default(state == shell_integration::IS_DEFAULT);
   base::FundamentalValue can_be_default(
       state != shell_integration::UNKNOWN_DEFAULT &&
-      !IsDisabledByPolicy(default_browser_policy_) &&
+      !DefaultBrowserIsDisabledByPolicy() &&
       shell_integration::CanSetAsDefaultBrowser());
 
   CallJavascriptFunction("Settings.updateDefaultBrowserState", is_default,
diff --git a/chrome/browser/ui/webui/settings/settings_default_browser_handler.h b/chrome/browser/ui/webui/settings/settings_default_browser_handler.h
index 05753eb..cc2f4ec 100644
--- a/chrome/browser/ui/webui/settings/settings_default_browser_handler.h
+++ b/chrome/browser/ui/webui/settings/settings_default_browser_handler.h
@@ -10,7 +10,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
-#include "components/prefs/pref_member.h"
+#include "components/prefs/pref_change_registrar.h"
 
 namespace base {
 class ListValue;
@@ -51,8 +51,8 @@
   scoped_refptr<shell_integration::DefaultBrowserWorker>
       default_browser_worker_;
 
-  // Policy setting to determine if default browser setting is managed.
-  BooleanPrefMember default_browser_policy_;
+  // Used to listen for changes to if the default browser setting is managed.
+  PrefChangeRegistrar local_state_pref_registrar_;
 
   // Used to invalidate the DefaultBrowserWorker callback.
   base::WeakPtrFactory<DefaultBrowserHandler> weak_ptr_factory_;
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 86ddd6f..00449b2a6 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -726,11 +726,6 @@
                 'service/service_utility_process_host.cc',
                 'service/service_utility_process_host.h',
               ],
-              'deps': [
-                # TODO(fdoray): Remove this once the PreRead field trial has
-                # expired. crbug.com/577698
-                '../components/components.gyp:startup_metric_utils_win',
-              ],
             }],
           ],
         },
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 7b6f035..ca2f15c5 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -196,6 +196,8 @@
         'browser/chromeos/extensions/extension_system_event_observer.h',
         'browser/chromeos/extensions/external_cache.cc',
         'browser/chromeos/extensions/external_cache.h',
+        'browser/chromeos/extensions/gfx_utils.cc',
+        'browser/chromeos/extensions/gfx_utils.h',
         'browser/chromeos/extensions/ime_menu_event_router.cc',
         'browser/chromeos/extensions/ime_menu_event_router.h',
         'browser/chromeos/extensions/info_private_api.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 366774a..de33ffd 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -506,9 +506,6 @@
           ],
           'dependencies': [
             '<(DEPTH)/components/components.gyp:dom_distiller_core',  # Needed by chrome_content_client.cc.
-            # TODO(fdoray): Remove this once the PreRead field trial has
-            # expired. crbug.com/577698
-            '<(DEPTH)/components/components.gyp:startup_metric_utils_win',
           ],
           'all_dependent_settings': {
             'msvs_settings': {
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi
index 2ad53fd..c144fe97 100644
--- a/chrome/chrome_exe.gypi
+++ b/chrome/chrome_exe.gypi
@@ -544,7 +544,7 @@
                 '../crypto/crypto.gyp:crypto_nacl_win64',
                 '../ipc/ipc.gyp:ipc_win64',
                 '../sandbox/sandbox.gyp:sandbox_win64',
-                '../third_party/kasko/kasko.gyp:kasko_features',
+                '../third_party/kasko/kasko.gyp:kasko',
               ],
               'defines': [
                 '<@(nacl_win64_defines)',
diff --git a/chrome/chrome_installer_util.gypi b/chrome/chrome_installer_util.gypi
index c9def26..41a88517 100644
--- a/chrome/chrome_installer_util.gypi
+++ b/chrome/chrome_installer_util.gypi
@@ -123,9 +123,6 @@
             '<(DEPTH)/chrome/common_constants.gyp:common_constants',
             '<(DEPTH)/components/components.gyp:base32',
             '<(DEPTH)/components/components.gyp:metrics',
-            # TODO(fdoray): Remove this once the PreRead field trial has
-            # expired. crbug.com/577698
-            '<(DEPTH)/components/components.gyp:startup_metric_utils_win',
             '<(DEPTH)/components/components.gyp:variations',
             '<(DEPTH)/courgette/courgette.gyp:courgette_lib',
             '<(DEPTH)/crypto/crypto.gyp:crypto',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 402295e6..56b519f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -698,6 +698,7 @@
       '../ui/base/ime/chromeos/input_method_whitelist.cc',
       '../ui/base/ime/chromeos/input_method_whitelist.h',
       'browser/apps/custom_launcher_page_browsertest_views.cc',
+      'browser/chromeos/accessibility/accessibility_highlight_manager_browsertest.cc',
       'browser/chromeos/accessibility/accessibility_manager_browsertest.cc',
       'browser/chromeos/accessibility/magnification_manager_browsertest.cc',
       'browser/chromeos/accessibility/speech_monitor.cc',
@@ -1752,7 +1753,6 @@
               'sources!': [
                 # Aura depended tests.
                 'browser/ui/views/bookmarks/bookmark_bar_view_test.cc',
-                'browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc',
               ]
             }, {
               'sources': [ '<@(chrome_interactive_ui_test_cocoa_sources)' ],
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 81f3ba12..b7db17c 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -221,14 +221,6 @@
       sources += rebase_path(gypi_values.chrome_common_service_process_sources,
                              ".",
                              "//chrome")
-
-      if (is_win) {
-        deps = [
-          # TODO(fdoray): Remove this once the PreRead field trial has expired.
-          # crbug.com/577698
-          "//components/startup_metric_utils/common",
-        ]
-      }
     }
   }
 
diff --git a/chrome/common/DEPS b/chrome/common/DEPS
index 2f6af27..f9d9f8e 100644
--- a/chrome/common/DEPS
+++ b/chrome/common/DEPS
@@ -24,9 +24,6 @@
   "+components/policy/core/common",
   "+components/printing/common",
   "+components/signin/core/common",
-  # TODO(fdoray): Remove this once the PreRead field trial has expired.
-  # crbug.com/577698
-  "+components/startup_metric_utils/common",
   "+components/strings/grit",
   "+components/translate/core/common",
   "+components/url_formatter",
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 71b91b8..bfb8f113 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -12,7 +12,7 @@
 
 // -----------------------------------------------------------------------------
 // Can't find the switch you are looking for? Try looking in:
-// ash/ash_switches.cc
+// ash/common/ash_switches.cc
 // base/base_switches.cc
 // chromeos/chromeos_switches.cc
 // etc.
diff --git a/chrome/common/safe_browsing/permission_report.proto b/chrome/common/safe_browsing/permission_report.proto
index 59dc519..4abd33d 100644
--- a/chrome/common/safe_browsing/permission_report.proto
+++ b/chrome/common/safe_browsing/permission_report.proto
@@ -34,9 +34,7 @@
   optional SourceUI source_ui = 6;
 
   // The relevant field trials enabled for this report.
-  // TODO(stefanocs): Update field_trials field to store hashes instead of
-  // string.
-  repeated string field_trials = 7;
+  repeated FieldTrial field_trials = 7;
 
   // Platform
   enum PlatformType {
@@ -89,4 +87,17 @@
     AUDIO_CAPTURE = 8;
     VIDEO_CAPTURE = 9;
   }
+
+  // Description of a field trial or experiment that the user is currently
+  // enrolled in. All metrics reported in this upload can potentially be
+  // influenced by the field trial.
+  message FieldTrial {
+    // The name of the field trial, as a 32-bit identifier. Currently, the
+    // identifier is a hash of the field trial's name.
+    optional fixed32 name_id = 1;
+
+    // The user's group within the field trial, as a 32-bit identifier.
+    // Currently, the identifier is a hash of the group's name.
+    optional fixed32 group_id = 2;
+  }
 }
diff --git a/chrome/common/service_process_util.cc b/chrome/common/service_process_util.cc
index 1607c63..4f7f3df 100644
--- a/chrome/common/service_process_util.cc
+++ b/chrome/common/service_process_util.cc
@@ -33,10 +33,6 @@
 #include "google_apis/gaia/gaia_switches.h"
 #include "ui/base/ui_base_switches.h"
 
-#if defined(OS_WIN)
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
-#endif  // defined(OS_WIN)
-
 #if !defined(OS_MACOSX)
 
 namespace {
@@ -169,8 +165,7 @@
                                   switches::kServiceProcess);
 
 #if defined(OS_WIN)
-  if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument)
-    command_line->AppendArg(switches::kPrefetchArgumentOther);
+  command_line->AppendArg(switches::kPrefetchArgumentOther);
 #endif  // defined(OS_WIN)
 
   static const char* const kSwitchesToCopy[] = {
diff --git a/chrome/installer/util/BUILD.gn b/chrome/installer/util/BUILD.gn
index 0711499..f9519b94 100644
--- a/chrome/installer/util/BUILD.gn
+++ b/chrome/installer/util/BUILD.gn
@@ -106,10 +106,6 @@
       "//chrome/install_static:install_static_util",
       "//components/base32",
       "//components/metrics",
-
-      # TODO(fdoray): Remove this once the PreRead field trial has expired.
-      # crbug.com/577698
-      "//components/startup_metric_utils/common",
       "//courgette:courgette_lib",
       "//crypto",
       "//third_party/bspatch",
diff --git a/chrome/installer/util/DEPS b/chrome/installer/util/DEPS
index 86908b5..e301ba2 100644
--- a/chrome/installer/util/DEPS
+++ b/chrome/installer/util/DEPS
@@ -7,10 +7,5 @@
 
   "+components/base32",
   "+components/metrics",
-
-  # TODO(fdoray): Remove this once the PreRead field trial has expired.
-  # crbug.com/577698
-  "+components/startup_metric_utils/common",
-
   "+third_party/crashpad",
 ]
diff --git a/chrome/installer/util/auto_launch_util.cc b/chrome/installer/util/auto_launch_util.cc
index 9fbeab7a..7bc403a 100644
--- a/chrome/installer/util/auto_launch_util.cc
+++ b/chrome/installer/util/auto_launch_util.cc
@@ -21,7 +21,6 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/installer/util/util_constants.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "crypto/sha2.h"
 
 namespace {
@@ -59,9 +58,7 @@
 
   base::CommandLine cmd_line(application_dir.Append(installer::kChromeExe));
   cmd_line.AppendSwitch(switches::kNoStartupWindow);
-
-  if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument)
-    cmd_line.AppendArg(switches::kPrefetchArgumentBrowserBackground);
+  cmd_line.AppendArg(switches::kPrefetchArgumentBrowserBackground);
 
   base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, GetAutoLaunchKeyName(),
                                  cmd_line.GetCommandLineString());
diff --git a/chrome/installer/util/channel_info.cc b/chrome/installer/util/channel_info.cc
index aa20598..dae2c4e 100644
--- a/chrome/installer/util/channel_info.cc
+++ b/chrome/installer/util/channel_info.cc
@@ -25,7 +25,7 @@
 const wchar_t kModMultiInstall[] = L"-multi";
 const wchar_t kModReadyMode[] = L"-readymode";
 const wchar_t kModStage[] = L"-stage:";
-const wchar_t kModStatsDefault[] = L"-statsdef:";
+const wchar_t kModStatsDefault[] = L"-statsdef=";
 const wchar_t kSfxFull[] = L"-full";
 const wchar_t kSfxMigrating[] = L"-migrating";
 const wchar_t kSfxMultiFail[] = L"-multifail";
@@ -73,7 +73,8 @@
   base::string16::size_type mod_position = base::string16::npos;
   base::string16::size_type mod_length =
       base::string16::traits_type::length(kModifiers[index]);
-  const bool mod_takes_arg = (kModifiers[index][mod_length - 1] == L':');
+  char last_char = kModifiers[index][mod_length - 1];
+  const bool mod_takes_arg = (last_char == L':' || last_char == L'=');
   base::string16::size_type pos = 0;
   do {
     mod_position = ap_value.find(kModifiers[index], pos, mod_length);
diff --git a/chrome/installer/util/channel_info.h b/chrome/installer/util/channel_info.h
index 9010802..9a02b228 100644
--- a/chrome/installer/util/channel_info.h
+++ b/chrome/installer/util/channel_info.h
@@ -90,7 +90,7 @@
 
   // Returns the string identifying the stats default state (i.e., the starting
   // value of the "send usage stats" checkbox during install), or an empty
-  // string if the -statsdef: modifier is not present in the value.
+  // string if the -statsdef= modifier is not present in the value.
   base::string16 GetStatsDefault() const;
 
   // Returns true if the -full suffix is present in the value.
diff --git a/chrome/installer/util/channel_info_unittest.cc b/chrome/installer/util/channel_info_unittest.cc
index 47861537..a7e2c30 100644
--- a/chrome/installer/util/channel_info_unittest.cc
+++ b/chrome/installer/util/channel_info_unittest.cc
@@ -243,33 +243,33 @@
   EXPECT_EQ(L"", ci.GetStatsDefault());
   ci.set_value(L"-statsdef");
   EXPECT_EQ(L"", ci.GetStatsDefault());
-  ci.set_value(L"-statsdef:");
+  ci.set_value(L"-statsdef=");
   EXPECT_EQ(L"", ci.GetStatsDefault());
-  ci.set_value(L"-statsdef:0");
+  ci.set_value(L"-statsdef=0");
   EXPECT_EQ(L"0", ci.GetStatsDefault());
-  ci.set_value(L"-statsdef:1");
+  ci.set_value(L"-statsdef=1");
   EXPECT_EQ(L"1", ci.GetStatsDefault());
 
   ci.set_value(L"-multi");
   EXPECT_EQ(L"", ci.GetStatsDefault());
   ci.set_value(L"-statsdef-multi");
   EXPECT_EQ(L"", ci.GetStatsDefault());
-  ci.set_value(L"-statsdef:-multi");
+  ci.set_value(L"-statsdef=-multi");
   EXPECT_EQ(L"", ci.GetStatsDefault());
-  ci.set_value(L"-statsdef:0-multi");
+  ci.set_value(L"-statsdef=0-multi");
   EXPECT_EQ(L"0", ci.GetStatsDefault());
-  ci.set_value(L"-statsdef:1-multi");
+  ci.set_value(L"-statsdef=1-multi");
   EXPECT_EQ(L"1", ci.GetStatsDefault());
 
   ci.set_value(L"2.0-beta-multi");
   EXPECT_EQ(L"", ci.GetStatsDefault());
   ci.set_value(L"2.0-beta-statsdef-multi");
   EXPECT_EQ(L"", ci.GetStatsDefault());
-  ci.set_value(L"2.0-beta-statsdef:-multi");
+  ci.set_value(L"2.0-beta-statsdef=-multi");
   EXPECT_EQ(L"", ci.GetStatsDefault());
-  ci.set_value(L"2.0-beta-statsdef:0-multi");
+  ci.set_value(L"2.0-beta-statsdef=0-multi");
   EXPECT_EQ(L"0", ci.GetStatsDefault());
-  ci.set_value(L"2.0-beta-statsdef:1-multi");
+  ci.set_value(L"2.0-beta-statsdef=1-multi");
   EXPECT_EQ(L"1", ci.GetStatsDefault());
 }
 
diff --git a/chrome/service/BUILD.gn b/chrome/service/BUILD.gn
index a1ef809..bb741209 100644
--- a/chrome/service/BUILD.gn
+++ b/chrome/service/BUILD.gn
@@ -71,11 +71,6 @@
       "service_utility_process_host.cc",
       "service_utility_process_host.h",
     ]
-    deps += [
-      # TODO(fdoray): Remove this once the PreRead field trial has expired.
-      # crbug.com/577698
-      "//components/startup_metric_utils/common",
-    ]
   } else {
     sources += [ "cloud_print/print_system_dummy.cc" ]
   }
diff --git a/chrome/service/DEPS b/chrome/service/DEPS
index 6d0fdd1f..641ad53 100644
--- a/chrome/service/DEPS
+++ b/chrome/service/DEPS
@@ -2,11 +2,6 @@
   "+chrome/grit",  # For generated headers.
   "+components/prefs",
   "+components/network_session_configurator/switches.h",
-
-  # TODO(fdoray): Remove this once the PreRead field trial has expired.
-  # crbug.com/577698
-  "+components/startup_metric_utils/common",
-
   "+components/version_info",
   "+sandbox/win/src",
 ]
diff --git a/chrome/service/service_utility_process_host.cc b/chrome/service/service_utility_process_host.cc
index 849f26c..089229c 100644
--- a/chrome/service/service_utility_process_host.cc
+++ b/chrome/service/service_utility_process_host.cc
@@ -24,7 +24,6 @@
 #include "build/build_config.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/chrome_utility_printing_messages.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "content/public/common/child_process_host.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/result_codes.h"
@@ -227,9 +226,7 @@
   cmd_line.AppendSwitchASCII(switches::kProcessType, switches::kUtilityProcess);
   cmd_line.AppendSwitchASCII(switches::kProcessChannelID, channel_id);
   cmd_line.AppendSwitch(switches::kLang);
-
-  if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument)
-    cmd_line.AppendArg(switches::kPrefetchArgumentOther);
+  cmd_line.AppendArg(switches::kPrefetchArgumentOther);
 
   if (Launch(&cmd_line, no_sandbox)) {
     ReportUmaEvent(SERVICE_UTILITY_STARTED);
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index e0f20cf..4621bd65 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -593,10 +593,7 @@
                 "//chrome")
 
         # Aura depended tests.
-        sources -= [
-          "../browser/ui/views/bookmarks/bookmark_bar_view_test.cc",
-          "../browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc",
-        ]
+        sources -= [ "../browser/ui/views/bookmarks/bookmark_bar_view_test.cc" ]
       } else {
         sources += rebase_path(
                 chrome_tests_gypi_values.chrome_interactive_ui_test_cocoa_sources,
@@ -1155,8 +1152,6 @@
       sources -= [
         "../../apps/load_and_launch_browsertest.cc",
         "../browser/policy/policy_startup_browsertest.cc",
-        "../browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc",
-        "../browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc",
 
         # chromeos does not support profile list avatar menu
         "../browser/profiles/profile_list_desktop_browsertest.cc",
@@ -1310,10 +1305,6 @@
 
         # ProcessSingletonMac doesn"t do anything.
         "../browser/process_singleton_browsertest.cc",
-
-        # This test depends on GetCommandLineForRelaunch, which is not
-        # available on Mac.
-        "../browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc",
       ]
 
       if (safe_browsing_mode == 1) {
@@ -1428,8 +1419,6 @@
     if (!enable_print_preview) {
       sources -= [
         "../browser/extensions/api/cloud_print_private/cloud_print_private_apitest.cc",
-        "../browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc",
-        "../browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc",
         "../browser/printing/print_preview_dialog_controller_browsertest.cc",
         "../browser/printing/print_preview_pdf_generated_browsertest.cc",
         "../browser/service_process/service_process_control_browsertest.cc",
@@ -1438,6 +1427,19 @@
         "data/webui/print_preview.h",
       ]
     }
+    if (!enable_print_preview || is_mac || is_chromeos) {
+      sources -= [
+        # This test depends on GetCommandLineForRelaunch, which is not
+        # available on Mac. It is also not intended to run on ChromeOS.
+        "../browser/printing/cloud_print/test/cloud_print_policy_browsertest.cc",
+      ]
+    }
+    if (!enable_print_preview || is_chromeos) {
+      sources -= [
+        # Not intended to run on ChromeOS.
+        "../browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc",
+      ]
+    }
     if (enable_mdns) {
       sources += [
         "../browser/extensions/api/gcd_private/gcd_private_apitest.cc",
diff --git a/chrome/test/android/OWNERS b/chrome/test/android/OWNERS
index a12ebe4..bbcb2e05 100644
--- a/chrome/test/android/OWNERS
+++ b/chrome/test/android/OWNERS
@@ -1,6 +1,7 @@
 dfalcantara@chromium.org
 dtrainor@chromium.org
 jbudorick@chromium.org
+mariakhomenko@chromium.org
 nyquist@chromium.org
 skyostil@chromium.org
 tedchoc@chromium.org
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
index 8476705c..2911a10d 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -167,7 +167,7 @@
 
         @Override
         public void startZeroSuggest(Profile profile, String omniboxText, String url,
-                boolean isQueryInOmnibox, boolean focusedFromFakebox) {
+                boolean focusedFromFakebox) {
             mZeroSuggestCalledCount++;
         }
 
@@ -222,7 +222,7 @@
 
         @Override
         public void startZeroSuggest(Profile profile, String omniboxText, String url,
-                boolean isQueryInOmnibox, boolean focusedFromFakebox) {
+                boolean focusedFromFakebox) {
         }
 
         @Override
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index a8c5a4a..e277349d 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/test/base/in_process_browser_test.h"
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/command_line.h"
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index 93a075a3..8ac1fbe 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -197,6 +197,11 @@
   return nullptr;
 }
 
+subresource_filter::RulesetService*
+TestingBrowserProcess::subresource_filter_ruleset_service() {
+  return nullptr;
+}
+
 net::URLRequestContextGetter* TestingBrowserProcess::system_request_context() {
   return system_request_context_;
 }
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index 59862e52..a3ad7a57 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -82,6 +82,8 @@
   safe_browsing::SafeBrowsingService* safe_browsing_service() override;
   safe_browsing::ClientSideDetectionService* safe_browsing_detection_service()
       override;
+  subresource_filter::RulesetService* subresource_filter_ruleset_service()
+      override;
   net::URLRequestContextGetter* system_request_context() override;
   BrowserProcessPlatformPart* platform_part() override;
 
diff --git a/chrome/test/base/view_event_test_platform_part_chromeos.cc b/chrome/test/base/view_event_test_platform_part_chromeos.cc
index bdd8c12..3222d190 100644
--- a/chrome/test/base/view_event_test_platform_part_chromeos.cc
+++ b/chrome/test/base/view_event_test_platform_part_chromeos.cc
@@ -6,7 +6,7 @@
 
 #include <memory>
 
-#include "ash/ash_switches.h"
+#include "ash/common/ash_switches.h"
 #include "ash/common/material_design/material_design_controller.h"
 #include "ash/shell.h"
 #include "ash/shell_init_params.h"
diff --git a/chrome/test/data/android/payments/dynamic_shipping.js b/chrome/test/data/android/payments/dynamic_shipping.js
index ede7b7f..f2e84c4 100644
--- a/chrome/test/data/android/payments/dynamic_shipping.js
+++ b/chrome/test/data/android/payments/dynamic_shipping.js
@@ -34,7 +34,7 @@
               .then(function() {
                 print(
                     JSON.stringify(resp.totalAmount, undefined, 2) + '<br>' +
-                    request.shippingOption + '<br>' +
+                    resp.shippingOption + '<br>' +
                     JSON.stringify(
                         toDictionary(resp.shippingAddress), undefined, 2) +
                     '<br>' + resp.methodName + '<br>' +
diff --git a/chrome/test/data/android/payments/free_shipping.js b/chrome/test/data/android/payments/free_shipping.js
index d7ee2132..b4c07c3 100644
--- a/chrome/test/data/android/payments/free_shipping.js
+++ b/chrome/test/data/android/payments/free_shipping.js
@@ -29,7 +29,7 @@
               .then(function() {
                 print(
                     JSON.stringify(resp.totalAmount, undefined, 2) + '<br>' +
-                    request.shippingOption + '<br>' +
+                    resp.shippingOption + '<br>' +
                     JSON.stringify(
                         toDictionary(resp.shippingAddress), undefined, 2) +
                     '<br>' + resp.methodName + '<br>' +
diff --git a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
index 7a53a510..ce2a7c9 100644
--- a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
@@ -20,6 +20,12 @@
   extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
     'test_browser_proxy.js',
   ]),
+
+  /** @override */
+  preLoad: function() {
+    SettingsPageBrowserTest.prototype.preLoad.call(this);
+    settingsHidePagesByDefaultForTest = true;
+  },
 };
 
 // Times out on debug builders and may time out on memory bots because
@@ -102,8 +108,13 @@
   /** @type {?CrSettingsPrefs} */
   var prefs = null;
 
+  var self = this;
+
   suite('SettingsEasyUnlock', function() {
     suiteSetup(function() {
+      self.getPage('basic').set('pageVisibility.people', true);
+      Polymer.dom.flush();
+
       // These overrides are necessary for this test to function on ChromeOS
       // bots that do not have Bluetooth (don't actually support Easy Unlock).
       loadTimeData.overrideValues({
diff --git a/chrome/test/data/webui/settings/on_startup_browsertest.js b/chrome/test/data/webui/settings/on_startup_browsertest.js
index 7e098dd..f6c0db2 100644
--- a/chrome/test/data/webui/settings/on_startup_browsertest.js
+++ b/chrome/test/data/webui/settings/on_startup_browsertest.js
@@ -36,6 +36,12 @@
     assertTrue(!!result);
     return result;
   },
+
+  /** @override */
+  preLoad: function() {
+    SettingsPageBrowserTest.prototype.preLoad.call(this);
+    settingsHidePagesByDefaultForTest = true;
+  },
 };
 
 TEST_F('OnStartupSettingsBrowserTest', 'uiTests', function() {
@@ -53,6 +59,9 @@
 
   suite('OnStartupHandler', function() {
     suiteSetup(function() {
+      self.getPage('basic').set('pageVisibility.onStartup', true);
+      Polymer.dom.flush();
+
       settingsPrefs = document.querySelector('cr-settings').$$(
           'settings-prefs');
       assertTrue(!!settingsPrefs);
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index e815261..366e79c 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -97,6 +97,15 @@
     ]
   } else if (is_cast_desktop_build || target_os == "android") {
     filters += [
+      # URLRequestTestHTTP.GetTest_ManyCookies takes roughly 55s to run. Increase
+      # timeout to 90s from 45s to allow it to pass (b/19821476) (b/29415636).
+      # CTLogVerifierTest.VerifiesValidConsistencyProofsFromReferenceGenerator
+      # times out occasionally, paricularly on the CQ bots; disable to reduce
+      # CQ flakiness (crbug/598406) (b/29415636).
+      # Running a batch of net_unittests has high overhead, so
+      # run tests in batches of 25 to reduce number of batches (b/23156294).
+      "net_unittests --gtest_filter=-CTLogVerifierTest.VerifiesValidConsistencyProofsFromReferenceGenerator --test-launcher-timeout=90000 --test-launcher-batch-limit=25",
+
       # Disable PipelineIntegrationTest.BasicPlayback_MediaSource_VP9_WebM (not supported)
       "media_unittests --gtest_filter=-PipelineIntegrationTest.BasicPlayback_MediaSource_VP9_WebM",
     ]
@@ -147,6 +156,27 @@
   }
 }
 
+if (is_android) {
+  cast_test_group("cast_junit_tests") {
+    test_type = "junit"
+    tests = [
+      "//base:base_junit_tests",
+      "//content/public/android:content_junit_tests",
+      "//net/android:net_junit_tests",
+      "//testing/android/junit:junit_unit_tests",
+      "//ui/android:ui_junit_tests",
+    ]
+  }
+
+  cast_test_group_list("cast_junit_test_lists") {
+    test_type = "junit"
+    build_list_path = "$root_out_dir/junit/build_junit_test_list.txt"
+    run_list_path = "$root_out_dir/junit/run_junit_test_list.txt"
+    build_tests = true
+    test_groups = [ ":cast_junit_tests" ]
+  }
+}
+
 source_set("cast_shell_common") {
   deps = [
     ":cast_shell_pak",
diff --git a/chromecast/build/tests/cast_test.gni b/chromecast/build/tests/cast_test.gni
index 1c56095..94a03c8 100644
--- a/chromecast/build/tests/cast_test.gni
+++ b/chromecast/build/tests/cast_test.gni
@@ -62,8 +62,10 @@
 
 import("//testing/test.gni")
 
-# This directory must be the same for every cast_test_group instance.
-_shared_dir = "$root_gen_dir/chromecast/tests"
+# Do not allow mixing of gtests and junit tests. All gtests must go into one
+# directory, while all junit tests must go into another directory.
+_gtest_gen_dir = "$root_gen_dir/chromecast/tests"
+_junit_gen_dir = "$root_gen_dir/chromecast/junit"
 
 # A group of test executables. Including test targets in this group makes it
 # possible for Chromecast build infrastructure to build and run them with
@@ -91,10 +93,26 @@
 #       cast_test_groups, where a higher number trumps a lower number.
 #       If not assigned, priority defaults to "1", the lowest priority.
 #
+#   test_type (optional)
+#       A string, which must be either "junit" or "gtest". If not defined,
+#       defaults to "gtest".
+#
 template("cast_test_group") {
   assert(defined(invoker.tests),
          "$target_name needs 'tests' listing the test() targets")
 
+  _test_type = "gtest"
+  if (defined(invoker.test_type)) {
+    assert(invoker.test_type == "gtest" || invoker.test_type == "junit")
+    _test_type = invoker.test_type
+  }
+
+  if (_test_type == "gtest") {
+    _shared_dir = _gtest_gen_dir
+  } else if (_test_type == "junit") {
+    _shared_dir = _junit_gen_dir
+  }
+
   # If a set of filters has not been defined, use the empty list.
   _filters = []
   if (defined(invoker.filters)) {
@@ -212,6 +230,9 @@
 #       Set this to true to build all of the tests included in |test_groups|.
 #       Defaults to false. Note that if this is set to true, the test targets
 #       will be built after all the lists are generated.
+#   test_type (optional)
+#       A string, which must be either "junit" or "gtest". If not defined,
+#       defaults to "gtest".
 #
 template("cast_test_group_list") {
   assert(defined(invoker.test_groups), "$target_name needs 'test_groups'")
@@ -221,6 +242,18 @@
 
   _pack_build_action = target_name + "_pack_build"
 
+  _test_type = "gtest"
+  if (defined(invoker.test_type)) {
+    assert(invoker.test_type == "gtest" || invoker.test_type == "junit")
+    _test_type = invoker.test_type
+  }
+
+  if (_test_type == "gtest") {
+    _shared_dir = _gtest_gen_dir
+  } else if (_test_type == "junit") {
+    _shared_dir = _junit_gen_dir
+  }
+
   # Generate a list of the "create_list" actions for each group. These will be
   # depended upon to ensure they're run before the "pack_build" step.
   _build_actions = []
diff --git a/chromecast/net/connectivity_checker_impl.cc b/chromecast/net/connectivity_checker_impl.cc
index 87f0b63..f964e00 100644
--- a/chromecast/net/connectivity_checker_impl.cc
+++ b/chromecast/net/connectivity_checker_impl.cc
@@ -65,6 +65,7 @@
 }
 
 void ConnectivityCheckerImpl::Initialize() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   base::CommandLine::StringType check_url_str =
       command_line->GetSwitchValueNative(switches::kConnectivityCheckUrl);
@@ -90,24 +91,29 @@
 }
 
 bool ConnectivityCheckerImpl::Connected() const {
+  base::AutoLock auto_lock(connected_lock_);
   return connected_;
 }
 
 void ConnectivityCheckerImpl::SetConnected(bool connected) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   if (connected_ == connected)
     return;
-
-  connected_ = connected;
+  {
+    base::AutoLock auto_lock(connected_lock_);
+    connected_ = connected;
+  }
   Notify(connected);
   LOG(INFO) << "Global connection is: " << (connected ? "Up" : "Down");
 }
 
 void ConnectivityCheckerImpl::Check() {
-  if (!task_runner_->BelongsToCurrentThread()) {
-    task_runner_->PostTask(FROM_HERE,
-                           base::Bind(&ConnectivityCheckerImpl::Check, this));
-    return;
-  }
+  task_runner_->PostTask(FROM_HERE,
+      base::Bind(&ConnectivityCheckerImpl::CheckInternal, this));
+}
+
+void ConnectivityCheckerImpl::CheckInternal() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(url_request_context_.get());
 
   // Don't check connectivity if network is offline, because Internet could be
@@ -162,6 +168,7 @@
 }
 
 void ConnectivityCheckerImpl::OnResponseStarted(net::URLRequest* request) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   int http_response_code =
       (request->status().is_success() &&
        request->response_info().headers.get() != nullptr)
@@ -192,6 +199,7 @@
     net::URLRequest* request,
     const net::SSLInfo& ssl_info,
     bool fatal) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   LOG(ERROR) << "OnSSLCertificateError: cert_status=" << ssl_info.cert_status;
   net::SSLClientSocket::ClearSessionCache();
   OnUrlRequestError(ErrorType::SSL_CERTIFICATE_ERROR);
@@ -199,6 +207,7 @@
 }
 
 void ConnectivityCheckerImpl::OnUrlRequestError(ErrorType type) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   ++check_errors_;
   if (check_errors_ > kNumErrorsToNotifyOffline) {
     // Only record event on the connectivity transition.
@@ -218,11 +227,13 @@
 }
 
 void ConnectivityCheckerImpl::OnUrlRequestTimeout() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   LOG(ERROR) << "time out";
   OnUrlRequestError(ErrorType::REQUEST_TIMEOUT);
 }
 
 void ConnectivityCheckerImpl::Cancel() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
   if (!url_request_.get())
     return;
   VLOG(2) << "Cancel connectivity check in progress";
diff --git a/chromecast/net/connectivity_checker_impl.h b/chromecast/net/connectivity_checker_impl.h
index 917545d..7d5663d 100644
--- a/chromecast/net/connectivity_checker_impl.h
+++ b/chromecast/net/connectivity_checker_impl.h
@@ -32,6 +32,7 @@
       public net::URLRequest::Delegate,
       public net::NetworkChangeNotifier::NetworkChangeObserver {
  public:
+  // Connectivity checking and initialization will run on task_runner.
   explicit ConnectivityCheckerImpl(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
 
@@ -77,11 +78,18 @@
   // Called when URL request timed out.
   void OnUrlRequestTimeout();
 
+  void CheckInternal();
+
   std::unique_ptr<GURL> connectivity_check_url_;
   std::unique_ptr<net::URLRequestContext> url_request_context_;
   std::unique_ptr<net::URLRequest> url_request_;
   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+  // connected_lock_ protects access to connected_ which is shared across
+  // threads.
+  mutable base::Lock connected_lock_;
   bool connected_;
+
   net::NetworkChangeNotifier::ConnectionType connection_type_;
   // Number of connectivity check errors.
   unsigned int check_errors_;
diff --git a/chromecast/renderer/cast_content_renderer_client.cc b/chromecast/renderer/cast_content_renderer_client.cc
index 64e0598..1544f84 100644
--- a/chromecast/renderer/cast_content_renderer_client.cc
+++ b/chromecast/renderer/cast_content_renderer_client.cc
@@ -21,11 +21,16 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
+#include "media/base/media.h"
 #include "third_party/WebKit/public/platform/WebColor.h"
 #include "third_party/WebKit/public/web/WebFrameWidget.h"
 #include "third_party/WebKit/public/web/WebSettings.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
+#if defined(OS_ANDROID)
+#include "media/base/android/media_codec_util.h"
+#endif  // OS_ANDROID
+
 namespace chromecast {
 namespace shell {
 
@@ -41,6 +46,15 @@
     : allow_hidden_media_playback_(
           base::CommandLine::ForCurrentProcess()->HasSwitch(
               switches::kAllowHiddenMediaPlayback)) {
+#if defined(OS_ANDROID)
+  DCHECK(::media::MediaCodecUtil::IsMediaCodecAvailable())
+      << "MediaCodec is not available!";
+  // Platform decoder support must be enabled before we set the
+  // IsCodecSupportedCB because the latter instantiates the lazy MimeUtil
+  // instance, which caches the platform decoder supported state when it is
+  // constructed.
+  ::media::EnablePlatformDecoderSupport();
+#endif  // OS_ANDROID
 }
 
 CastContentRendererClient::~CastContentRendererClient() {
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 8334b54..9ad4ade 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -370,9 +370,9 @@
 const char kTestCrosGaiaIdMigration[] = "test-cros-gaia-id-migration";
 const char kTestCrosGaiaIdMigrationStarted[] = "started";
 
-// This flag enables SystemTimezoneAutomaticDetection policy.
-const char kEnableSystemTimezoneAutomaticDetectionPolicy[] =
-    "enable-system-timezone-automatic-detection";
+// This flag disables SystemTimezoneAutomaticDetection policy.
+const char kDisableSystemTimezoneAutomaticDetectionPolicy[] =
+    "disable-system-timezone-automatic-detection";
 
 // This flag enables material design OOBE UI.
 const char kEnableMdOobe[] = "enable-md-oobe";
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index 367068e..58bf141 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -122,7 +122,7 @@
 CHROMEOS_EXPORT extern const char kTestCrosGaiaIdMigration[];
 CHROMEOS_EXPORT extern const char kTestCrosGaiaIdMigrationStarted[];
 CHROMEOS_EXPORT extern const char
-    kEnableSystemTimezoneAutomaticDetectionPolicy[];
+    kDisableSystemTimezoneAutomaticDetectionPolicy[];
 CHROMEOS_EXPORT extern const char kEnableMdOobe[];
 
 CHROMEOS_EXPORT bool WakeOnWifiEnabled();
diff --git a/components/arc/common/audio.mojom b/components/arc/common/audio.mojom
index e8eecb9..47dd90b 100644
--- a/components/arc/common/audio.mojom
+++ b/components/arc/common/audio.mojom
@@ -13,7 +13,7 @@
 
 interface AudioHost {
   // Tells the host to show the volume controls.
-  ShowVolumeControls();
+  ShowVolumeControls@0();
 };
 
 interface AudioInstance {
diff --git a/components/arc/common/auth.mojom b/components/arc/common/auth.mojom
index d2e30045..503cb36 100644
--- a/components/arc/common/auth.mojom
+++ b/components/arc/common/auth.mojom
@@ -31,5 +31,5 @@
 
 interface AuthInstance {
   // Establishes full-duplex communication with the host.
-  Init(AuthHost host_ptr);
+  Init@0(AuthHost host_ptr);
 };
diff --git a/components/arc/common/bluetooth.mojom b/components/arc/common/bluetooth.mojom
index 61961dc..2017ee0 100644
--- a/components/arc/common/bluetooth.mojom
+++ b/components/arc/common/bluetooth.mojom
@@ -226,97 +226,99 @@
 };
 
 interface BluetoothHost {
-  EnableAdapter() => (BluetoothAdapterState state);
-  DisableAdapter() => (BluetoothAdapterState state);
-  GetAdapterProperty(BluetoothPropertyType type);
-  SetAdapterProperty(BluetoothProperty property);
-  GetRemoteDeviceProperty(BluetoothAddress remote_addr,
-                          BluetoothPropertyType type);
-  SetRemoteDeviceProperty(BluetoothAddress remote_addr,
-                          BluetoothProperty property);
-  GetRemoteServiceRecord(BluetoothAddress remote_addr,
-                         BluetoothUUID uuid);
-  GetRemoteServices(BluetoothAddress remote_addr);
-  StartDiscovery();
-  CancelDiscovery();
-  CreateBond(BluetoothAddress addr, int32 transport);
-  RemoveBond(BluetoothAddress addr);
-  CancelBond(BluetoothAddress addr);
+  EnableAdapter@0() => (BluetoothAdapterState state);
+  DisableAdapter@1() => (BluetoothAdapterState state);
+  GetAdapterProperty@2(BluetoothPropertyType type);
+  SetAdapterProperty@3(BluetoothProperty property);
+  GetRemoteDeviceProperty@4(BluetoothAddress remote_addr,
+                            BluetoothPropertyType type);
+  SetRemoteDeviceProperty@5(BluetoothAddress remote_addr,
+                            BluetoothProperty property);
+  GetRemoteServiceRecord@6(BluetoothAddress remote_addr,
+                           BluetoothUUID uuid);
+  GetRemoteServices@7(BluetoothAddress remote_addr);
+  StartDiscovery@8();
+  CancelDiscovery@9();
+  CreateBond@10(BluetoothAddress addr, int32 transport);
+  RemoveBond@11(BluetoothAddress addr);
+  CancelBond@12(BluetoothAddress addr);
 
-  GetConnectionState(BluetoothAddress addr) => (bool connected);
+  GetConnectionState@13(BluetoothAddress addr) => (bool connected);
 
   // Bluetooth Gatt Client functions
-  [MinVersion=1] StartLEScan();
-  [MinVersion=1] StopLEScan();
-  [MinVersion=1] ConnectLEDevice(BluetoothAddress remote_addr);
-  [MinVersion=1] DisconnectLEDevice(BluetoothAddress remote_addr);
-  [MinVersion=1] SearchService(BluetoothAddress remote_addr);
-  [MinVersion=1] GetGattDB(BluetoothAddress remote_addr);
-  [MinVersion=1] StartLEListen() => (BluetoothGattStatus status);
-  [MinVersion=1] StopLEListen() => (BluetoothGattStatus status);
-  [MinVersion=1] ReadGattCharacteristic(BluetoothAddress remote_addr,
+  [MinVersion=1] StartLEScan@14();
+  [MinVersion=1] StopLEScan@15();
+  [MinVersion=1] ConnectLEDevice@16(BluetoothAddress remote_addr);
+  [MinVersion=1] DisconnectLEDevice@17(BluetoothAddress remote_addr);
+  [MinVersion=1] SearchService@18(BluetoothAddress remote_addr);
+  [MinVersion=1] GetGattDB@19(BluetoothAddress remote_addr);
+  [MinVersion=1] StartLEListen@20() => (BluetoothGattStatus status);
+  [MinVersion=1] StopLEListen@21() => (BluetoothGattStatus status);
+  [MinVersion=1] ReadGattCharacteristic@22(BluetoothAddress remote_addr,
+                                           BluetoothGattServiceID service_id,
+                                           BluetoothGattID char_id)
+      => (BluetoothGattValue value);
+  [MinVersion=1] WriteGattCharacteristic@23(BluetoothAddress remote_addr,
+                                            BluetoothGattServiceID service_id,
+                                            BluetoothGattID char_id,
+                                            BluetoothGattValue value)
+      => (BluetoothGattStatus status);
+  [MinVersion=1] ReadGattDescriptor@24(BluetoothAddress remote_addr,
+                                       BluetoothGattServiceID service_id,
+                                       BluetoothGattID char_id,
+                                       BluetoothGattID desc_id)
+      => (BluetoothGattValue value);
+  [MinVersion=1] WriteGattDescriptor@25(BluetoothAddress remote_addr,
                                         BluetoothGattServiceID service_id,
-                                        BluetoothGattID char_id)
-      => (BluetoothGattValue value);
-  [MinVersion=1] WriteGattCharacteristic(BluetoothAddress remote_addr,
-                                         BluetoothGattServiceID service_id,
-                                         BluetoothGattID char_id,
-                                         BluetoothGattValue value)
+                                        BluetoothGattID char_id,
+                                        BluetoothGattID desc_id,
+                                        BluetoothGattValue value)
       => (BluetoothGattStatus status);
-  [MinVersion=1] ReadGattDescriptor(BluetoothAddress remote_addr,
-                                    BluetoothGattServiceID service_id,
-                                    BluetoothGattID char_id,
-                                    BluetoothGattID desc_id)
-      => (BluetoothGattValue value);
-  [MinVersion=1] WriteGattDescriptor(BluetoothAddress remote_addr,
-                                     BluetoothGattServiceID service_id,
-                                     BluetoothGattID char_id,
-                                     BluetoothGattID desc_id,
-                                     BluetoothGattValue value)
+  [MinVersion=1] RegisterForGattNotification@26(
+      BluetoothAddress remote_addr,
+      BluetoothGattServiceID service_id,
+      BluetoothGattID char_id)
       => (BluetoothGattStatus status);
-  [MinVersion=1] RegisterForGattNotification(BluetoothAddress remote_addr,
-                                             BluetoothGattServiceID service_id,
-                                             BluetoothGattID char_id)
+  [MinVersion=1] DeregisterForGattNotification@27(
+      BluetoothAddress remote_addr,
+      BluetoothGattServiceID service_id,
+      BluetoothGattID char_id)
       => (BluetoothGattStatus status);
-  [MinVersion=1] DeregisterForGattNotification(BluetoothAddress remote_addr,
-                                               BluetoothGattServiceID service_id,
-                                               BluetoothGattID char_id)
-      => (BluetoothGattStatus status);
-  [MinVersion=1] ReadRemoteRssi(BluetoothAddress remote_addr)
+  [MinVersion=1] ReadRemoteRssi@28(BluetoothAddress remote_addr)
       => (int32 rssi);
 
 };
 
 interface BluetoothInstance {
-  Init(BluetoothHost host_ptr);
+  Init@0(BluetoothHost host_ptr);
 
-  OnAdapterProperties(BluetoothStatus status,
-                      array<BluetoothProperty> properties);
-  OnRemoteDeviceProperties(BluetoothStatus status,
-                           BluetoothAddress address,
-                           array<BluetoothProperty> properties);
-  OnDeviceFound(array<BluetoothProperty> properties);
-  OnDiscoveryStateChanged(BluetoothDiscoveryState state);
-  OnBondStateChanged(BluetoothStatus status,
-                     BluetoothAddress remote_addr,
-                     BluetoothBondState state);
-  OnAclStateChanged(BluetoothStatus status,
-                    BluetoothAddress remote_addr,
-                    BluetoothAclState state);
+  OnAdapterProperties@1(BluetoothStatus status,
+                        array<BluetoothProperty> properties);
+  OnRemoteDeviceProperties@2(BluetoothStatus status,
+                             BluetoothAddress address,
+                             array<BluetoothProperty> properties);
+  OnDeviceFound@3(array<BluetoothProperty> properties);
+  OnDiscoveryStateChanged@4(BluetoothDiscoveryState state);
+  OnBondStateChanged@5(BluetoothStatus status,
+                       BluetoothAddress remote_addr,
+                       BluetoothBondState state);
+  OnAclStateChanged@6(BluetoothStatus status,
+                      BluetoothAddress remote_addr,
+                      BluetoothAclState state);
 
   // Bluetooth Gatt Client callbacks
-  [MinVersion=1] OnLEDeviceFound(BluetoothAddress addr,
-                                 int32 rssi,
-                                 array<BluetoothAdvertisingData> adv_data);
-  [MinVersion=1] OnLEConnectionStateChange(BluetoothAddress remote_addr,
-                                           bool connected);
-  [MinVersion=1] OnSearchComplete(BluetoothAddress remote_addr,
-                                  BluetoothGattStatus status);
-  [MinVersion=1] OnGetGattDB(BluetoothAddress remote_addr,
-                             array<BluetoothGattDBElement> db);
-  [MinVersion=1] OnServicesRemoved(BluetoothAddress remote_addr,
-                                   uint16 start_handle,
-                                   uint16 end_handle);
-  [MinVersion=1] OnServicesAdded(BluetoothAddress remote_addr,
-                                 array<BluetoothGattDBElement> db);
+  [MinVersion=1] OnLEDeviceFound@7(BluetoothAddress addr,
+                                   int32 rssi,
+                                   array<BluetoothAdvertisingData> adv_data);
+  [MinVersion=1] OnLEConnectionStateChange@8(BluetoothAddress remote_addr,
+                                             bool connected);
+  [MinVersion=1] OnSearchComplete@9(BluetoothAddress remote_addr,
+                                    BluetoothGattStatus status);
+  [MinVersion=1] OnGetGattDB@10(BluetoothAddress remote_addr,
+                                array<BluetoothGattDBElement> db);
+  [MinVersion=1] OnServicesRemoved@11(BluetoothAddress remote_addr,
+                                      uint16 start_handle,
+                                      uint16 end_handle);
+  [MinVersion=1] OnServicesAdded@12(BluetoothAddress remote_addr,
+                                    array<BluetoothGattDBElement> db);
 };
diff --git a/components/arc/common/clipboard.mojom b/components/arc/common/clipboard.mojom
index 6d49004..47304d8 100644
--- a/components/arc/common/clipboard.mojom
+++ b/components/arc/common/clipboard.mojom
@@ -7,18 +7,18 @@
 interface ClipboardHost {
   // Tells the host to change its content, usually when the user initiates
   // a 'copy' action.
-  SetTextContent(string text);
+  SetTextContent@0(string text);
 
   // Tells the host to return its content, usually when the user initiates
   // a 'paste' action or when the instance needs to re-sync its clipboard
   // content with the host.
-  GetTextContent();
+  GetTextContent@1();
 };
 
 interface ClipboardInstance {
   // Establishes full-duplex communication with the host.
-  Init(ClipboardHost host_ptr);
+  Init@0(ClipboardHost host_ptr);
 
   // Pass the result of ClipboardHost.GetTextContent().
-  OnGetTextContent(string returnedText);
+  OnGetTextContent@1(string returnedText);
 };
diff --git a/components/arc/common/crash_collector.mojom b/components/arc/common/crash_collector.mojom
index abb164d..b61963c 100644
--- a/components/arc/common/crash_collector.mojom
+++ b/components/arc/common/crash_collector.mojom
@@ -9,14 +9,14 @@
   // the dump from |pipe|, or rejects the dump by closing |pipe|. Note that
   // |type| is a string instead of an enum, because its value is not relevant
   // to the host: it only serves as a tag in the report.
-  DumpCrash(string type, handle pipe);
+  DumpCrash@0(string type, handle pipe);
 
   // Sets build properties included in every report.
-  [MinVersion=1] SetBuildProperties(string device,
-                                    string board,
-                                    string cpu_abi);
+  [MinVersion=1] SetBuildProperties@1(string device,
+                                      string board,
+                                      string cpu_abi);
 };
 
 interface CrashCollectorInstance {
-  Init(CrashCollectorHost host_ptr);
+  Init@0(CrashCollectorHost host_ptr);
 };
diff --git a/components/arc/common/ime.mojom b/components/arc/common/ime.mojom
index 20fd85b..a3620ea 100644
--- a/components/arc/common/ime.mojom
+++ b/components/arc/common/ime.mojom
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Next MinVersion: 4
+
 module arc.mojom;
 
 import "screen_rect.mojom";
@@ -40,36 +42,35 @@
   bool emphasized;
 };
 
-// Next MinVersion: 4
 interface ImeHost {
   // Notifies Chrome that the text input focus is changed.
-  OnTextInputTypeChanged(TextInputType type);
+  OnTextInputTypeChanged@0(TextInputType type);
 
   // Notifies Chrome that the cursor poisition has changed.
-  OnCursorRectChanged(CursorRect rect);
+  OnCursorRectChanged@1(CursorRect rect);
 
   // Notifies Chrome that the current composition is canceled.
-  [MinVersion=1] OnCancelComposition();
+  [MinVersion=1] OnCancelComposition@2();
 
   // Show virtual keyboard of Chrome OS if needed.
-  [MinVersion=2] ShowImeIfNeeded();
+  [MinVersion=2] ShowImeIfNeeded@3();
 };
 
 interface ImeInstance {
-  Init(ImeHost host_ptr);
+  Init@0(ImeHost host_ptr);
 
   // Sets composition text and attributes requested by the host IME.
-  SetCompositionText(string text, array<CompositionSegment> segments);
+  SetCompositionText@1(string text, array<CompositionSegment> segments);
 
   // Commits the last set composition text and clears the composition.
-  ConfirmCompositionText();
+  ConfirmCompositionText@2();
 
   // Commits the specified text and clears the composition.
-  InsertText(string text);
+  InsertText@3(string text);
 
   // Informs the virtual keyboard bounds on screen is changing.
   // |new_bounds| Represents a ChromeOS virtual keyboard bounds in ChromeOS
   // screen coordinate, physical pixel as a unit.
   // When all members are zero value, virtual keyboard is being hidden.
-  [MinVersion=3] OnKeyboardBoundsChanging(ScreenRect new_bounds);
+  [MinVersion=3] OnKeyboardBoundsChanging@4(ScreenRect new_bounds);
 };
diff --git a/components/arc/common/input.mojom b/components/arc/common/input.mojom
index d3fb37a..17ecc43 100644
--- a/components/arc/common/input.mojom
+++ b/components/arc/common/input.mojom
@@ -11,7 +11,7 @@
   // The virtual device will be reading 'struct input_event's from |fd|.  The
   // ownership of |fd| will be transferred to the receiver, so the sender must
   // not close it.
-  RegisterInputDevice(string name,
-                      string device_type,
-                      handle fd);
+  RegisterInputDevice@0(string name,
+                        string device_type,
+                        handle fd);
 };
diff --git a/components/arc/common/metrics.mojom b/components/arc/common/metrics.mojom
index 0e98f504..cb2e936 100644
--- a/components/arc/common/metrics.mojom
+++ b/components/arc/common/metrics.mojom
@@ -25,9 +25,9 @@
 
 interface MetricsHost {
   // Report boot progress events from ARC instance.
-  ReportBootProgress(array<BootProgressEvent> events);
+  ReportBootProgress@0(array<BootProgressEvent> events);
 };
 
 interface MetricsInstance {
-  Init(MetricsHost host_ptr);
+  Init@0(MetricsHost host_ptr);
 };
diff --git a/components/arc/common/notifications.mojom b/components/arc/common/notifications.mojom
index 792c0406..948fb8aa 100644
--- a/components/arc/common/notifications.mojom
+++ b/components/arc/common/notifications.mojom
@@ -109,9 +109,9 @@
 // TODO(lhchavez): Migrate all request/response messages to Mojo.
 interface NotificationsInstance {
   // Establishes full-duplex communication with the host.
-  Init(NotificationsHost host_ptr);
+  Init@0(NotificationsHost host_ptr);
 
   // Sends an event from Chrome notification UI to Android.
   // |event| is a type of occured event.
-  SendNotificationEventToAndroid(string key, ArcNotificationEvent event);
+  SendNotificationEventToAndroid@1(string key, ArcNotificationEvent event);
 };
diff --git a/components/arc/common/obb_mounter.mojom b/components/arc/common/obb_mounter.mojom
index c1ac0c7..d47dcb6 100644
--- a/components/arc/common/obb_mounter.mojom
+++ b/components/arc/common/obb_mounter.mojom
@@ -7,14 +7,14 @@
 interface ObbMounterHost {
   // Mounts the specified OBB file to the target path, the owner GID will be set
   // to the specified value.
-  MountObb(string obb_file,
-           string target_path,
-           int32 owner_gid) => (bool success);
+  MountObb@0(string obb_file,
+             string target_path,
+             int32 owner_gid) => (bool success);
 
   // Unmounts the OBB file mounted to the specifed path.
-  UnmountObb(string target_path) => (bool success);
+  UnmountObb@1(string target_path) => (bool success);
 };
 
 interface ObbMounterInstance {
-  Init(ObbMounterHost host_ptr);
+  Init@0(ObbMounterHost host_ptr);
 };
diff --git a/components/arc/common/process.mojom b/components/arc/common/process.mojom
index e9494a5..6dd05d68 100644
--- a/components/arc/common/process.mojom
+++ b/components/arc/common/process.mojom
@@ -91,21 +91,21 @@
 
 interface ProcessInstance {
   // Requests ARC instance to return the current process list.
-  RequestProcessList() => (array<RunningAppProcessInfo> processes);
+  RequestProcessList@0() => (array<RunningAppProcessInfo> processes);
 
   // Requests ARC instance to kill a process.
   [MinVersion=1]
-  KillProcess(uint32 pid, string reason);
+  KillProcess@1(uint32 pid, string reason);
 
   // Sets oom_score_adj of a process.
   [MinVersion=2]
-  SetOomScoreAdj(uint32 pid, int32 score);
+  SetOomScoreAdj@2(uint32 pid, int32 score);
 
   // Disables Android built-in oom_adj adjustment.
   [MinVersion=2]
-  DisableBuiltinOomAdjustment();
+  DisableBuiltinOomAdjustment@3();
 
   // Disables Android lowmemorykiller.
   [MinVersion=3]
-  DisableLowMemoryKiller();
+  DisableLowMemoryKiller@4();
 };
diff --git a/components/arc/common/storage_manager.mojom b/components/arc/common/storage_manager.mojom
index 79812f7b..2e4295d 100644
--- a/components/arc/common/storage_manager.mojom
+++ b/components/arc/common/storage_manager.mojom
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// Next MinVersion: 3
+
 module arc.mojom;
 
 // Represents total storage usage of Android applications.
@@ -14,7 +16,6 @@
     uint64 total_cache_bytes;
 };
 
-// Next MinVersion: 3
 // Next method ID: 5
 // Deprecated method ID: 1
 interface StorageManagerInstance {
diff --git a/components/arc/common/video.mojom b/components/arc/common/video.mojom
index a10a05e..664bfb5 100644
--- a/components/arc/common/video.mojom
+++ b/components/arc/common/video.mojom
@@ -10,11 +10,11 @@
   // creating the client end of VideoAcceleratorService message pipe.
   // Replys invalid handle and empty token if any failure.
   [MinVersion=2]
-  OnRequestArcVideoAcceleratorChannel() => (handle channel_handle,
-                                            string token);
+  OnRequestArcVideoAcceleratorChannel@0() => (handle channel_handle,
+                                              string token);
 };
 
 interface VideoInstance {
   // Establishes full-duplex communication with the host.
-  Init(VideoHost host_ptr);
+  Init@0(VideoHost host_ptr);
 };
diff --git a/components/arc/common/window_manager.mojom b/components/arc/common/window_manager.mojom
index 60fd3a74..c456b1a 100644
--- a/components/arc/common/window_manager.mojom
+++ b/components/arc/common/window_manager.mojom
@@ -12,5 +12,5 @@
 
 interface WindowManagerInstance {
   // Informs of the currently used window mode.
-  OnWindowManagerModeChange(WindowManagerMode mode);
+  OnWindowManagerModeChange@0(WindowManagerMode mode);
 };
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index 5e1dfb0..14a28b1 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -225,6 +225,9 @@
       prefs::kAutofillEnabled,
       true,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      prefs::kAutofillProfileUseDatesFixed, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
   // These choices are made on a per-device basis, so they're not syncable.
   registry->RegisterBooleanPref(prefs::kAutofillWalletImportEnabled, true);
   registry->RegisterBooleanPref(
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index 9019bc0..ee5111b1 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -574,6 +574,10 @@
 
 bool AutofillProfile::SaveAdditionalInfo(const AutofillProfile& profile,
                                          const std::string& app_locale) {
+  // If both profiles are verified, do not merge them.
+  if (IsVerified() && profile.IsVerified())
+    return false;
+
   ServerFieldTypeSet field_types, other_field_types;
   GetNonEmptyTypes(app_locale, &field_types);
   profile.GetNonEmptyTypes(app_locale, &other_field_types);
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index 3f7763aa..525f808 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -324,6 +324,7 @@
         ReceiveLoadedDbValues(h, result, &pending_profiles_query_,
                               &web_profiles_);
         LogProfileCount();  // This only logs local profiles.
+        ApplyProfileUseDatesFix();
       } else {
         ReceiveLoadedDbValues(h, result, &pending_server_profiles_query_,
                               &server_profiles_);
@@ -904,11 +905,16 @@
   merged_profiles->clear();
 
   // Sort the existing profiles in decreasing order of frecency, so the "best"
-  // profiles are checked first.
+  // profiles are checked first. Put the verified profiles last so the non
+  // verified profiles get deduped among themselves before reaching the verified
+  // profiles.
+  // TODO(crbug.com/620521): Remove the check for verified from the sort.
   base::Time comparison_time = base::Time::Now();
   std::sort(existing_profiles.begin(), existing_profiles.end(),
             [comparison_time](const AutofillDataModel* a,
                               const AutofillDataModel* b) {
+              if (a->IsVerified() != b->IsVerified())
+                return !a->IsVerified();
               return a->CompareFrecency(b, comparison_time);
             });
 
@@ -1581,8 +1587,11 @@
       if (existing_profile->SaveAdditionalInfo(*profile_to_merge,
                                                app_locale_)) {
         // Since |profile_to_merge| was a duplicate of |existing_profile| and
-        // was merged sucessfully, it can now be deleted.
-        profile_guids_to_delete->push_back(profile_to_merge->guid());
+        // was merged sucessfully, it can now be deleted. The only exception is
+        // if |profile_to_merge| is verified and |existing_profile| is not.
+        // Verified profiles only merge with other verified profiles.
+        if (!profile_to_merge->IsVerified() || existing_profile->IsVerified())
+          profile_guids_to_delete->push_back(profile_to_merge->guid());
 
         // Now try to merge the new resulting profile with the rest of the
         // existing profiles.
@@ -1595,4 +1604,26 @@
       profile_guids_to_delete->size());
 }
 
+void PersonalDataManager::ApplyProfileUseDatesFix() {
+  // Don't run if the fix has already been applied.
+  if (pref_service_->GetBoolean(prefs::kAutofillProfileUseDatesFixed))
+    return;
+
+  std::vector<AutofillProfile> profiles;
+  bool has_changed_data = false;
+  for (AutofillProfile* profile : web_profiles()) {
+    if (profile->use_date() == base::Time()) {
+      profile->set_use_date(base::Time::Now() - base::TimeDelta::FromDays(14));
+      has_changed_data = true;
+    }
+    profiles.push_back(*profile);
+  }
+
+  // Set the pref so that this fix is never run again.
+  pref_service_->SetBoolean(prefs::kAutofillProfileUseDatesFixed, true);
+
+  if (has_changed_data)
+    SetProfiles(&profiles);
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 5357888..9fcbc74b 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -256,6 +256,9 @@
                            FindAndMergeDuplicateProfiles_ProfilesToDelete);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            FindAndMergeDuplicateProfiles_MergedProfileValues);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, ApplyProfileUseDatesFix);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
+                           ApplyProfileUseDatesFix_NotAppliedTwice);
   friend class autofill::AutofillInteractiveTest;
   friend class autofill::AutofillTest;
   friend class autofill::PersonalDataManagerFactory;
@@ -437,6 +440,10 @@
       AutofillProfile* profile_to_merge,
       std::vector<std::string>* profile_guids_to_delete);
 
+  // Runs the Autofill use date fix routine if it's never been done. Returns
+  // whether the routine was run.
+  void ApplyProfileUseDatesFix();
+
   const std::string app_locale_;
 
   // The default country code for new addresses.
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 6c2b79a..48c968b 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -2734,44 +2734,6 @@
   EXPECT_EQ(0, new_verified_profile.Compare(*results[0]));
 }
 
-// Ensure that verified profiles can be saved via SaveImportedProfile,
-// overwriting existing verified profiles as well.
-TEST_F(PersonalDataManagerTest, SaveImportedProfileWithExistingVerifiedData) {
-  // Start with a verified profile.
-  AutofillProfile profile(base::GenerateGUID(), kSettingsOrigin);
-  test::SetProfileInfo(&profile,
-      "Marion", "Mitchell", "Morrison",
-      "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
-      "91601", "US", "12345678910");
-  EXPECT_TRUE(profile.IsVerified());
-
-  // Add the profile to the database.
-  personal_data_->AddProfile(profile);
-
-  // Verify that the web database has been updated and the notification sent.
-  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-      .WillOnce(QuitMainMessageLoop());
-  base::MessageLoop::current()->Run();
-
-  AutofillProfile new_verified_profile = profile;
-  new_verified_profile.set_guid(base::GenerateGUID());
-  new_verified_profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER,
-                                  ASCIIToUTF16("1 234 567-8910"));
-  EXPECT_TRUE(new_verified_profile.IsVerified());
-
-  personal_data_->SaveImportedProfile(new_verified_profile);
-
-  // Verify that the web database has been updated and the notification sent.
-  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
-      .WillOnce(QuitMainMessageLoop());
-  base::MessageLoop::current()->Run();
-
-  // The new profile should be merged into the existing one.
-  const std::vector<AutofillProfile*>& results = personal_data_->GetProfiles();
-  ASSERT_EQ(1U, results.size());
-  EXPECT_EQ(0, new_verified_profile.Compare(*results[0]));
-}
-
 // Ensure that verified credit cards can be saved via SaveImportedCreditCard.
 TEST_F(PersonalDataManagerTest, SaveImportedCreditCardWithVerifiedData) {
   // Start with a verified credit card.
@@ -4460,7 +4422,10 @@
       .WillOnce(QuitMainMessageLoop());
   base::MessageLoop::current()->Run();
 
-  std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
+  // Create a similar new non verified imported profile to be merged with the
+  // saved profiles.
+  std::vector<AutofillProfile*> profiles =
+      personal_data_->GetProfilesToSuggest();
 
   // The imported profile and saved profiles 1 and 2 should be merged together.
   // Therefore there should only be 3 saved profiles.
@@ -4668,4 +4633,346 @@
             profiles[0]->use_date());
 }
 
+// Tests that FindAndMergeDuplicateProfiles only keeps the verified profile with
+// its original data when deduping with similar profiles, even if it has a
+// higher frecency score.
+TEST_F(PersonalDataManagerTest,
+       FindAndMergeDuplicateProfiles_VerifiedProfileFirst) {
+  EnableAutofillProfileCleanup();
+
+  // Create a verified profile with a higher frecency score.
+  AutofillProfile profile1(base::GenerateGUID(), kSettingsOrigin);
+  test::SetProfileInfo(&profile1, "Homer", "Jay", "Simpson",
+                       "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+                       "Springfield", "IL", "91601", "", "12345678910");
+  profile1.set_use_count(5);
+  profile1.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(3));
+
+  // Create a similar non verified profile with a lower frecency score.
+  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
+                       "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+                       "", "Springfield", "IL", "91601", "", "");
+  profile2.set_use_count(3);
+  profile2.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(5));
+
+  personal_data_->AddProfile(profile1);
+  personal_data_->AddProfile(profile2);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  EXPECT_EQ(2U, personal_data_->GetProfiles().size());
+
+  // Create a similar new non verified imported profile to be merged with the
+  // saved profiles.
+  AutofillProfile imported_profile(base::GenerateGUID(),
+                                   "https://www.example.com");
+  test::SetProfileInfo(&imported_profile, "Homer", "J", "Simpson",
+                       "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "");
+
+  base::HistogramTester histogram_tester;
+  personal_data_->SaveImportedProfile(imported_profile);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  std::vector<AutofillProfile*> profiles =
+      personal_data_->GetProfilesToSuggest();
+  // The |imported_profile| should have merged with |profile2|. |profile2|
+  // should then have been discarded because it is similar to the verified
+  // |profile1|.
+  ASSERT_EQ(1U, profiles.size());
+  // 2 profiles were considered for dedupe (profiles 1 and 2).
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.NumberOfProfilesConsideredForDedupe", 2, 1);
+  // 1 profile was removed (|profile2|).
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.NumberOfProfilesRemovedDuringDedupe", 1, 1);
+
+  // Only the verified |profile2| with its original data should have been kept.
+  EXPECT_EQ(profile1.guid(), profiles[0]->guid());
+  EXPECT_EQ(UTF8ToUTF16("742 Evergreen Terrace"),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
+  EXPECT_EQ(UTF8ToUTF16("Jay"), profiles[0]->GetRawInfo(NAME_MIDDLE));
+  EXPECT_EQ(UTF8ToUTF16("12345678910"),
+            profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+  EXPECT_EQ(UTF8ToUTF16(""), profiles[0]->GetRawInfo(COMPANY_NAME));
+  EXPECT_EQ(UTF8ToUTF16(""), profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
+  EXPECT_EQ(profile1.use_count(), profiles[0]->use_count());
+  EXPECT_LT(profile1.use_date() - TimeDelta::FromSeconds(2),
+            profiles[0]->use_date());
+  EXPECT_GT(profile1.use_date() + TimeDelta::FromSeconds(2),
+            profiles[0]->use_date());
+}
+
+// Tests that FindAndMergeDuplicateProfiles only keeps the verified profile with
+// it's original data when deduping with similar profiles, even if it has a
+// lower frecency score.
+TEST_F(PersonalDataManagerTest,
+       FindAndMergeDuplicateProfiles_VerifiedProfileLast) {
+  EnableAutofillProfileCleanup();
+
+  // Create a non verified profile with a higher frecency score.
+  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+                       "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+                       "", "Springfield", "IL", "91601", "", "");
+  profile1.set_use_count(5);
+  profile1.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(3));
+
+  // Create a similar verified profile with a lower frecency score.
+  AutofillProfile profile2(base::GenerateGUID(), kSettingsOrigin);
+  test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
+                       "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+                       "Springfield", "IL", "91601", "", "12345678910");
+  profile2.set_use_count(3);
+  profile2.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(5));
+
+  personal_data_->AddProfile(profile1);
+  personal_data_->AddProfile(profile2);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  EXPECT_EQ(2U, personal_data_->GetProfiles().size());
+
+  // Create a similar non verified imported profile to be merged with the saved
+  // profiles.
+  AutofillProfile imported_profile(base::GenerateGUID(),
+                                   "https://www.example.com");
+  test::SetProfileInfo(&imported_profile, "Homer", "J", "Simpson",
+                       "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "");
+
+  base::HistogramTester histogram_tester;
+  personal_data_->SaveImportedProfile(imported_profile);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  std::vector<AutofillProfile*> profiles = personal_data_->GetProfiles();
+  // The |imported_profile| should have merged with |profile1|. |profile1|
+  // should then have been discarded because it is similar to the verified
+  // |profile2|.
+  ASSERT_EQ(1U, profiles.size());
+  // 2 profiles were considered for dedupe (profiles 1 and 2).
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.NumberOfProfilesConsideredForDedupe", 2, 1);
+  // 1 profile was removed (|profile1|).
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.NumberOfProfilesRemovedDuringDedupe", 1, 1);
+
+  // Only the verified |profile2| with it's original data should have been kept.
+  EXPECT_EQ(profile2.guid(), profiles[0]->guid());
+  EXPECT_EQ(UTF8ToUTF16("742 Evergreen Terrace"),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
+  EXPECT_EQ(UTF8ToUTF16("Jay"), profiles[0]->GetRawInfo(NAME_MIDDLE));
+  EXPECT_EQ(UTF8ToUTF16("12345678910"),
+            profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+  EXPECT_EQ(UTF8ToUTF16(""), profiles[0]->GetRawInfo(COMPANY_NAME));
+  EXPECT_EQ(UTF8ToUTF16(""), profiles[0]->GetRawInfo(ADDRESS_HOME_COUNTRY));
+  EXPECT_EQ(profile2.use_count(), profiles[0]->use_count());
+  EXPECT_LT(profile2.use_date() - TimeDelta::FromSeconds(2),
+            profiles[0]->use_date());
+  EXPECT_GT(profile2.use_date() + TimeDelta::FromSeconds(2),
+            profiles[0]->use_date());
+}
+
+// Tests that FindAndMergeDuplicateProfiles does not merge unverified data into
+// a verified profile. Also tests that two verified profiles don't get merged.
+TEST_F(PersonalDataManagerTest,
+       FindAndMergeDuplicateProfiles_MultipleVerifiedProfiles) {
+  EnableAutofillProfileCleanup();
+
+  // Create a verified profile with a higher frecency score.
+  AutofillProfile profile1(base::GenerateGUID(), kSettingsOrigin);
+  test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
+                       "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
+                       "", "Springfield", "IL", "91601", "", "");
+  profile1.set_use_count(5);
+  profile1.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(3));
+
+  // Create a similar verified profile with a lower frecency score.
+  AutofillProfile profile2(base::GenerateGUID(), kSettingsOrigin);
+  test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
+                       "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
+                       "Springfield", "IL", "91601", "", "12345678910");
+  profile2.set_use_count(3);
+  profile2.set_use_date(base::Time::Now() - base::TimeDelta::FromDays(5));
+
+  personal_data_->AddProfile(profile1);
+  personal_data_->AddProfile(profile2);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  EXPECT_EQ(2U, personal_data_->GetProfiles().size());
+
+  // Create a non verified imported profile to be merged with the saved
+  // profiles.
+  AutofillProfile imported_profile(base::GenerateGUID(),
+                                   "https://www.example.com");
+  test::SetProfileInfo(&imported_profile, "Homer", "J", "Simpson",
+                       "homer.simpson@abc.com", "", "742. Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "");
+
+  base::HistogramTester histogram_tester;
+  personal_data_->SaveImportedProfile(imported_profile);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  // Get the profiles, sorted by frecency to have a deterministic order.
+  std::vector<AutofillProfile*> profiles =
+      personal_data_->GetProfilesToSuggest();
+
+  // The |imported_profile| should have been discarded because the saved profile
+  // with the highest frecency score is verified (|profile1|). Therefore, the
+  // |imported_profile|'s data should not have been merged with |profile1|'s
+  // data. Then |profile1| should have been compared to |profile2| but they
+  // should not have merged because both profiles are verified.
+  ASSERT_EQ(2U, profiles.size());
+  // 2 profiles were considered for dedupe (the 2 saved profiles).
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.NumberOfProfilesConsideredForDedupe", 2, 1);
+  // No profile was removed.
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.NumberOfProfilesRemovedDuringDedupe", 0, 1);
+
+  EXPECT_EQ(profile1.guid(), profiles[0]->guid());
+  EXPECT_EQ(profile2.guid(), profiles[1]->guid());
+  // The profiles should have kept their original data.
+  EXPECT_EQ(UTF8ToUTF16("742 Evergreen Terrace."),
+            profiles[0]->GetRawInfo(ADDRESS_HOME_LINE1));
+  EXPECT_EQ(UTF8ToUTF16("742 Evergreen Terrace"),
+            profiles[1]->GetRawInfo(ADDRESS_HOME_LINE1));
+  EXPECT_EQ(UTF8ToUTF16("J"), profiles[0]->GetRawInfo(NAME_MIDDLE));
+  EXPECT_EQ(UTF8ToUTF16("Jay"), profiles[1]->GetRawInfo(NAME_MIDDLE));
+  EXPECT_EQ(UTF8ToUTF16(""), profiles[0]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+  EXPECT_EQ(UTF8ToUTF16("12345678910"),
+            profiles[1]->GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
+  EXPECT_EQ(profile1.use_count(), profiles[0]->use_count());
+  EXPECT_EQ(profile2.use_count(), profiles[1]->use_count());
+  EXPECT_LT(profile1.use_date() - TimeDelta::FromSeconds(2),
+            profiles[0]->use_date());
+  EXPECT_GT(profile1.use_date() + TimeDelta::FromSeconds(2),
+            profiles[0]->use_date());
+  EXPECT_LT(profile2.use_date() - TimeDelta::FromSeconds(2),
+            profiles[1]->use_date());
+  EXPECT_GT(profile2.use_date() + TimeDelta::FromSeconds(2),
+            profiles[1]->use_date());
+}
+
+// Tests that ApplyProfileUseDatesFix sets the use date of profiles from an
+// incorrect value of 0 to [two weeks from now]. Also tests that SetProfiles
+// does not modify any other profiles.
+TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix) {
+  // Set the kAutofillProfileUseDatesFixed pref to true so that the fix is not
+  // applied just yet.
+  personal_data_->pref_service_->SetBoolean(
+      prefs::kAutofillProfileUseDatesFixed, true);
+
+  // Create a profile. The use date will be set to now automatically.
+  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile1, "Homer", "Jay", "Simpson",
+                       "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "12345678910");
+
+  // Create another profile and set its use date to the default value.
+  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile2, "Marge", "", "Simpson",
+                       "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "12345678910");
+  profile2.set_use_date(base::Time());
+
+  personal_data_->AddProfile(profile1);
+  personal_data_->AddProfile(profile2);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  // Get a sorted list of profiles. |profile1| will be first and |profile2| will
+  // be second.
+  std::vector<AutofillProfile*> saved_profiles =
+      personal_data_->GetProfilesToSuggest();
+
+  ASSERT_EQ(2U, saved_profiles.size());
+
+  // The use dates should not have been modified.
+  EXPECT_LE(base::Time::Now() - base::TimeDelta::FromDays(1),
+            saved_profiles[0]->use_date());
+  EXPECT_EQ(base::Time(), saved_profiles[1]->use_date());
+
+  // Set the pref to false to indicate the fix has never been run.
+  personal_data_->pref_service_->SetBoolean(
+      prefs::kAutofillProfileUseDatesFixed, false);
+
+  personal_data_->ApplyProfileUseDatesFix();
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  // Get a sorted list of profiles.
+  saved_profiles = personal_data_->GetProfilesToSuggest();
+
+  ASSERT_EQ(2U, saved_profiles.size());
+
+  // |profile1|'s use date should not have been modified.
+  EXPECT_LE(base::Time::Now() - base::TimeDelta::FromDays(1),
+            saved_profiles[0]->use_date());
+  // |profile2|'s use date should have been set to two weeks before now.
+  EXPECT_LE(base::Time::Now() - base::TimeDelta::FromDays(15),
+            saved_profiles[1]->use_date());
+  EXPECT_GE(base::Time::Now() - base::TimeDelta::FromDays(13),
+            saved_profiles[1]->use_date());
+}
+
+// Tests that ApplyProfileUseDatesFix does apply the fix if it's already been
+// applied.
+TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix_NotAppliedTwice) {
+  // Set the kAutofillProfileUseDatesFixed pref which means the fix has already
+  // been applied.
+  personal_data_->pref_service_->SetBoolean(
+      prefs::kAutofillProfileUseDatesFixed, true);
+
+  // Create two profiles.
+  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile1, "Homer", "Jay", "Simpson",
+                       "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "12345678910");
+  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile2, "Marge", "", "Simpson",
+                       "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
+                       "", "Springfield", "IL", "91601", "US", "12345678910");
+  profile2.set_use_date(base::Time());
+
+  personal_data_->AddProfile(profile1);
+  personal_data_->AddProfile(profile2);
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+      .WillOnce(QuitMainMessageLoop());
+  base::MessageLoop::current()->Run();
+
+  // Get a sorted list of profiles. |profile1| will be first and |profile2| will
+  // be second.
+  std::vector<AutofillProfile*> saved_profiles =
+      personal_data_->GetProfilesToSuggest();
+
+  ASSERT_EQ(2U, saved_profiles.size());
+  // The use dates should not have been modified.
+  EXPECT_LE(base::Time::Now() - base::TimeDelta::FromDays(1),
+            saved_profiles[0]->use_date());
+  EXPECT_EQ(base::Time(), saved_profiles[1]->use_date());
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_pref_names.cc b/components/autofill/core/common/autofill_pref_names.cc
index 0adfdcf9..20a9883 100644
--- a/components/autofill/core/common/autofill_pref_names.cc
+++ b/components/autofill/core/common/autofill_pref_names.cc
@@ -10,6 +10,10 @@
 // Boolean that is true if Autofill is enabled and allowed to save profile data.
 const char kAutofillEnabled[] = "autofill.enabled";
 
+// Boolean that is true if Autofill address profiles were fixed regarding their
+// bad use dates.
+const char kAutofillProfileUseDatesFixed[] = "autofill.profile_use_dates_fixed";
+
 // Boolean that's true when Wallet card and address import is enabled by the
 // user.
 const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled";
diff --git a/components/autofill/core/common/autofill_pref_names.h b/components/autofill/core/common/autofill_pref_names.h
index c89f292..8fa34e0b 100644
--- a/components/autofill/core/common/autofill_pref_names.h
+++ b/components/autofill/core/common/autofill_pref_names.h
@@ -12,6 +12,7 @@
 // component. Keep alphabetized, and document each in the .cc file.
 
 extern const char kAutofillEnabled[];
+extern const char kAutofillProfileUseDatesFixed[];
 extern const char kAutofillWalletImportEnabled[];
 extern const char kAutofillWalletImportStorageCheckboxState[];
 
diff --git a/components/captive_portal/captive_portal_detector.cc b/components/captive_portal/captive_portal_detector.cc
index ceeffe6..7188c34 100644
--- a/components/captive_portal/captive_portal_detector.cc
+++ b/components/captive_portal/captive_portal_detector.cc
@@ -80,6 +80,10 @@
   results->retry_after_delta = base::TimeDelta();
   results->landing_url = url_fetcher->GetURL();
 
+  VLOG(1) << "Getting captive portal result"
+          << " response code: " << results->response_code
+          << " landing_url: " << results->landing_url;
+
   // If there's a network error of some sort when fetching a file via HTTP,
   // there may be a networking problem, rather than a captive portal.
   // TODO(mmenke):  Consider special handling for redirects that end up at
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 8d17911..6aaf66f 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -785,7 +785,8 @@
       'storage_monitor/storage_monitor_unittest.cc',
       'storage_monitor/storage_monitor_win_unittest.cc',
     ],
-    'subresource_filter_unittest_sources': [
+    'subresource_filter_core_browser_unittest_sources': [
+      'subresource_filter/core/browser/ruleset_service_unittest.cc',
       'subresource_filter/core/browser/subresource_filter_features_unittest.cc',
     ],
     'suggestions_unittest_sources': [
@@ -1058,7 +1059,7 @@
         '<@(signin_unittest_sources)',
         '<@(ssl_config_unittest_sources)',
         '<@(ssl_errors_unittest_sources)',
-        '<@(subresource_filter_unittest_sources)',
+        '<@(subresource_filter_core_browser_unittest_sources)',
         '<@(suggestions_unittest_sources)',
         '<@(supervised_user_error_page_unittest_sources)',
         '<@(sync_bookmarks_unittest_sources)',
diff --git a/components/crash.gypi b/components/crash.gypi
index 84eb148..7b154b3 100644
--- a/components/crash.gypi
+++ b/components/crash.gypi
@@ -224,13 +224,6 @@
             '../third_party/kasko/kasko.gyp:kasko',
           ],
           'conditions': [
-            ['OS=="win"', {
-              'dependencies': [
-                # TODO(fdoray): Remove this once the PreRead field trial has
-                # expired. crbug.com/577698
-                '<(DEPTH)/components/components.gyp:startup_metric_utils_win',
-              ],
-            }],
             ['OS=="mac" or OS=="win"', {
               'dependencies': [
                 '../third_party/crashpad/crashpad/client/client.gyp:crashpad_client',
diff --git a/components/crash/content/app/BUILD.gn b/components/crash/content/app/BUILD.gn
index 7662d852..5f1c1be865 100644
--- a/components/crash/content/app/BUILD.gn
+++ b/components/crash/content/app/BUILD.gn
@@ -53,13 +53,6 @@
     "//base",
   ]
 
-  if (is_win) {
-    deps += [
-      # TODO(fdoray): Remove this once the PreRead field trial has expired.
-      # crbug.com/577698
-      "//components/startup_metric_utils/common",
-    ]
-  }
   if (is_mac || is_win) {
     deps += [
       "//third_party/crashpad/crashpad/client",
diff --git a/components/crash/content/app/DEPS b/components/crash/content/app/DEPS
index 01c710b..80bc21a3 100644
--- a/components/crash/content/app/DEPS
+++ b/components/crash/content/app/DEPS
@@ -3,11 +3,6 @@
 
   "+content/public/common/content_descriptors.h",
   "+content/public/common/result_codes.h",
-
-  # TODO(fdoray): Remove this once the PreRead field trial has expired.
-  # crbug.com/577698
-  "+components/startup_metric_utils/common/pre_read_field_trial_utils_win.h",
-
   "+third_party/crashpad",
   "+third_party/kasko",
   "+third_party/lss/linux_syscall_support.h",
diff --git a/components/crash/content/app/crashpad_win.cc b/components/crash/content/app/crashpad_win.cc
index 7c45badb..ec00a0d 100644
--- a/components/crash/content/app/crashpad_win.cc
+++ b/components/crash/content/app/crashpad_win.cc
@@ -15,7 +15,6 @@
 #include "build/build_config.h"
 #include "components/crash/content/app/crash_reporter_client.h"
 #include "components/crash/content/app/crash_switches.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "third_party/crashpad/crashpad/client/crashpad_client.h"
 #include "third_party/crashpad/crashpad/client/crashpad_info.h"
 #include "third_party/crashpad/crashpad/client/simulate_crash_win.h"
@@ -101,8 +100,8 @@
     if (embedded_handler) {
       arguments.push_back(std::string("--type=") + switches::kCrashpadHandler);
       // The prefetch argument added here has to be documented in
-      // chrome_switches.cc, below the kPrefetchArgument* constants. A
-      // constant can't be used here because crashpad can't depend on Chrome.
+      // chrome_switches.cc, below the kPrefetchArgument* constants. A constant
+      // can't be used here because crashpad can't depend on Chrome.
       arguments.push_back("/prefetch:7");
     } else {
       base::FilePath exe_dir = exe_file.DirName();
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
index b6b4858..87bd478 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
@@ -168,7 +168,7 @@
 
   // Retry if block-once was specified or if method is idempotent.
   return bypass_type == BYPASS_EVENT_TYPE_CURRENT ||
-         IsMethodIdempotent(request->method());
+         util::IsMethodIdempotent(request->method());
 }
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
index 38b3e98..561204eb 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
@@ -344,7 +344,8 @@
     std::unique_ptr<net::URLRequest> request(context.CreateRequest(
         GURL("http://www.google.com/"), net::DEFAULT_PRIORITY, NULL));
     request->set_method(tests[i].method);
-    EXPECT_EQ(tests[i].expected_result, IsMethodIdempotent(request->method()));
+    EXPECT_EQ(tests[i].expected_result,
+              util::IsMethodIdempotent(request->method()));
   }
 }
 
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index e72d249..a9edb9a 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -153,7 +153,7 @@
       net_log_(net_log),
       config_storer_(config_storer),
       backoff_entry_(&backoff_policy),
-      config_service_url_(AddApiKeyToUrl(params::GetConfigServiceURL())),
+      config_service_url_(util::AddApiKeyToUrl(params::GetConfigServiceURL())),
       enabled_(false),
       remote_config_applied_(false),
       url_request_context_getter_(nullptr),
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index 6eb2fe3..4acb735 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -108,12 +108,12 @@
   DCHECK(result->is_empty() || result->is_direct() ||
          !config->IsDataReductionProxy(result->proxy_server().host_port_pair(),
                                        NULL));
-  if (!EligibleForDataReductionProxy(*result, url, method))
+  if (!util::EligibleForDataReductionProxy(*result, url, method))
     return;
   net::ProxyInfo data_reduction_proxy_info;
-  bool data_saver_proxy_used =
-      ApplyProxyConfigToProxyInfo(data_reduction_proxy_config, proxy_retry_info,
-                                  url, &data_reduction_proxy_info);
+  bool data_saver_proxy_used = util::ApplyProxyConfigToProxyInfo(
+      data_reduction_proxy_config, proxy_retry_info, url,
+      &data_reduction_proxy_info);
   if (data_saver_proxy_used)
     result->OverrideProxyList(data_reduction_proxy_info.proxy_list());
   if (config->enabled_by_user_and_reachable() && url.SchemeIsHTTPOrHTTPS() &&
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index 82eb6f2..7b534cc 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -374,15 +374,16 @@
   DCHECK(proxy_info.is_empty() || proxy_info.is_direct() ||
          !data_reduction_proxy_config_->IsDataReductionProxy(
              proxy_info.proxy_server().host_port_pair(), nullptr));
-  if (!EligibleForDataReductionProxy(proxy_info, request.url(),
-                                     request.method())) {
+  if (!util::EligibleForDataReductionProxy(proxy_info, request.url(),
+                                           request.method())) {
     return false;
   }
   net::ProxyConfig proxy_config =
       data_reduction_proxy_config_->ProxyConfigIgnoringHoldback();
   net::ProxyInfo data_reduction_proxy_info;
-  return ApplyProxyConfigToProxyInfo(proxy_config, proxy_retry_info,
-                                     request.url(), &data_reduction_proxy_info);
+  return util::ApplyProxyConfigToProxyInfo(proxy_config, proxy_retry_info,
+                                           request.url(),
+                                           &data_reduction_proxy_info);
 }
 
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
index 44277dc..7d9c066 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_pingback_client.cc
@@ -65,7 +65,7 @@
 DataReductionProxyPingbackClient::DataReductionProxyPingbackClient(
     net::URLRequestContextGetter* url_request_context)
     : url_request_context_(url_request_context),
-      pingback_url_(AddApiKeyToUrl(params::GetPingbackURL())) {}
+      pingback_url_(util::AddApiKeyToUrl(params::GetPingbackURL())) {}
 
 DataReductionProxyPingbackClient::~DataReductionProxyPingbackClient() {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc
index ab38445..b691faf 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_util.cc
@@ -23,6 +23,8 @@
 #endif
 }  // namespace
 
+namespace util {
+
 bool IsMethodIdempotent(const std::string& method) {
   return method == "GET" || method == "OPTIONS" || method == "HEAD" ||
          method == "PUT" || method == "DELETE" || method == "TRACE";
@@ -58,6 +60,8 @@
   return !data_reduction_proxy_info->proxy_server().is_direct();
 }
 
+}  // namespace util
+
 namespace protobuf_parser {
 
 net::ProxyServer::Scheme SchemeFromProxyScheme(
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h
index 8bed6f4d..dcefb8c 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_util.h
@@ -25,7 +25,7 @@
 
 namespace data_reduction_proxy {
 
-// TODO(ryansturm): Move these methods to util namespace. crbug.com/620161
+namespace util {
 
 // Returns true if the request method is idempotent.
 bool IsMethodIdempotent(const std::string& method);
@@ -49,6 +49,8 @@
                                  const GURL& url,
                                  net::ProxyInfo* data_reduction_proxy_info);
 
+}  // namespace util
+
 namespace protobuf_parser {
 
 // Returns the |net::ProxyServer::Scheme| for a ProxyServer_ProxyScheme.
diff --git a/components/drive/drive_uploader.cc b/components/drive/drive_uploader.cc
index ed2a921..125fdd8 100644
--- a/components/drive/drive_uploader.cc
+++ b/components/drive/drive_uploader.cc
@@ -99,7 +99,7 @@
         progress_callback(progress_callback),
         content_length(0),
         next_start_position(-1),
-        power_save_blocker(device::PowerSaveBlocker::CreateWithTaskRunners(
+        power_save_blocker(new device::PowerSaveBlocker(
             device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
             device::PowerSaveBlocker::kReasonOther,
             "Upload in progress",
diff --git a/components/exo/keyboard.cc b/components/exo/keyboard.cc
index 1e567022..1036f55 100644
--- a/components/exo/keyboard.cc
+++ b/components/exo/keyboard.cc
@@ -162,17 +162,17 @@
 // Keyboard, private:
 
 Surface* Keyboard::GetEffectiveFocus(aura::Window* window) const {
-  Surface* main_surface =
-      ShellSurface::GetMainSurface(window->GetToplevelWindow());
-  Surface* window_surface = Surface::AsSurface(window);
+  // Use window surface as effective focus.
+  Surface* focus = Surface::AsSurface(window);
+  if (!focus) {
+    // Fallback to main surface.
+    aura::Window* top_level_window = window->GetToplevelWindow();
+    if (top_level_window)
+      focus = ShellSurface::GetMainSurface(top_level_window);
+  }
 
-  // Use window surface as effective focus and fallback to main surface when
-  // needed.
-  Surface* focus = window_surface ? window_surface : main_surface;
-  if (!focus)
-    return nullptr;
-
-  return delegate_->CanAcceptKeyboardEventsForSurface(focus) ? focus : nullptr;
+  return focus && delegate_->CanAcceptKeyboardEventsForSurface(focus) ? focus
+                                                                      : nullptr;
 }
 
 }  // namespace exo
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index 64b3e02..47de7667 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -145,6 +145,9 @@
 
   // Sets the main surface for the window.
   static void SetMainSurface(aura::Window* window, Surface* surface);
+
+  // Returns the main Surface instance or nullptr if it is not set.
+  // |window| must not be nullptr.
   static Surface* GetMainSurface(const aura::Window* window);
 
   // Returns a trace value representing the state of the surface.
diff --git a/components/mus/demo/manifest.json b/components/mus/demo/manifest.json
index 9214d396..7971b79 100644
--- a/components/mus/demo/manifest.json
+++ b/components/mus/demo/manifest.json
@@ -5,7 +5,7 @@
   "capabilities": {
     "required": {
       "mojo:mus": {
-        "interfaces": [ "mus::mojom::WindowManagerFactoryService"],
+        "interfaces": [ "mus::mojom::WindowManagerWindowTreeFactory"],
       "classes": [ "app" ]
       }
     }
diff --git a/components/mus/demo/mus_demo.cc b/components/mus/demo/mus_demo.cc
index c5f02f61..017e36c 100644
--- a/components/mus/demo/mus_demo.cc
+++ b/components/mus/demo/mus_demo.cc
@@ -6,7 +6,9 @@
 
 #include "base/time/time.h"
 #include "components/bitmap_uploader/bitmap_uploader.h"
+#include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_client.h"
+#include "services/shell/public/cpp/connector.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
@@ -54,18 +56,18 @@
 
 }  // namespace
 
-MusDemo::MusDemo() : window_manager_factory_binding_(this) {}
+MusDemo::MusDemo() {}
 
-MusDemo::~MusDemo() {}
+MusDemo::~MusDemo() {
+  delete window_tree_client_;
+}
 
 void MusDemo::Initialize(shell::Connector* connector,
                          const shell::Identity& identity,
                          uint32_t id) {
   connector_ = connector;
-  mus::mojom::WindowManagerFactoryServicePtr wm_factory_service;
-  connector->ConnectToInterface("mojo:mus", &wm_factory_service);
-  wm_factory_service->SetWindowManagerFactory(
-      window_manager_factory_binding_.CreateInterfacePtrAndBind());
+  window_tree_client_ = new mus::WindowTreeClient(this, this, nullptr);
+  window_tree_client_->ConnectAsWindowManager(connector);
 }
 
 bool MusDemo::AcceptConnection(shell::Connection* connection) {
@@ -73,36 +75,18 @@
 }
 
 void MusDemo::OnEmbed(mus::Window* window) {
-  window_ = window;
-
-  // Initialize bitmap uploader for sending frames to MUS.
-  uploader_.reset(new bitmap_uploader::BitmapUploader(window_));
-  uploader_->Init(connector_);
-
-  // Draw initial frame and start the timer to regularly draw frames.
-  DrawFrame();
-  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kFrameDelay),
-               base::Bind(&MusDemo::DrawFrame, base::Unretained(this)));
+  // Not called for the WindowManager.
+  NOTREACHED();
 }
 
-void MusDemo::OnUnembed(mus::Window* root) {}
-
 void MusDemo::OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) {
+  window_tree_client_ = nullptr;
   timer_.Stop();
 }
 
 void MusDemo::OnEventObserved(const ui::Event& event, mus::Window* target) {}
 
-// mus::mojom::WindowManagerFactory:
-void MusDemo::CreateWindowManager(mus::mojom::DisplayPtr display,
-                                  mus::mojom::WindowTreeClientRequest request) {
-  new mus::WindowTreeClient(this, this, std::move(request));
-}
-
-// mus::WindowManagerDelegate:
-void MusDemo::SetWindowManagerClient(mus::WindowManagerClient* client) {
-  window_manager_client_ = client;
-}
+void MusDemo::SetWindowManagerClient(mus::WindowManagerClient* client) {}
 
 bool MusDemo::OnWmSetBounds(mus::Window* window, gfx::Rect* bounds) {
   return true;
@@ -125,6 +109,21 @@
   // Don't care
 }
 
+void MusDemo::OnWmNewDisplay(mus::Window* window,
+                             const display::Display& display) {
+  DCHECK(!window_);  // Only support one display.
+  window_ = window;
+
+  // Initialize bitmap uploader for sending frames to MUS.
+  uploader_.reset(new bitmap_uploader::BitmapUploader(window_));
+  uploader_->Init(connector_);
+
+  // Draw initial frame and start the timer to regularly draw frames.
+  DrawFrame();
+  timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kFrameDelay),
+               base::Bind(&MusDemo::DrawFrame, base::Unretained(this)));
+}
+
 void MusDemo::OnAccelerator(uint32_t id, const ui::Event& event) {
   // Don't care
 }
diff --git a/components/mus/demo/mus_demo.h b/components/mus/demo/mus_demo.h
index 28c9de2e..dbb62647 100644
--- a/components/mus/demo/mus_demo.h
+++ b/components/mus/demo/mus_demo.h
@@ -13,12 +13,8 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/timer/timer.h"
-#include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_manager_delegate.h"
 #include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/shell_client.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -32,7 +28,6 @@
 // window and draws a spinning square in the center of the window. Provides a
 // simple way to demonstrate that the graphic stack works as intended.
 class MusDemo : public shell::ShellClient,
-                public mus::mojom::WindowManagerFactory,
                 public mus::WindowTreeClientDelegate,
                 public mus::WindowManagerDelegate {
  public:
@@ -48,15 +43,9 @@
 
   // WindowTreeClientDelegate:
   void OnEmbed(mus::Window* root) override;
-  void OnUnembed(mus::Window* root) override;
   void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override;
   void OnEventObserved(const ui::Event& event, mus::Window* target) override;
 
-  // mus::mojom::WindowManagerFactory:
-  void CreateWindowManager(
-      mus::mojom::DisplayPtr display,
-      mus::mojom::WindowTreeClientRequest request) override;
-
   // WindowManagerDelegate:
   void SetWindowManagerClient(mus::WindowManagerClient* client) override;
   bool OnWmSetBounds(mus::Window* window, gfx::Rect* bounds) override;
@@ -68,6 +57,8 @@
       std::map<std::string, std::vector<uint8_t>>* properties) override;
   void OnWmClientJankinessChanged(const std::set<mus::Window*>& client_windows,
                                   bool janky) override;
+  void OnWmNewDisplay(mus::Window* window,
+                      const display::Display& display) override;
   void OnAccelerator(uint32_t id, const ui::Event& event) override;
 
   // Allocate a bitmap the same size as the window to draw into.
@@ -79,9 +70,7 @@
   shell::Connector* connector_ = nullptr;
 
   mus::Window* window_ = nullptr;
-  mus::WindowManagerClient* window_manager_client_ = nullptr;
-  mojo::Binding<mus::mojom::WindowManagerFactory>
-      window_manager_factory_binding_;
+  mus::WindowTreeClient* window_tree_client_ = nullptr;
 
   // Used to send frames to mus.
   std::unique_ptr<bitmap_uploader::BitmapUploader> uploader_;
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index 75f2192..de22b9a9 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -199,7 +199,7 @@
   connection->AddInterface<mojom::DisplayManager>(this);
   connection->AddInterface<mojom::UserAccessManager>(this);
   connection->AddInterface<WindowTreeHostFactory>(this);
-  connection->AddInterface<mojom::WindowManagerFactoryService>(this);
+  connection->AddInterface<mojom::WindowManagerWindowTreeFactory>(this);
   connection->AddInterface<mojom::WindowTreeFactory>(this);
   if (test_config_)
     connection->AddInterface<WindowServerTest>(this);
@@ -272,9 +272,9 @@
 }
 
 void MusApp::Create(shell::Connection* connection,
-                    mojom::WindowManagerFactoryServiceRequest request) {
+                    mojom::WindowManagerWindowTreeFactoryRequest request) {
   AddUserIfNecessary(connection);
-  window_server_->window_manager_factory_registry()->Register(
+  window_server_->window_manager_window_tree_factory_set()->Add(
       connection->GetRemoteIdentity().user_id(), std::move(request));
 }
 
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h
index 3a5285f..a87bf27 100644
--- a/components/mus/mus_app.h
+++ b/components/mus/mus_app.h
@@ -18,7 +18,7 @@
 #include "components/mus/public/interfaces/gpu.mojom.h"
 #include "components/mus/public/interfaces/gpu_service.mojom.h"
 #include "components/mus/public/interfaces/user_access_manager.mojom.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
+#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
 #include "components/mus/public/interfaces/window_server_test.mojom.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "components/mus/public/interfaces/window_tree_host.mojom.h"
@@ -61,7 +61,7 @@
       public shell::InterfaceFactory<mojom::Gpu>,
       public shell::InterfaceFactory<mojom::GpuService>,
       public shell::InterfaceFactory<mojom::UserAccessManager>,
-      public shell::InterfaceFactory<mojom::WindowManagerFactoryService>,
+      public shell::InterfaceFactory<mojom::WindowManagerWindowTreeFactory>,
       public shell::InterfaceFactory<mojom::WindowTreeFactory>,
       public shell::InterfaceFactory<mojom::WindowTreeHostFactory>,
       public shell::InterfaceFactory<mojom::WindowServerTest> {
@@ -119,9 +119,10 @@
   void Create(shell::Connection* connection,
               mojom::UserAccessManagerRequest request) override;
 
-  // shell::InterfaceFactory<mojom::WindowManagerFactoryService> implementation.
+  // shell::InterfaceFactory<mojom::WindowManagerWindowTreeFactory>
+  // implementation.
   void Create(shell::Connection* connection,
-              mojom::WindowManagerFactoryServiceRequest request) override;
+              mojom::WindowManagerWindowTreeFactoryRequest request) override;
 
   // shell::InterfaceFactory<mojom::WindowTreeFactory>:
   void Create(shell::Connection* connection,
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index 0da736f..1d5b6df 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -64,6 +64,7 @@
     "//gpu/ipc/client",
     "//services/shell/public/cpp",
     "//ui/display",
+    "//ui/display/mojo",
     "//ui/events",
     "//ui/gfx/geometry",
   ]
diff --git a/components/mus/public/cpp/lib/in_flight_change.cc b/components/mus/public/cpp/lib/in_flight_change.cc
index 27b4a69..0487874 100644
--- a/components/mus/public/cpp/lib/in_flight_change.cc
+++ b/components/mus/public/cpp/lib/in_flight_change.cc
@@ -51,6 +51,7 @@
 }
 
 void CrashInFlightChange::ChangeFailed() {
+  DLOG(ERROR) << "changed failed, type=" << static_cast<int>(change_type());
   CHECK(false);
 }
 
diff --git a/components/mus/public/cpp/lib/window_tree_client.cc b/components/mus/public/cpp/lib/window_tree_client.cc
index 5ed5eae..95c6324 100644
--- a/components/mus/public/cpp/lib/window_tree_client.cc
+++ b/components/mus/public/cpp/lib/window_tree_client.cc
@@ -21,7 +21,9 @@
 #include "components/mus/public/cpp/window_tracker.h"
 #include "components/mus/public/cpp/window_tree_client_delegate.h"
 #include "components/mus/public/cpp/window_tree_client_observer.h"
+#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
 #include "services/shell/public/cpp/connector.h"
+#include "ui/display/mojo/display_type_converters.h"
 #include "ui/events/event.h"
 #include "ui/gfx/geometry/insets.h"
 #include "ui/gfx/geometry/size.h"
@@ -94,7 +96,7 @@
       focused_window_(nullptr),
       binding_(this),
       tree_(nullptr),
-      delete_on_no_roots_(true),
+      delete_on_no_roots_(!window_manager_delegate),
       in_destructor_(false),
       cursor_location_memory_(nullptr),
       weak_factory_(this) {
@@ -143,13 +145,21 @@
 
   mojom::WindowTreeFactoryPtr factory;
   connector->ConnectToInterface("mojo:mus", &factory);
-  factory->CreateWindowTree(GetProxy(&tree_ptr_),
+  mojom::WindowTreePtr window_tree;
+  factory->CreateWindowTree(GetProxy(&window_tree),
                             binding_.CreateInterfacePtrAndBind());
-  tree_ = tree_ptr_.get();
+  SetWindowTree(std::move(window_tree));
+}
 
-  tree_ptr_->GetCursorLocationMemory(
-      base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory,
-                 weak_factory_.GetWeakPtr()));
+void WindowTreeClient::ConnectAsWindowManager(shell::Connector* connector) {
+  DCHECK(window_manager_delegate_);
+
+  mojom::WindowManagerWindowTreeFactoryPtr factory;
+  connector->ConnectToInterface("mojo:mus", &factory);
+  mojom::WindowTreePtr window_tree;
+  factory->CreateWindowTree(GetProxy(&window_tree),
+                            binding_.CreateInterfacePtrAndBind());
+  SetWindowTree(std::move(window_tree));
 }
 
 void WindowTreeClient::WaitForEmbed() {
@@ -501,6 +511,27 @@
   return window;
 }
 
+void WindowTreeClient::SetWindowTree(mojom::WindowTreePtr window_tree_ptr) {
+  tree_ptr_ = std::move(window_tree_ptr);
+  tree_ = tree_ptr_.get();
+
+  tree_ptr_->GetCursorLocationMemory(
+      base::Bind(&WindowTreeClient::OnReceivedCursorLocationMemory,
+                 weak_factory_.GetWeakPtr()));
+
+  tree_ptr_.set_connection_error_handler(base::Bind(
+      &WindowTreeClient::OnConnectionLost, weak_factory_.GetWeakPtr()));
+
+  if (window_manager_delegate_) {
+    tree_ptr_->GetWindowManagerClient(GetProxy(&window_manager_internal_client_,
+                                               tree_ptr_.associated_group()));
+  }
+}
+
+void WindowTreeClient::OnConnectionLost() {
+  delete this;
+}
+
 void WindowTreeClient::OnEmbedImpl(mojom::WindowTree* window_tree,
                                        ClientSpecificId client_id,
                                        mojom::WindowDataPtr root_data,
@@ -529,6 +560,19 @@
   }
 }
 
+void WindowTreeClient::WmNewDisplayAddedImpl(const display::Display& display,
+                                             mojom::WindowDataPtr root_data,
+                                             bool parent_drawn) {
+  DCHECK(window_manager_delegate_);
+
+  Window* root = AddWindowToClient(this, nullptr, root_data);
+  WindowPrivate(root).LocalSetDisplay(display.id());
+  WindowPrivate(root).LocalSetParentDrawn(parent_drawn);
+  roots_.insert(root);
+
+  window_manager_delegate_->OnWmNewDisplay(root, display);
+}
+
 void WindowTreeClient::OnReceivedCursorLocationMemory(
     mojo::ScopedSharedBufferHandle handle) {
   cursor_location_handle_ = std::move(handle);
@@ -1000,6 +1044,17 @@
                     OnRequestClose(window));
 }
 
+void WindowTreeClient::OnConnect(ClientSpecificId client_id) {
+  client_id_ = client_id;
+}
+
+void WindowTreeClient::WmNewDisplayAdded(mojom::DisplayPtr display,
+                                         mojom::WindowDataPtr root_data,
+                                         bool parent_drawn) {
+  WmNewDisplayAddedImpl(display.To<display::Display>(), std::move(root_data),
+                        parent_drawn);
+}
+
 void WindowTreeClient::WmSetBounds(uint32_t change_id,
                                        Id window_id,
                                        const gfx::Rect& transit_bounds) {
diff --git a/components/mus/public/cpp/tests/BUILD.gn b/components/mus/public/cpp/tests/BUILD.gn
index ac6ea23..e5f756f 100644
--- a/components/mus/public/cpp/tests/BUILD.gn
+++ b/components/mus/public/cpp/tests/BUILD.gn
@@ -22,6 +22,7 @@
     "//base",
     "//components/mus/public/cpp",
     "//testing/gtest",
+    "//ui/display",
     "//ui/gfx/geometry/mojo",
   ]
 }
diff --git a/components/mus/public/cpp/tests/test_window_tree_client_setup.cc b/components/mus/public/cpp/tests/test_window_tree_client_setup.cc
index 7a2e9383..400f059 100644
--- a/components/mus/public/cpp/tests/test_window_tree_client_setup.cc
+++ b/components/mus/public/cpp/tests/test_window_tree_client_setup.cc
@@ -7,6 +7,7 @@
 #include "components/mus/public/cpp/tests/test_window_tree.h"
 #include "components/mus/public/cpp/tests/window_tree_client_private.h"
 #include "components/mus/public/cpp/window_tree_client.h"
+#include "ui/display/display.h"
 
 namespace mus {
 
@@ -20,6 +21,26 @@
 }
 
 void TestWindowTreeClientSetup::Init(
+    WindowTreeClientDelegate* window_tree_delegate) {
+  CommonInit(window_tree_delegate, nullptr);
+  WindowTreeClientPrivate(window_tree_client_.get())
+      .OnEmbed(window_tree_.get());
+}
+
+void TestWindowTreeClientSetup::InitForWindowManager(
+    WindowTreeClientDelegate* window_tree_delegate,
+    WindowManagerDelegate* window_manager_delegate,
+    const display::Display& display) {
+  CommonInit(window_tree_delegate, window_manager_delegate);
+  WindowTreeClientPrivate(window_tree_client_.get())
+      .SetTreeAndClientId(window_tree_.get(), 1);
+}
+
+WindowTreeClient* TestWindowTreeClientSetup::window_tree_client() {
+  return window_tree_client_.get();
+}
+
+void TestWindowTreeClientSetup::CommonInit(
     WindowTreeClientDelegate* window_tree_delegate,
     WindowManagerDelegate* window_manager_delegate) {
   window_tree_.reset(new TestWindowTree);
@@ -27,12 +48,6 @@
       window_tree_delegate, window_manager_delegate, nullptr));
   static_cast<WindowTreeClient*>(window_tree_client_.get())
       ->AddObserver(this);
-  WindowTreeClientPrivate(window_tree_client_.get())
-      .OnEmbed(window_tree_.get());
-}
-
-WindowTreeClient* TestWindowTreeClientSetup::window_tree_client() {
-  return window_tree_client_.get();
 }
 
 void TestWindowTreeClientSetup::OnWillDestroyClient(
diff --git a/components/mus/public/cpp/tests/test_window_tree_client_setup.h b/components/mus/public/cpp/tests/test_window_tree_client_setup.h
index 6886158..b2170cc 100644
--- a/components/mus/public/cpp/tests/test_window_tree_client_setup.h
+++ b/components/mus/public/cpp/tests/test_window_tree_client_setup.h
@@ -10,6 +10,10 @@
 #include "base/macros.h"
 #include "components/mus/public/cpp/window_tree_client_observer.h"
 
+namespace display {
+class Display;
+}
+
 namespace mus {
 
 class TestWindowTree;
@@ -24,10 +28,11 @@
   TestWindowTreeClientSetup();
   ~TestWindowTreeClientSetup() override;
 
-  // Initializes the WindowTreeClient. |window_manager_delegate| may be
-  // null.
-  void Init(WindowTreeClientDelegate* window_tree_delegate,
-            WindowManagerDelegate* window_manager_delegate);
+  // Initializes the WindowTreeClient.
+  void Init(WindowTreeClientDelegate* window_tree_delegate);
+  void InitForWindowManager(WindowTreeClientDelegate* window_tree_delegate,
+                            WindowManagerDelegate* window_manager_delegate,
+                            const display::Display& display);
 
   // The WindowTree that WindowTreeClient talks to.
   TestWindowTree* window_tree() { return window_tree_.get(); }
@@ -35,6 +40,10 @@
   WindowTreeClient* window_tree_client();
 
  private:
+  // Called by both implementations of init to perform common initialization.
+  void CommonInit(WindowTreeClientDelegate* window_tree_delegate,
+                  WindowManagerDelegate* window_manager_delegate);
+
   // mus::WindowTreeClientObserver:
   void OnWillDestroyClient(mus::WindowTreeClient* client) override;
 
diff --git a/components/mus/public/cpp/tests/window_server_test_base.cc b/components/mus/public/cpp/tests/window_server_test_base.cc
index 9770bbd..93394f7 100644
--- a/components/mus/public/cpp/tests/window_server_test_base.cc
+++ b/components/mus/public/cpp/tests/window_server_test_base.cc
@@ -126,6 +126,12 @@
     window_manager_delegate_->OnWmClientJankinessChanged(client_windows, janky);
 }
 
+void WindowServerTestBase::OnWmNewDisplay(Window* window,
+                                          const display::Display& display) {
+  if (window_manager_delegate_)
+    window_manager_delegate_->OnWmNewDisplay(window, display);
+}
+
 void WindowServerTestBase::OnAccelerator(uint32_t id, const ui::Event& event) {
   if (window_manager_delegate_)
     window_manager_delegate_->OnAccelerator(id, event);
diff --git a/components/mus/public/cpp/tests/window_server_test_base.h b/components/mus/public/cpp/tests/window_server_test_base.h
index 3e38e72e..ed24480 100644
--- a/components/mus/public/cpp/tests/window_server_test_base.h
+++ b/components/mus/public/cpp/tests/window_server_test_base.h
@@ -81,6 +81,7 @@
       std::map<std::string, std::vector<uint8_t>>* properties) override;
   void OnWmClientJankinessChanged(const std::set<Window*>& client_windows,
                                   bool not_responding) override;
+  void OnWmNewDisplay(Window* window, const display::Display& display) override;
   void OnAccelerator(uint32_t id, const ui::Event& event) override;
 
   // InterfaceFactory<WindowTreeClient>:
diff --git a/components/mus/public/cpp/tests/window_tree_client_private.cc b/components/mus/public/cpp/tests/window_tree_client_private.cc
index 3d2e2bd..eafd2a6 100644
--- a/components/mus/public/cpp/tests/window_tree_client_private.cc
+++ b/components/mus/public/cpp/tests/window_tree_client_private.cc
@@ -6,6 +6,7 @@
 
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_client.h"
+#include "ui/display/display.h"
 
 namespace mus {
 
@@ -34,6 +35,19 @@
                                  display_id, focused_window_id, true);
 }
 
+void WindowTreeClientPrivate::CallWmNewDisplayAdded(
+    const display::Display& display) {
+  mojom::WindowDataPtr root_data(mojom::WindowData::New());
+  root_data->parent_id = 0;
+  root_data->window_id = 1;
+  root_data->properties.SetToEmpty();
+  root_data->visible = true;
+  root_data->bounds = gfx::Rect(display.bounds().size());
+  const bool parent_drawn = true;
+  tree_client_impl_->WmNewDisplayAddedImpl(display, std::move(root_data),
+                                           parent_drawn);
+}
+
 void WindowTreeClientPrivate::CallOnWindowInputEvent(
     Window* window,
     std::unique_ptr<ui::Event> event) {
@@ -43,4 +57,10 @@
                                         std::move(event), observer_id);
 }
 
+void WindowTreeClientPrivate::SetTreeAndClientId(mojom::WindowTree* window_tree,
+                                                 ClientSpecificId client_id) {
+  tree_client_impl_->tree_ = window_tree;
+  tree_client_impl_->client_id_ = client_id;
+}
+
 }  // namespace mus
diff --git a/components/mus/public/cpp/tests/window_tree_client_private.h b/components/mus/public/cpp/tests/window_tree_client_private.h
index 7cec901..0612bbf 100644
--- a/components/mus/public/cpp/tests/window_tree_client_private.h
+++ b/components/mus/public/cpp/tests/window_tree_client_private.h
@@ -10,6 +10,11 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/mus/common/types.h"
+
+namespace display {
+class Display;
+}
 
 namespace ui {
 class Event;
@@ -35,9 +40,15 @@
   // Calls OnEmbed() on the WindowTreeClient.
   void OnEmbed(mojom::WindowTree* window_tree);
 
+  void CallWmNewDisplayAdded(const display::Display& display);
+
   // Pretends that |event| has been received from the window server.
   void CallOnWindowInputEvent(Window* window, std::unique_ptr<ui::Event> event);
 
+  // Sets the WindowTree and client id.
+  void SetTreeAndClientId(mojom::WindowTree* window_tree,
+                          ClientSpecificId client_id);
+
  private:
    WindowTreeClient* tree_client_impl_;
 
diff --git a/components/mus/public/cpp/window_manager_delegate.h b/components/mus/public/cpp/window_manager_delegate.h
index c68d983..99ddf34c 100644
--- a/components/mus/public/cpp/window_manager_delegate.h
+++ b/components/mus/public/cpp/window_manager_delegate.h
@@ -18,6 +18,10 @@
 #include "components/mus/public/interfaces/window_manager_constants.mojom.h"
 #include "ui/events/mojo/event.mojom.h"
 
+namespace display {
+class Display;
+}
+
 namespace gfx {
 class Insets;
 class Rect;
@@ -96,6 +100,11 @@
       const std::set<Window*>& client_windows,
       bool janky) = 0;
 
+  // Called when a display is added. |window| is the root of the window tree for
+  // the specified display.
+  virtual void OnWmNewDisplay(Window* window,
+                              const display::Display& display) = 0;
+
   virtual void OnAccelerator(uint32_t id, const ui::Event& event) = 0;
 
  protected:
diff --git a/components/mus/public/cpp/window_tree_client.h b/components/mus/public/cpp/window_tree_client.h
index 436883d2..3d61596 100644
--- a/components/mus/public/cpp/window_tree_client.h
+++ b/components/mus/public/cpp/window_tree_client.h
@@ -23,6 +23,10 @@
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
+namespace display {
+class Display;
+}
+
 namespace gfx {
 class Insets;
 class Size;
@@ -39,7 +43,20 @@
 class WindowTreeClientObserver;
 enum class ChangeType;
 
-// Manages the connection with the Window Server service.
+// Manages the connection with mus.
+//
+// WindowTreeClient is deleted by any of the following:
+// . If all the roots of the connection are destroyed and the connection is
+//   configured to delete when there are no roots (true if the WindowTreeClient
+//   is created with a mojom::WindowTreeClientRequest). This happens
+//   if the owner of the roots Embed()s another app in all the roots, or all
+//   the roots are explicitly deleted.
+// . The connection to mus is lost.
+// . Explicitly by way of calling delete.
+//
+// When WindowTreeClient is deleted all windows are deleted (and observers
+// notified). This is followed by calling
+// WindowTreeClientDelegate::OnWindowTreeClientDestroyed().
 class WindowTreeClient : public mojom::WindowTreeClient,
                          public mojom::WindowManager,
                          public WindowManagerClient {
@@ -52,6 +69,9 @@
   // Establishes the connection by way of the WindowTreeFactory.
   void ConnectViaWindowTreeFactory(shell::Connector* connector);
 
+  // Establishes the connection by way of WindowManagerWindowTreeFactory.
+  void ConnectAsWindowManager(shell::Connector* connector);
+
   // Wait for OnEmbed(), returning when done.
   void WaitForEmbed();
 
@@ -206,6 +226,12 @@
   Window* NewWindowImpl(NewWindowType type,
                         const Window::SharedProperties* properties);
 
+  // Sets the mojom::WindowTree implementation.
+  void SetWindowTree(mojom::WindowTreePtr window_tree_ptr);
+
+  // Called when the mojom::WindowTree connection is lost, deletes this.
+  void OnConnectionLost();
+
   // OnEmbed() calls into this. Exposed as a separate function for testing.
   void OnEmbedImpl(mojom::WindowTree* window_tree,
                    ClientSpecificId client_id,
@@ -214,6 +240,11 @@
                    Id focused_window_id,
                    bool drawn);
 
+  // Called by WmNewDisplayAdded().
+  void WmNewDisplayAddedImpl(const display::Display& display,
+                             mojom::WindowDataPtr root_data,
+                             bool parent_drawn);
+
   void OnReceivedCursorLocationMemory(mojo::ScopedSharedBufferHandle handle);
 
   // Overridden from WindowTreeClient:
@@ -273,6 +304,10 @@
       mojo::AssociatedInterfaceRequest<WindowManager> internal) override;
 
   // Overridden from WindowManager:
+  void OnConnect(ClientSpecificId client_id) override;
+  void WmNewDisplayAdded(mojom::DisplayPtr display,
+                         mojom::WindowDataPtr root_data,
+                         bool parent_drawn) override;
   void WmSetBounds(uint32_t change_id,
                    Id window_id,
                    const gfx::Rect& transit_bounds) override;
diff --git a/components/mus/public/cpp/window_tree_client_delegate.h b/components/mus/public/cpp/window_tree_client_delegate.h
index 877bd60..41f09df 100644
--- a/components/mus/public/cpp/window_tree_client_delegate.h
+++ b/components/mus/public/cpp/window_tree_client_delegate.h
@@ -19,19 +19,7 @@
 class Window;
 class WindowTreeClient;
 
-// Interface implemented by an application using the window manager.
-//
-// WindowTreeClient is deleted by any of the following:
-// . If all the roots of the connection are destroyed and the connection is
-//   configured to delete when there are no roots (the default). This happens
-//   if the owner of the roots Embed()s another app in all the roots, or all
-//   the roots are explicitly deleted.
-// . The connection to the window manager is lost.
-// . Explicitly by way of calling delete.
-//
-// When the WindowTreeClient is deleted all windows are deleted (and observers
-// notified). This is followed by notifying the delegate by way of
-// OnClientDestroyed().
+// Interface implemented by an application using mus.
 class WindowTreeClientDelegate {
  public:
   // Called when the application implementing this interface is embedded at
diff --git a/components/mus/public/interfaces/BUILD.gn b/components/mus/public/interfaces/BUILD.gn
index d98a2c7..bb10b56 100644
--- a/components/mus/public/interfaces/BUILD.gn
+++ b/components/mus/public/interfaces/BUILD.gn
@@ -21,9 +21,10 @@
     "user_access_manager.mojom",
     "window_manager.mojom",
     "window_manager_constants.mojom",
-    "window_manager_factory.mojom",
+    "window_manager_window_tree_factory.mojom",
     "window_server_test.mojom",
     "window_tree.mojom",
+    "window_tree_constants.mojom",
     "window_tree_host.mojom",
   ]
 
diff --git a/components/mus/public/interfaces/window_manager.mojom b/components/mus/public/interfaces/window_manager.mojom
index 571ca35..ed0ffe1 100644
--- a/components/mus/public/interfaces/window_manager.mojom
+++ b/components/mus/public/interfaces/window_manager.mojom
@@ -7,6 +7,7 @@
 import "components/mus/public/interfaces/cursor.mojom";
 import "components/mus/public/interfaces/event_matcher.mojom";
 import "components/mus/public/interfaces/window_manager_constants.mojom";
+import "components/mus/public/interfaces/window_tree_constants.mojom";
 import "ui/events/mojo/event.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
@@ -54,6 +55,13 @@
   // and the client area should be equivalent to the window area. Type: bool
   const string kRemoveStandardFrame_Property = "prop:remove-standard-frame";
 
+  // Called immediately when the WindowManager is obtained.
+  OnConnect(uint16 client_id);
+
+  // Called when a new display is added. |root| gives the root window specific
+  // to this WindowManager for |display|.
+  WmNewDisplayAdded(Display display, WindowData root, bool parent_drawn);
+
   // When the WindowManager completes a request it must call back to
   // WindowManagerClient::WmResponse().
   WmSetBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds);
diff --git a/components/mus/public/interfaces/window_manager_factory.mojom b/components/mus/public/interfaces/window_manager_factory.mojom
deleted file mode 100644
index 718d7c81..0000000
--- a/components/mus/public/interfaces/window_manager_factory.mojom
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module mus.mojom;
-
-import "components/mus/public/interfaces/window_manager_constants.mojom";
-import "components/mus/public/interfaces/window_tree.mojom";
-
-// Used to register the WindowManagerFactory that is used as displays are
-// added.
-// NOTE: The WindowManagerFactoryService can only be obtained once, further
-// SetWindowManagerFactory() can only be called once as well.
-interface WindowManagerFactoryService {
-  SetWindowManagerFactory(WindowManagerFactory factory);
-};
-
-// When a new display is detected WindowManagerFactory is used to bind the
-// root window of the display to a WindowTreeClient, and then obtain a
-// WindowManager from the WindowTreeClient.
-interface WindowManagerFactory {
-  CreateWindowManager(Display display, WindowTreeClient& client);
-};
diff --git a/components/mus/public/interfaces/window_manager_window_tree_factory.mojom b/components/mus/public/interfaces/window_manager_window_tree_factory.mojom
new file mode 100644
index 0000000..7e875f4
--- /dev/null
+++ b/components/mus/public/interfaces/window_manager_window_tree_factory.mojom
@@ -0,0 +1,16 @@
+// 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.
+
+module mus.mojom;
+
+import "components/mus/public/interfaces/window_manager_constants.mojom";
+import "components/mus/public/interfaces/window_tree.mojom";
+
+// Interface used by the WindowManager to obtain a WindowTree. The
+// WindowManager is informed of the roots (one per display) by way of
+// WmNewDisplayAdded(). See it for details.
+interface WindowManagerWindowTreeFactory {
+  // NOTE: it is expected this is called only once.
+  CreateWindowTree(WindowTree& tree_request, WindowTreeClient client);
+};
diff --git a/components/mus/public/interfaces/window_tree.mojom b/components/mus/public/interfaces/window_tree.mojom
index 8aaa8b3..3313253 100644
--- a/components/mus/public/interfaces/window_tree.mojom
+++ b/components/mus/public/interfaces/window_tree.mojom
@@ -11,47 +11,11 @@
 import "components/mus/public/interfaces/mus_constants.mojom";
 import "components/mus/public/interfaces/window_manager.mojom";
 import "components/mus/public/interfaces/window_manager_constants.mojom";
+import "components/mus/public/interfaces/window_tree_constants.mojom";
 import "ui/events/mojo/event.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 import "ui/platform_window/mojo/text_input_state.mojom";
 
-struct WindowData {
-  uint32 parent_id;
-  uint32 window_id;
-  gfx.mojom.Rect bounds;
-  map<string, array<uint8>> properties;
-  // True if this window is visible. The window may not be drawn on screen (see
-  // OnWindowParentDrawnStateChanged() for details).
-  bool visible;
-};
-
-enum ErrorCode {
-  NONE,
-  VALUE_IN_USE,
-  ILLEGAL_ARGUMENT,
-};
-
-// Each Window has support for two surfaces. Generally the |DEFAULT| surface
-// is used. The |UNDERLAY| surface is useful if the owner of a window wants to
-// to Embed() another client and at the same time draw something under the
-// embedded apps representation.
-enum SurfaceType {
-  // Only the owner of a window may obtain this surface.
-  // The window manager can change the offset of this by way of
-  // SetUnderlaySurfaceOffsetAndExtendedHitArea().
-  UNDERLAY,
-
-  // Only the embedded app may obtain this surface. If an app is not embedded
-  // in the Window than the owner may also render to this surface as well.
-  DEFAULT,
-};
-
-// The result of an input event sent to a client app.
-enum EventResult {
-  HANDLED,
-  UNHANDLED,
-};
-
 // Windows are identified by a uint32. The upper 16 bits are the connection id,
 // and the lower 16 the id assigned by the client.
 //
diff --git a/components/mus/public/interfaces/window_tree_constants.mojom b/components/mus/public/interfaces/window_tree_constants.mojom
new file mode 100644
index 0000000..a4540aa
--- /dev/null
+++ b/components/mus/public/interfaces/window_tree_constants.mojom
@@ -0,0 +1,49 @@
+// 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.
+
+module mus.mojom;
+
+import "ui/gfx/geometry/mojo/geometry.mojom";
+
+// Contains state of a single window.
+struct WindowData {
+  // Unique identifier of the parent. If the client can not see the parent an
+  // id of 0 is supplied.
+  uint32 parent_id;
+
+  // Unique identifier of the window.
+  uint32 window_id;
+
+  gfx.mojom.Rect bounds;
+
+  // Arbitrary key/value pairs. The interpretation of these is left to the
+  // client. See SetWindowProperty() for more information.
+  map<string, array<uint8>> properties;
+
+  // True if this window is visible. The window may not be drawn on screen (see
+  // OnWindowParentDrawnStateChanged() for details).
+  bool visible;
+};
+
+// Each Window has support for two surfaces. Generally the |DEFAULT| surface
+// is used. The |UNDERLAY| surface is useful if the owner of a window wants to
+// to Embed() another client and at the same time draw something under the
+// embedded apps representation.
+enum SurfaceType {
+  // Only the owner of a window may obtain this surface.
+  // The window manager can change the offset of this by way of
+  // SetUnderlaySurfaceOffsetAndExtendedHitArea().
+  UNDERLAY,
+
+  // Only the embedded app may obtain this surface. If an app is not embedded
+  // in the Window than the owner may also render to this surface as well.
+  DEFAULT,
+};
+
+// The result of an input event sent to a client app.
+enum EventResult {
+  HANDLED,
+  UNHANDLED,
+};
+
diff --git a/components/mus/surfaces/direct_output_surface.cc b/components/mus/surfaces/direct_output_surface.cc
index 0f26e3c9..2f2b02f 100644
--- a/components/mus/surfaces/direct_output_surface.cc
+++ b/components/mus/surfaces/direct_output_surface.cc
@@ -11,7 +11,7 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface_client.h"
-#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "gpu/command_buffer/client/context_support.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 
@@ -19,22 +19,19 @@
 
 DirectOutputSurface::DirectOutputSurface(
     scoped_refptr<SurfacesContextProvider> context_provider,
-    base::SingleThreadTaskRunner* task_runner)
+    cc::SyntheticBeginFrameSource* synthetic_begin_frame_source)
     : cc::OutputSurface(context_provider, nullptr, nullptr),
-      synthetic_begin_frame_source_(new cc::DelayBasedBeginFrameSource(
-          base::MakeUnique<cc::DelayBasedTimeSource>(task_runner))),
+      synthetic_begin_frame_source_(synthetic_begin_frame_source),
       weak_ptr_factory_(this) {
   context_provider->SetDelegate(this);
 }
 
-DirectOutputSurface::~DirectOutputSurface() {}
+DirectOutputSurface::~DirectOutputSurface() = default;
 
 bool DirectOutputSurface::BindToClient(cc::OutputSurfaceClient* client) {
   if (!cc::OutputSurface::BindToClient(client))
     return false;
 
-  client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
-
   if (capabilities_.uses_default_gl_framebuffer) {
     capabilities_.flipped_output_surface =
         context_provider()->ContextCapabilities().flips_vertically;
diff --git a/components/mus/surfaces/direct_output_surface.h b/components/mus/surfaces/direct_output_surface.h
index 38ca523..03e7110 100644
--- a/components/mus/surfaces/direct_output_surface.h
+++ b/components/mus/surfaces/direct_output_surface.h
@@ -8,10 +8,14 @@
 #include <memory>
 
 #include "cc/output/output_surface.h"
-#include "cc/scheduler/begin_frame_source.h"
 #include "components/mus/surfaces/surfaces_context_provider.h"
 #include "components/mus/surfaces/surfaces_context_provider_delegate.h"
 
+namespace cc {
+class CompositorFrame;
+class SyntheticBeginFrameSource;
+}
+
 namespace mus {
 
 // An OutputSurface implementation that directly draws and
@@ -21,7 +25,7 @@
  public:
   explicit DirectOutputSurface(
       scoped_refptr<SurfacesContextProvider> context_provider,
-      base::SingleThreadTaskRunner* task_runner);
+      cc::SyntheticBeginFrameSource* synthetic_begin_frame_source);
   ~DirectOutputSurface() override;
 
   // cc::OutputSurface implementation
@@ -33,7 +37,7 @@
                                 const base::TimeDelta& interval) override;
 
  private:
-  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source_;
+  cc::SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
   base::WeakPtrFactory<DirectOutputSurface> weak_ptr_factory_;
 };
 
diff --git a/components/mus/surfaces/direct_output_surface_ozone.cc b/components/mus/surfaces/direct_output_surface_ozone.cc
index a8c601d..48af7d77 100644
--- a/components/mus/surfaces/direct_output_surface_ozone.cc
+++ b/components/mus/surfaces/direct_output_surface_ozone.cc
@@ -11,7 +11,7 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface_client.h"
-#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "components/display_compositor/buffer_queue.h"
 #include "components/mus/common/gpu_service.h"
 #include "components/mus/common/mojo_gpu_memory_buffer_manager.h"
@@ -27,14 +27,13 @@
 DirectOutputSurfaceOzone::DirectOutputSurfaceOzone(
     scoped_refptr<SurfacesContextProvider> context_provider,
     gfx::AcceleratedWidget widget,
-    base::SingleThreadTaskRunner* task_runner,
+    cc::SyntheticBeginFrameSource* synthetic_begin_frame_source,
     uint32_t target,
     uint32_t internalformat)
     : cc::OutputSurface(context_provider, nullptr, nullptr),
       gl_helper_(context_provider->ContextGL(),
                  context_provider->ContextSupport()),
-      synthetic_begin_frame_source_(new cc::DelayBasedBeginFrameSource(
-          base::MakeUnique<cc::DelayBasedTimeSource>(task_runner))),
+      synthetic_begin_frame_source_(synthetic_begin_frame_source),
       weak_ptr_factory_(this) {
   if (!GpuService::UseChromeGpuCommandBuffer()) {
     ozone_gpu_memory_buffer_manager_.reset(new OzoneGpuMemoryBufferManager());
@@ -108,8 +107,6 @@
   if (!cc::OutputSurface::BindToClient(client))
     return false;
 
-  client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
-
   if (capabilities_.uses_default_gl_framebuffer) {
     capabilities_.flipped_output_surface =
         context_provider()->ContextCapabilities().flips_vertically;
diff --git a/components/mus/surfaces/direct_output_surface_ozone.h b/components/mus/surfaces/direct_output_surface_ozone.h
index 92113df..30931d3 100644
--- a/components/mus/surfaces/direct_output_surface_ozone.h
+++ b/components/mus/surfaces/direct_output_surface_ozone.h
@@ -10,7 +10,6 @@
 #include "base/memory/weak_ptr.h"
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface.h"
-#include "cc/scheduler/begin_frame_source.h"
 #include "components/display_compositor/gl_helper.h"
 #include "components/mus/surfaces/ozone_gpu_memory_buffer_manager.h"
 #include "ui/gfx/geometry/size.h"
@@ -28,6 +27,7 @@
 
 namespace cc {
 class CompositorFrame;
+class SyntheticBeginFrameSource;
 }  // namespace cc
 
 namespace mus {
@@ -43,7 +43,7 @@
   DirectOutputSurfaceOzone(
       scoped_refptr<SurfacesContextProvider> context_provider,
       gfx::AcceleratedWidget widget,
-      base::SingleThreadTaskRunner* task_runner,
+      cc::SyntheticBeginFrameSource* synthetic_begin_frame_source,
       uint32_t target,
       uint32_t internalformat);
 
@@ -70,7 +70,7 @@
   display_compositor::GLHelper gl_helper_;
   std::unique_ptr<OzoneGpuMemoryBufferManager> ozone_gpu_memory_buffer_manager_;
   std::unique_ptr<display_compositor::BufferQueue> buffer_queue_;
-  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source_;
+  cc::SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
 
   base::WeakPtrFactory<DirectOutputSurfaceOzone> weak_ptr_factory_;
 };
diff --git a/components/mus/surfaces/display_compositor.cc b/components/mus/surfaces/display_compositor.cc
index 79e052305..c8f17740c 100644
--- a/components/mus/surfaces/display_compositor.cc
+++ b/components/mus/surfaces/display_compositor.cc
@@ -7,7 +7,11 @@
 #include "cc/output/copy_output_request.h"
 #include "cc/output/output_surface.h"
 #include "cc/output/renderer_settings.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/scheduler/delay_based_time_source.h"
 #include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "components/mus/surfaces/direct_output_surface.h"
 #include "components/mus/surfaces/surfaces_context_provider.h"
 
@@ -36,32 +40,39 @@
   // TODO(rjkroege): If there is something better to do than CHECK, add it.
   CHECK(surfaces_context_provider->BindToCurrentThread());
 
+  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source(
+      new cc::DelayBasedBeginFrameSource(
+          base::MakeUnique<cc::DelayBasedTimeSource>(task_runner_.get())));
+
   std::unique_ptr<cc::OutputSurface> display_output_surface;
   if (surfaces_context_provider->ContextCapabilities().surfaceless) {
 #if defined(USE_OZONE)
     display_output_surface = base::WrapUnique(new DirectOutputSurfaceOzone(
-        surfaces_context_provider, widget, task_runner_.get(), GL_TEXTURE_2D,
-        GL_RGB));
+        surfaces_context_provider, widget, synthetic_begin_frame_source.get(),
+        GL_TEXTURE_2D, GL_RGB));
 #else
     NOTREACHED();
 #endif
   } else {
-    display_output_surface = base::WrapUnique(
-        new DirectOutputSurface(surfaces_context_provider, task_runner_.get()));
+    display_output_surface = base::WrapUnique(new DirectOutputSurface(
+        surfaces_context_provider, synthetic_begin_frame_source.get()));
   }
 
   int max_frames_pending =
       display_output_surface->capabilities().max_frames_pending;
   DCHECK_GT(max_frames_pending, 0);
 
-  display_.reset(
-      new cc::Display(surfaces_state_->manager(), nullptr /* bitmap_manager */,
-                      nullptr /* gpu_memory_buffer_manager */,
-                      cc::RendererSettings(), allocator_.id_namespace(),
-                      task_runner_.get(), std::move(display_output_surface)));
+  std::unique_ptr<cc::DisplayScheduler> scheduler(
+      new cc::DisplayScheduler(synthetic_begin_frame_source.get(),
+                               task_runner_.get(), max_frames_pending));
 
-  bool init = display_->Initialize(this);
-  DCHECK(init);  // The context provider was already bound above.
+  display_.reset(new cc::Display(
+      surfaces_state_->manager(), nullptr /* bitmap_manager */,
+      nullptr /* gpu_memory_buffer_manager */, cc::RendererSettings(),
+      allocator_.id_namespace(), std::move(synthetic_begin_frame_source),
+      std::move(display_output_surface), std::move(scheduler),
+      base::MakeUnique<cc::TextureMailboxDeleter>(task_runner_.get())));
+  display_->Initialize(this);
 }
 
 DisplayCompositor::~DisplayCompositor() {
diff --git a/components/mus/test_wm/manifest.json b/components/mus/test_wm/manifest.json
index fde1cf3..67f2fa9 100644
--- a/components/mus/test_wm/manifest.json
+++ b/components/mus/test_wm/manifest.json
@@ -4,7 +4,7 @@
   "display_name": "Test Window Manager",
   "capabilities": {
     "required": {
-      "mojo:mus": { "interfaces": [ "mus::mojom::WindowManagerFactoryService" ] }
+      "mojo:mus": { "interfaces": [ "mus::mojom::WindowManagerWindowTreeFactory" ] }
     }
   }
 }
diff --git a/components/mus/test_wm/test_wm.cc b/components/mus/test_wm/test_wm.cc
index dfca459..39ad3759 100644
--- a/components/mus/test_wm/test_wm.cc
+++ b/components/mus/test_wm/test_wm.cc
@@ -6,7 +6,6 @@
 #include "components/mus/public/cpp/window_manager_delegate.h"
 #include "components/mus/public/cpp/window_tree_client.h"
 #include "components/mus/public/cpp/window_tree_client_delegate.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
 #include "mojo/public/c/system/main.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/shell/public/cpp/application_runner.h"
@@ -19,45 +18,33 @@
 namespace test {
 
 class TestWM : public shell::ShellClient,
-               public mus::mojom::WindowManagerFactory,
                public mus::WindowTreeClientDelegate,
                public mus::WindowManagerDelegate {
  public:
-  TestWM() : window_manager_factory_binding_(this) {}
-  ~TestWM() override {}
+  TestWM() {}
+  ~TestWM() override { delete window_tree_client_; }
 
  private:
   // shell::ShellClient:
   void Initialize(shell::Connector* connector,
                   const shell::Identity& identity,
                   uint32_t id) override {
-    mus::mojom::WindowManagerFactoryServicePtr wm_factory_service;
-    connector->ConnectToInterface("mojo:mus", &wm_factory_service);
-    wm_factory_service->SetWindowManagerFactory(
-        window_manager_factory_binding_.CreateInterfacePtrAndBind());
+    window_tree_client_ = new mus::WindowTreeClient(this, this, nullptr);
+    window_tree_client_->ConnectAsWindowManager(connector);
   }
   bool AcceptConnection(shell::Connection* connection) override {
     return true;
   }
 
-  // mus::mojom::WindowManagerFactory:
-  void CreateWindowManager(
-      mus::mojom::DisplayPtr display,
-      mus::mojom::WindowTreeClientRequest request) override {
-    new mus::WindowTreeClient(this, this, std::move(request));
-  }
-
   // mus::WindowTreeClientDelegate:
   void OnEmbed(mus::Window* root) override {
-    root_ = root;
-    window_manager_client_->AddActivationParent(root_);
-    mus::mojom::FrameDecorationValuesPtr frame_decoration_values =
-        mus::mojom::FrameDecorationValues::New();
-    frame_decoration_values->max_title_bar_button_width = 0;
-    window_manager_client_->SetFrameDecorationValues(
-        std::move(frame_decoration_values));
+    // WindowTreeClients configured as the window manager should never get
+    // OnEmbed().
+    NOTREACHED();
   }
-  void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override {}
+  void OnWindowTreeClientDestroyed(mus::WindowTreeClient* client) override {
+    window_tree_client_ = nullptr;
+  }
   void OnEventObserved(const ui::Event& event, mus::Window* target) override {
     // Don't care.
   }
@@ -86,14 +73,27 @@
                                   bool janky) override {
     // Don't care.
   }
+  void OnWmNewDisplay(Window* window,
+                      const display::Display& display) override {
+    // Only handles a single root.
+    DCHECK(!root_);
+    root_ = window;
+    DCHECK(window_manager_client_);
+    window_manager_client_->AddActivationParent(root_);
+    mus::mojom::FrameDecorationValuesPtr frame_decoration_values =
+        mus::mojom::FrameDecorationValues::New();
+    frame_decoration_values->max_title_bar_button_width = 0;
+    window_manager_client_->SetFrameDecorationValues(
+        std::move(frame_decoration_values));
+  }
   void OnAccelerator(uint32_t id, const ui::Event& event) override {
     // Don't care.
   }
 
-  mojo::Binding<mus::mojom::WindowManagerFactory>
-      window_manager_factory_binding_;
   mus::Window* root_ = nullptr;
   mus::WindowManagerClient* window_manager_client_ = nullptr;
+  // See WindowTreeClient for details on ownership.
+  mus::WindowTreeClient* window_tree_client_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TestWM);
 };
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn
index 096fbdf..e9313537 100644
--- a/components/mus/ws/BUILD.gn
+++ b/components/mus/ws/BUILD.gn
@@ -68,13 +68,13 @@
     "window_finder.h",
     "window_manager_access_policy.cc",
     "window_manager_access_policy.h",
-    "window_manager_factory_registry.cc",
-    "window_manager_factory_registry.h",
-    "window_manager_factory_registry_observer.h",
-    "window_manager_factory_service.cc",
-    "window_manager_factory_service.h",
     "window_manager_state.cc",
     "window_manager_state.h",
+    "window_manager_window_tree_factory.cc",
+    "window_manager_window_tree_factory.h",
+    "window_manager_window_tree_factory_set.cc",
+    "window_manager_window_tree_factory_set.h",
+    "window_manager_window_tree_factory_set_observer.h",
     "window_server.cc",
     "window_server.h",
     "window_server_delegate.cc",
diff --git a/components/mus/ws/cursor_unittest.cc b/components/mus/ws/cursor_unittest.cc
index 5fcb54dc..909c4936 100644
--- a/components/mus/ws/cursor_unittest.cc
+++ b/components/mus/ws/cursor_unittest.cc
@@ -51,9 +51,9 @@
     window_server_delegate_.set_num_displays_to_create(1);
 
     // As a side effect, this allocates Displays.
-    WindowManagerFactoryRegistryTestApi(
-        window_server_->window_manager_factory_registry())
-        .AddService(kTestId1, &test_window_manager_factory_);
+    WindowManagerWindowTreeFactorySetTestApi(
+        window_server_->window_manager_window_tree_factory_set())
+        .Add(kTestId1);
     window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
   }
 
@@ -103,7 +103,6 @@
   TestWindowServerDelegate window_server_delegate_;
   std::unique_ptr<WindowServer> window_server_;
   base::MessageLoop message_loop_;
-  TestWindowManagerFactory test_window_manager_factory_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(CursorTest);
diff --git a/components/mus/ws/display.cc b/components/mus/ws/display.cc
index 879c19aa..45d116d 100644
--- a/components/mus/ws/display.cc
+++ b/components/mus/ws/display.cc
@@ -15,8 +15,8 @@
 #include "components/mus/ws/focus_controller.h"
 #include "components/mus/ws/platform_display.h"
 #include "components/mus/ws/platform_display_init_params.h"
-#include "components/mus/ws/window_manager_factory_service.h"
 #include "components/mus/ws/window_manager_state.h"
+#include "components/mus/ws/window_manager_window_tree_factory.h"
 #include "components/mus/ws/window_server.h"
 #include "components/mus/ws/window_server_delegate.h"
 #include "components/mus/ws/window_tree.h"
@@ -36,14 +36,15 @@
       last_cursor_(ui::kCursorNone) {
   platform_display_->Init(this);
 
-  window_server_->window_manager_factory_registry()->AddObserver(this);
+  window_server_->window_manager_window_tree_factory_set()->AddObserver(this);
   window_server_->user_id_tracker()->AddObserver(this);
 }
 
 Display::~Display() {
   window_server_->user_id_tracker()->RemoveObserver(this);
 
-  window_server_->window_manager_factory_registry()->RemoveObserver(this);
+  window_server_->window_manager_window_tree_factory_set()->RemoveObserver(
+      this);
 
   if (!focus_controller_) {
     focus_controller_->RemoveObserver(this);
@@ -231,31 +232,31 @@
     window_manager_state_map_[shell::mojom::kRootUserID] = std::move(wms_ptr);
     wms->tree_ = binding_->CreateWindowTree(wms->root());
   } else {
-    CreateWindowManagerStatesFromRegistry();
+    CreateWindowManagerStatesFromFactories();
   }
 }
 
-void Display::CreateWindowManagerStatesFromRegistry() {
-  std::vector<WindowManagerFactoryService*> services =
-      window_server_->window_manager_factory_registry()->GetServices();
-  for (WindowManagerFactoryService* service : services) {
-    if (service->window_manager_factory())
-      CreateWindowManagerStateFromService(service);
+void Display::CreateWindowManagerStatesFromFactories() {
+  std::vector<WindowManagerWindowTreeFactory*> factories =
+      window_server_->window_manager_window_tree_factory_set()->GetFactories();
+  for (WindowManagerWindowTreeFactory* factory : factories) {
+    if (factory->window_tree())
+      CreateWindowManagerStateFromFactory(factory);
   }
 }
 
-void Display::CreateWindowManagerStateFromService(
-    WindowManagerFactoryService* service) {
+void Display::CreateWindowManagerStateFromFactory(
+    WindowManagerWindowTreeFactory* factory) {
   std::unique_ptr<WindowManagerState> wms_ptr(new WindowManagerState(
-      this, platform_display_.get(), service->user_id()));
+      this, platform_display_.get(), factory->user_id()));
   WindowManagerState* wms = wms_ptr.get();
-  window_manager_state_map_[service->user_id()] = std::move(wms_ptr);
-  wms->tree_ = window_server_->CreateTreeForWindowManager(
-      this, service->window_manager_factory(), wms->root(), service->user_id());
+  window_manager_state_map_[factory->user_id()] = std::move(wms_ptr);
+  wms->tree_ = factory->window_tree();
   if (!binding_) {
     const bool is_active =
-        service->user_id() == window_server_->user_id_tracker()->active_id();
+        factory->user_id() == window_server_->user_id_tracker()->active_id();
     wms->root()->SetVisible(is_active);
+    wms->tree_->AddRootForWindowManager(wms->root());
   }
 }
 
@@ -444,9 +445,10 @@
   DCHECK_EQ(0u, window_manager_state_map_.count(id));
 }
 
-void Display::OnWindowManagerFactorySet(WindowManagerFactoryService* service) {
+void Display::OnWindowManagerWindowTreeFactoryReady(
+    WindowManagerWindowTreeFactory* factory) {
   if (!binding_)
-    CreateWindowManagerStateFromService(service);
+    CreateWindowManagerStateFromFactory(factory);
 }
 
 }  // namespace ws
diff --git a/components/mus/ws/display.h b/components/mus/ws/display.h
index fd7a641..c48b1904d 100644
--- a/components/mus/ws/display.h
+++ b/components/mus/ws/display.h
@@ -24,7 +24,7 @@
 #include "components/mus/ws/server_window_observer.h"
 #include "components/mus/ws/server_window_tracker.h"
 #include "components/mus/ws/user_id_tracker_observer.h"
-#include "components/mus/ws/window_manager_factory_registry_observer.h"
+#include "components/mus/ws/window_manager_window_tree_factory_set_observer.h"
 
 namespace mus {
 namespace ws {
@@ -56,7 +56,7 @@
                 public FocusControllerDelegate,
                 public ServerWindowObserver,
                 public UserIdTrackerObserver,
-                public WindowManagerFactoryRegistryObserver {
+                public WindowManagerWindowTreeFactorySetObserver {
  public:
   Display(WindowServer* window_server,
           const PlatformDisplayInitParams& platform_display_init_params);
@@ -148,11 +148,11 @@
   void InitWindowManagersIfNecessary();
 
   // Creates the set of WindowManagerStates from the
-  // WindowManagerFactoryRegistry.
-  void CreateWindowManagerStatesFromRegistry();
+  // WindowManagerWindowTreeFactorySet.
+  void CreateWindowManagerStatesFromFactories();
 
-  void CreateWindowManagerStateFromService(
-      WindowManagerFactoryService* service);
+  void CreateWindowManagerStateFromFactory(
+      WindowManagerWindowTreeFactory* factory);
 
   // PlatformDisplayDelegate:
   ServerWindow* GetRootWindow() override;
@@ -182,8 +182,9 @@
   void OnUserIdAdded(const UserId& id) override;
   void OnUserIdRemoved(const UserId& id) override;
 
-  // WindowManagerFactoryRegistryObserver:
-  void OnWindowManagerFactorySet(WindowManagerFactoryService* service) override;
+  // WindowManagerWindowTreeFactorySetObserver:
+  void OnWindowManagerWindowTreeFactoryReady(
+      WindowManagerWindowTreeFactory* factory) override;
 
   const uint32_t id_;
   std::unique_ptr<DisplayBinding> binding_;
diff --git a/components/mus/ws/display_unittest.cc b/components/mus/ws/display_unittest.cc
index 75a6fff..eef1da6 100644
--- a/components/mus/ws/display_unittest.cc
+++ b/components/mus/ws/display_unittest.cc
@@ -62,7 +62,6 @@
   TestWindowServerDelegate window_server_delegate_;
   std::unique_ptr<WindowServer> window_server_;
   base::MessageLoop message_loop_;
-  TestWindowManagerFactory test_window_manager_factory_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(DisplayTest);
@@ -75,9 +74,9 @@
   const UserId kTestId1 = "2";
   const UserId kTestId2 = "21";
   DisplayManager* display_manager = window_server_->display_manager();
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId1);
   // The first register should trigger creation of the default
   // Displays. There should be kNumHostsToCreate Displays.
   EXPECT_EQ(static_cast<size_t>(kNumHostsToCreate),
@@ -91,9 +90,9 @@
   }
 
   // Add another registry, should trigger creation of another wm.
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId2, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId2);
   for (Display* display : display_manager->displays()) {
     ASSERT_EQ(2u, display->num_window_manger_states());
     WindowManagerState* state1 =
@@ -113,15 +112,15 @@
 
   const UserId kTestId1 = "2";
   const UserId kTestId2 = "21";
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId1);
 
   // Add another registry, should trigger creation of another wm.
   DisplayManager* display_manager = window_server_->display_manager();
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId2, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId2);
   ASSERT_EQ(1u, display_manager->displays().size());
   Display* display = *display_manager->displays().begin();
   ASSERT_EQ(2u, display->num_window_manger_states());
@@ -151,12 +150,12 @@
 
   const UserId kTestId1 = "20";
   const UserId kTestId2 = "201";
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId1, &test_window_manager_factory_);
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId2, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId1);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId2);
 
   window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
 
@@ -196,12 +195,12 @@
   window_server_delegate_.set_num_displays_to_create(1);
   const UserId kTestId1 = "20";
   const UserId kTestId2 = "201";
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId1, &test_window_manager_factory_);
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId2, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId1);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId2);
   window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
   DisplayManager* display_manager = window_server_->display_manager();
   ASSERT_EQ(1u, display_manager->displays().size());
@@ -231,15 +230,15 @@
   window_server_delegate_.set_num_displays_to_create(1);
   const UserId kTestId1 = "20";
   const UserId kTestId2 = "201";
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId1);
   TestWindowTreeClient* window_tree_client1 =
       window_server_delegate_.last_client();
   ASSERT_TRUE(window_tree_client1);
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId2, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId2);
   window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
   DisplayManager* display_manager = window_server_->display_manager();
   ASSERT_EQ(1u, display_manager->displays().size());
@@ -268,59 +267,32 @@
   EXPECT_TRUE(wms_for_id1->tree()->SetFocus(child1_id));
 }
 
-// Verifies clients are notified of focus changes in different displays.
-TEST_F(DisplayTest, CrossDisplayFocus) {
+// Verifies a single tree is used for multiple displays.
+TEST_F(DisplayTest, MultipleDisplays) {
   window_server_delegate_.set_num_displays_to_create(2);
   const UserId kTestId1 = "20";
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kTestId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kTestId1);
   window_server_->user_id_tracker()->SetActiveUserId(kTestId1);
-  ASSERT_EQ(2u, window_server_delegate_.bindings()->size());
-  TestWindowTreeBinding* window_tree_binding1 =
+  ASSERT_EQ(1u, window_server_delegate_.bindings()->size());
+  TestWindowTreeBinding* window_tree_binding =
       (*window_server_delegate_.bindings())[0];
-  Display* display1 = window_tree_binding1->tree()->GetDisplay(
-      FirstRoot(window_tree_binding1->tree()));
+  WindowTree* tree = window_tree_binding->tree();
+  ASSERT_EQ(2u, tree->roots().size());
+  std::set<const ServerWindow*> roots = tree->roots();
+  auto it = roots.begin();
+  ServerWindow* root1 = tree->GetWindow((*it)->id());
+  ++it;
+  ServerWindow* root2 = tree->GetWindow((*it)->id());
+  ASSERT_NE(root1, root2);
+  Display* display1 = tree->GetDisplay(root1);
   WindowManagerState* display1_wms =
       display1->GetWindowManagerStateForUser(kTestId1);
-  TestWindowTreeBinding* window_tree_binding2 =
-      (*window_server_delegate_.bindings())[1];
-  Display* display2 = window_tree_binding2->tree()->GetDisplay(
-      FirstRoot(window_tree_binding2->tree()));
+  Display* display2 = tree->GetDisplay(root2);
   WindowManagerState* display2_wms =
       display2->GetWindowManagerStateForUser(kTestId1);
-
-  // Create children in both displays.
-  ClientWindowId child1_id;
-  ServerWindow* child1 = NewWindowInTree(display1_wms->tree(), &child1_id);
-  ASSERT_TRUE(child1);
-  child1->set_can_focus(true);
-  ClientWindowId child2_id;
-  ServerWindow* child2 = NewWindowInTree(display2_wms->tree(), &child2_id);
-  ASSERT_TRUE(child2);
-  child2->set_can_focus(true);
-
-  display1->AddActivationParent(FirstRoot(display1_wms->tree()));
-  display2->AddActivationParent(FirstRoot(display2_wms->tree()));
-  FirstRoot(display1_wms->tree())->set_can_focus(true);
-  FirstRoot(display2_wms->tree())->set_can_focus(true);
-  EXPECT_TRUE(display1_wms->tree()->SetFocus(child1_id));
-  EXPECT_EQ(child1, display1->GetFocusedWindow());
-  EXPECT_FALSE(display2->GetFocusedWindow());
-  window_tree_binding1->client()->tracker()->changes()->clear();
-  window_tree_binding2->client()->tracker()->changes()->clear();
-  // Moving focus to display2 should result in notifying display1.
-  EXPECT_TRUE(display2_wms->tree()->SetFocus(child2_id));
-  EXPECT_EQ("Focused id=null",
-            SingleChangeToDescription(
-                *window_tree_binding1->client()->tracker()->changes()));
-  EXPECT_EQ("", SingleChangeToDescription(
-                    *window_tree_binding2->client()->tracker()->changes()));
-  EXPECT_TRUE(window_tree_binding2->client()->tracker()->changes()->empty());
-  window_tree_binding1->client()->tracker()->changes()->clear();
-  window_tree_binding2->client()->tracker()->changes()->clear();
-  EXPECT_FALSE(display1->GetFocusedWindow());
-  EXPECT_EQ(child2, display2->GetFocusedWindow());
+  EXPECT_EQ(display1_wms->tree(), display2_wms->tree());
 }
 
 }  // namespace test
diff --git a/components/mus/ws/test_utils.cc b/components/mus/ws/test_utils.cc
index bf2d2022..f85f058b 100644
--- a/components/mus/ws/test_utils.cc
+++ b/components/mus/ws/test_utils.cc
@@ -8,9 +8,10 @@
 #include "cc/output/copy_output_request.h"
 #include "components/mus/surfaces/surfaces_state.h"
 #include "components/mus/ws/display_binding.h"
+#include "components/mus/ws/display_manager.h"
 #include "components/mus/ws/server_window_surface_manager_test_api.h"
 #include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_manager_factory_service.h"
+#include "components/mus/ws/window_manager_window_tree_factory.h"
 #include "services/shell/public/interfaces/connector.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -75,22 +76,22 @@
 
 }  // namespace
 
-// WindowManagerFactoryRegistryTestApi ----------------------------------------
+// WindowManagerWindowTreeFactorySetTestApi ------------------------------------
 
-WindowManagerFactoryRegistryTestApi::WindowManagerFactoryRegistryTestApi(
-    WindowManagerFactoryRegistry* registry)
-    : registry_(registry) {}
+WindowManagerWindowTreeFactorySetTestApi::
+    WindowManagerWindowTreeFactorySetTestApi(
+        WindowManagerWindowTreeFactorySet*
+            window_manager_window_tree_factory_set)
+    : window_manager_window_tree_factory_set_(
+          window_manager_window_tree_factory_set) {}
 
-WindowManagerFactoryRegistryTestApi::~WindowManagerFactoryRegistryTestApi() {}
+WindowManagerWindowTreeFactorySetTestApi::
+    ~WindowManagerWindowTreeFactorySetTestApi() {}
 
-void WindowManagerFactoryRegistryTestApi::AddService(
-    const UserId& user_id,
-    mojom::WindowManagerFactory* factory) {
-  std::unique_ptr<WindowManagerFactoryService> service_ptr(
-      new WindowManagerFactoryService(registry_, user_id));
-  WindowManagerFactoryService* service = service_ptr.get();
-  registry_->AddServiceImpl(std::move(service_ptr));
-  service->SetWindowManagerFactoryImpl(factory);
+void WindowManagerWindowTreeFactorySetTestApi::Add(const UserId& user_id) {
+  WindowManagerWindowTreeFactory* factory =
+      window_manager_window_tree_factory_set_->Add(user_id, nullptr);
+  factory->CreateWindowTree(nullptr, nullptr);
 }
 
 // TestPlatformDisplayFactory  -------------------------------------------------
@@ -442,16 +443,6 @@
 
 // ----------------------------------------------------------------------------
 
-TestWindowManagerFactory::TestWindowManagerFactory() {}
-
-TestWindowManagerFactory::~TestWindowManagerFactory() {}
-
-void TestWindowManagerFactory::CreateWindowManager(
-    mus::mojom::DisplayPtr display,
-    mus::mojom::WindowTreeClientRequest client) {}
-
-// ----------------------------------------------------------------------------
-
 ServerWindow* FirstRoot(WindowTree* tree) {
   return tree->roots().size() == 1u
              ? tree->GetWindow((*tree->roots().begin())->id())
@@ -473,7 +464,12 @@
 }
 
 ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id) {
-  ServerWindow* parent = FirstRoot(tree);
+  return NewWindowInTreeWithParent(tree, FirstRoot(tree), client_id);
+}
+
+ServerWindow* NewWindowInTreeWithParent(WindowTree* tree,
+                                        ServerWindow* parent,
+                                        ClientWindowId* client_id) {
   if (!parent)
     return nullptr;
   ClientWindowId parent_client_id;
diff --git a/components/mus/ws/test_utils.h b/components/mus/ws/test_utils.h
index d694307..c754dcef 100644
--- a/components/mus/ws/test_utils.h
+++ b/components/mus/ws/test_utils.h
@@ -19,8 +19,8 @@
 #include "components/mus/ws/test_change_tracker.h"
 #include "components/mus/ws/user_display_manager.h"
 #include "components/mus/ws/user_id.h"
-#include "components/mus/ws/window_manager_factory_registry.h"
 #include "components/mus/ws/window_manager_state.h"
+#include "components/mus/ws/window_manager_window_tree_factory_set.h"
 #include "components/mus/ws/window_server_delegate.h"
 #include "components/mus/ws/window_tree.h"
 #include "components/mus/ws/window_tree_binding.h"
@@ -31,18 +31,19 @@
 
 // Collection of utilities useful in creating mus tests.
 
-class WindowManagerFactoryRegistryTestApi {
+class WindowManagerWindowTreeFactorySetTestApi {
  public:
-  explicit WindowManagerFactoryRegistryTestApi(
-      WindowManagerFactoryRegistry* registry);
-  ~WindowManagerFactoryRegistryTestApi();
+  explicit WindowManagerWindowTreeFactorySetTestApi(
+      WindowManagerWindowTreeFactorySet*
+          window_manager_window_tree_factory_set);
+  ~WindowManagerWindowTreeFactorySetTestApi();
 
-  void AddService(const UserId& user_id, mojom::WindowManagerFactory* factory);
+  void Add(const UserId& user_id);
 
  private:
-  WindowManagerFactoryRegistry* registry_;
+  WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set_;
 
-  DISALLOW_COPY_AND_ASSIGN(WindowManagerFactoryRegistryTestApi);
+  DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactorySetTestApi);
 };
 
 // -----------------------------------------------------------------------------
@@ -232,6 +233,10 @@
 
  private:
   // WindowManager:
+  void OnConnect(uint16_t client_id) override {}
+  void WmNewDisplayAdded(mus::mojom::DisplayPtr display,
+                         mus::mojom::WindowDataPtr root,
+                         bool drawn) override {}
   void WmSetBounds(uint32_t change_id,
                    uint32_t window_id,
                    const gfx::Rect& bounds) override {}
@@ -472,21 +477,6 @@
 
 // -----------------------------------------------------------------------------
 
-class TestWindowManagerFactory : public mojom::WindowManagerFactory {
- public:
-  TestWindowManagerFactory();
-  ~TestWindowManagerFactory() override;
-
-  // mojom::WindowManagerFactory:
-  void CreateWindowManager(mus::mojom::DisplayPtr display,
-                           mus::mojom::WindowTreeClientRequest client) override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestWindowManagerFactory);
-};
-
-// -----------------------------------------------------------------------------
-
 // Returns the first and only root of |tree|. If |tree| has zero or more than
 // one root returns null.
 ServerWindow* FirstRoot(WindowTree* tree);
@@ -502,6 +492,9 @@
 // Creates a new visible window as a child of the single root of |tree|.
 // |client_id| set to the ClientWindowId of the new window.
 ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id);
+ServerWindow* NewWindowInTreeWithParent(WindowTree* tree,
+                                        ServerWindow* parent,
+                                        ClientWindowId* client_id);
 
 }  // namespace test
 }  // namespace ws
diff --git a/components/mus/ws/user_display_manager.cc b/components/mus/ws/user_display_manager.cc
index 567045e..aa5f656 100644
--- a/components/mus/ws/user_display_manager.cc
+++ b/components/mus/ws/user_display_manager.cc
@@ -52,10 +52,10 @@
 }
 
 void UserDisplayManager::OnWillDestroyDisplay(Display* display) {
-  if (!display->GetWindowManagerStateForUser(user_id_)
-           ->got_frame_decoration_values()) {
+  const WindowManagerState* wms =
+      display->GetWindowManagerStateForUser(user_id_);
+  if (wms && !wms->got_frame_decoration_values())
     return;
-  }
 
   display_manager_observers_.ForAllPtrs(
       [this, &display](mojom::DisplayManagerObserver* observer) {
@@ -169,12 +169,7 @@
     mojom::DisplayManagerObserver* observer) {
   mojo::Array<mojom::DisplayPtr> displays(1);
   displays[0] = wms->ToMojomDisplay();
-  display_manager_observers_.ForAllPtrs(
-      [&displays](mojom::DisplayManagerObserver* observer) {
-        observer->OnDisplaysChanged(displays.Clone());
-      });
-  if (test_observer_)
-    test_observer_->OnDisplaysChanged(displays.Clone());
+  observer->OnDisplaysChanged(displays.Clone());
 }
 
 void UserDisplayManager::AddObserver(
diff --git a/components/mus/ws/user_display_manager_unittest.cc b/components/mus/ws/user_display_manager_unittest.cc
index 24eb477..4bd1dea 100644
--- a/components/mus/ws/user_display_manager_unittest.cc
+++ b/components/mus/ws/user_display_manager_unittest.cc
@@ -109,7 +109,6 @@
   TestWindowServerDelegate window_server_delegate_;
   std::unique_ptr<WindowServer> window_server_;
   base::MessageLoop message_loop_;
-  TestWindowManagerFactory test_window_manager_factory_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(UserDisplayManagerTest);
@@ -121,9 +120,9 @@
   const UserId kUserId1 = "2";
   TestDisplayManagerObserver display_manager_observer1;
   DisplayManager* display_manager = window_server_->display_manager();
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kUserId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kUserId1);
   UserDisplayManager* user_display_manager1 =
       display_manager->GetUserDisplayManager(kUserId1);
   ASSERT_TRUE(user_display_manager1);
@@ -150,9 +149,9 @@
   const UserId kUserId1 = "2";
   TestDisplayManagerObserver display_manager_observer1;
   DisplayManager* display_manager = window_server_->display_manager();
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kUserId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kUserId1);
   UserDisplayManager* user_display_manager1 =
       display_manager->GetUserDisplayManager(kUserId1);
   ASSERT_TRUE(user_display_manager1);
@@ -175,9 +174,9 @@
   const UserId kUserId1 = "2";
   TestDisplayManagerObserver display_manager_observer1;
   DisplayManager* display_manager = window_server_->display_manager();
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kUserId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kUserId1);
   UserDisplayManager* user_display_manager1 =
       display_manager->GetUserDisplayManager(kUserId1);
   ASSERT_TRUE(user_display_manager1);
@@ -217,9 +216,9 @@
   const UserId kUserId1 = "2";
   TestDisplayManagerObserver display_manager_observer1;
   DisplayManager* display_manager = window_server_->display_manager();
-  WindowManagerFactoryRegistryTestApi(
-      window_server_->window_manager_factory_registry())
-      .AddService(kUserId1, &test_window_manager_factory_);
+  WindowManagerWindowTreeFactorySetTestApi(
+      window_server_->window_manager_window_tree_factory_set())
+      .Add(kUserId1);
   UserDisplayManager* user_display_manager1 =
       display_manager->GetUserDisplayManager(kUserId1);
   ASSERT_TRUE(user_display_manager1);
diff --git a/components/mus/ws/window_manager_client_unittest.cc b/components/mus/ws/window_manager_client_unittest.cc
index 1721a4d9..a8049c6b 100644
--- a/components/mus/ws/window_manager_client_unittest.cc
+++ b/components/mus/ws/window_manager_client_unittest.cc
@@ -60,6 +60,8 @@
   }
   void OnWmClientJankinessChanged(const std::set<Window*>& client_windows,
                                   bool janky) override {}
+  void OnWmNewDisplay(Window* window,
+                      const display::Display& display) override {}
   void OnAccelerator(uint32_t id, const ui::Event& event) override {}
 
  private:
diff --git a/components/mus/ws/window_manager_factory_registry.cc b/components/mus/ws/window_manager_factory_registry.cc
deleted file mode 100644
index 453c1c68..0000000
--- a/components/mus/ws/window_manager_factory_registry.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/ws/window_manager_factory_registry.h"
-
-#include "components/mus/ws/user_id_tracker_observer.h"
-#include "components/mus/ws/window_manager_factory_registry_observer.h"
-#include "components/mus/ws/window_manager_factory_service.h"
-#include "components/mus/ws/window_server.h"
-
-namespace mus {
-namespace ws {
-
-WindowManagerFactoryRegistry::WindowManagerFactoryRegistry(
-    WindowServer* window_server,
-    UserIdTracker* id_tracker)
-    : id_tracker_(id_tracker), window_server_(window_server) {
-  id_tracker_->AddObserver(this);
-}
-
-WindowManagerFactoryRegistry::~WindowManagerFactoryRegistry() {
-  id_tracker_->RemoveObserver(this);
-}
-
-void WindowManagerFactoryRegistry::Register(
-    const UserId& user_id,
-    mojo::InterfaceRequest<mojom::WindowManagerFactoryService> request) {
-  if (ContainsServiceForUser(user_id))
-    return;
-
-  std::unique_ptr<WindowManagerFactoryService> service(
-      new WindowManagerFactoryService(this, user_id, std::move(request)));
-  AddServiceImpl(std::move(service));
-}
-
-std::vector<WindowManagerFactoryService*>
-WindowManagerFactoryRegistry::GetServices() {
-  std::vector<WindowManagerFactoryService*> result;
-  for (auto& service_ptr : services_)
-    result.push_back(service_ptr.get());
-  return result;
-}
-
-void WindowManagerFactoryRegistry::AddObserver(
-    WindowManagerFactoryRegistryObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void WindowManagerFactoryRegistry::RemoveObserver(
-    WindowManagerFactoryRegistryObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
-void WindowManagerFactoryRegistry::AddServiceImpl(
-    std::unique_ptr<WindowManagerFactoryService> service) {
-  services_.push_back(std::move(service));
-}
-
-bool WindowManagerFactoryRegistry::ContainsServiceForUser(
-    const UserId& user_id) const {
-  for (auto& service_ptr : services_) {
-    if (service_ptr->user_id() == user_id) {
-      LOG(ERROR) << "WindowManagerFactoryService already registered for "
-                 << user_id;
-      return true;
-    }
-  }
-  return false;
-}
-
-void WindowManagerFactoryRegistry::OnWindowManagerFactoryConnectionLost(
-    WindowManagerFactoryService* service) {
-  for (auto it = services_.begin(); it != services_.end(); ++it) {
-    if (it->get() == service) {
-      services_.erase(it);
-      return;
-    }
-  }
-}
-
-void WindowManagerFactoryRegistry::OnWindowManagerFactorySet(
-    WindowManagerFactoryService* service) {
-  DCHECK(service->window_manager_factory());
-  const bool is_first_valid_factory = !got_valid_factory_;
-  got_valid_factory_ = true;
-  FOR_EACH_OBSERVER(WindowManagerFactoryRegistryObserver, observers_,
-                    OnWindowManagerFactorySet(service));
-
-  // Notify after other observers as WindowServer triggers other
-  // observers being added, which will have already processed the add.
-  if (is_first_valid_factory)
-    window_server_->OnFirstWindowManagerFactorySet();
-}
-
-void WindowManagerFactoryRegistry::OnActiveUserIdChanged(
-    const UserId& previously_active_id,
-    const UserId& active_id) {}
-
-void WindowManagerFactoryRegistry::OnUserIdAdded(const UserId& id) {}
-
-void WindowManagerFactoryRegistry::OnUserIdRemoved(const UserId& id) {
-  for (auto iter = services_.begin(); iter != services_.end(); ++iter) {
-    if ((*iter)->user_id() == id) {
-      services_.erase(iter);
-      return;
-    }
-  }
-}
-
-}  // namespace ws
-}  // namespace mus
diff --git a/components/mus/ws/window_manager_factory_registry.h b/components/mus/ws/window_manager_factory_registry.h
deleted file mode 100644
index ca60fa2..0000000
--- a/components/mus/ws/window_manager_factory_registry.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_REGISTRY_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_REGISTRY_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
-#include "components/mus/ws/user_id_tracker_observer.h"
-
-namespace mus {
-namespace ws {
-
-class UserIdTracker;
-class WindowManagerFactoryRegistryObserver;
-class WindowManagerFactoryService;
-class WindowServer;
-
-namespace test {
-class WindowManagerFactoryRegistryTestApi;
-}
-
-// WindowManagerFactoryRegistry tracks the set of registered
-// WindowManagerFactoryServices.
-class WindowManagerFactoryRegistry : public UserIdTrackerObserver {
- public:
-  WindowManagerFactoryRegistry(WindowServer* window_server,
-                               UserIdTracker* tracker);
-  ~WindowManagerFactoryRegistry() override;
-
-  void Register(
-      const UserId& user_id,
-      mojo::InterfaceRequest<mojom::WindowManagerFactoryService> request);
-
-  std::vector<WindowManagerFactoryService*> GetServices();
-
-  void AddObserver(WindowManagerFactoryRegistryObserver* observer);
-  void RemoveObserver(WindowManagerFactoryRegistryObserver* observer);
-
- private:
-  friend class WindowManagerFactoryService;
-  friend class test::WindowManagerFactoryRegistryTestApi;
-
-  void AddServiceImpl(std::unique_ptr<WindowManagerFactoryService> service);
-
-  bool ContainsServiceForUser(const UserId& user_id) const;
-  void OnWindowManagerFactoryConnectionLost(
-      WindowManagerFactoryService* service);
-  void OnWindowManagerFactorySet(WindowManagerFactoryService* service);
-
-  // UserIdTrackerObserver:
-  void OnActiveUserIdChanged(const UserId& previously_active_id,
-                             const UserId& active_id) override;
-  void OnUserIdAdded(const UserId& id) override;
-  void OnUserIdRemoved(const UserId& id) override;
-
-  // Set to true the first time a valid factory has been found.
-  bool got_valid_factory_ = false;
-  UserIdTracker* id_tracker_;
-  WindowServer* window_server_;
-
-  std::vector<std::unique_ptr<WindowManagerFactoryService>> services_;
-
-  base::ObserverList<WindowManagerFactoryRegistryObserver> observers_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowManagerFactoryRegistry);
-};
-
-}  // namespace ws
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_REGISTRY_H_
diff --git a/components/mus/ws/window_manager_factory_registry_observer.h b/components/mus/ws/window_manager_factory_registry_observer.h
deleted file mode 100644
index ebbddf0..0000000
--- a/components/mus/ws/window_manager_factory_registry_observer.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_REGISTRY_OBSERVER_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_REGISTRY_OBSERVER_H_
-
-namespace mus {
-namespace ws {
-
-class WindowManagerFactoryService;
-
-class WindowManagerFactoryRegistryObserver {
- public:
-  // Called when the mojom::WindowManagerFactory associated with |service| has
-  // been obtained.
-  virtual void OnWindowManagerFactorySet(
-      WindowManagerFactoryService* service) = 0;
-
- protected:
-  virtual ~WindowManagerFactoryRegistryObserver() {}
-};
-
-}  // namespace ws
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_REGISTRY_OBSERVER_H_
diff --git a/components/mus/ws/window_manager_factory_service.cc b/components/mus/ws/window_manager_factory_service.cc
deleted file mode 100644
index 9aebb5a..0000000
--- a/components/mus/ws/window_manager_factory_service.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/mus/ws/window_manager_factory_service.h"
-
-#include "base/bind.h"
-#include "components/mus/ws/window_manager_factory_registry.h"
-#include "components/mus/ws/window_tree.h"
-
-namespace mus {
-namespace ws {
-
-WindowManagerFactoryService::WindowManagerFactoryService(
-    WindowManagerFactoryRegistry* registry,
-    const UserId& user_id,
-    mojo::InterfaceRequest<mojom::WindowManagerFactoryService> request)
-    : registry_(registry),
-      user_id_(user_id),
-      binding_(this, std::move(request)),
-      window_manager_factory_(nullptr) {}
-
-WindowManagerFactoryService::~WindowManagerFactoryService() {}
-
-void WindowManagerFactoryService::SetWindowManagerFactory(
-    mojom::WindowManagerFactoryPtr factory) {
-  window_manager_factory_ptr_ = std::move(factory);
-  window_manager_factory_ptr_.set_connection_error_handler(base::Bind(
-      &WindowManagerFactoryService::OnConnectionLost, base::Unretained(this)));
-  SetWindowManagerFactoryImpl(window_manager_factory_ptr_.get());
-}
-
-WindowManagerFactoryService::WindowManagerFactoryService(
-    WindowManagerFactoryRegistry* registry,
-    const UserId& user_id)
-    : registry_(registry),
-      user_id_(user_id),
-      binding_(this),
-      window_manager_factory_(nullptr) {}
-
-void WindowManagerFactoryService::SetWindowManagerFactoryImpl(
-    mojom::WindowManagerFactory* factory) {
-  DCHECK(!window_manager_factory_);
-  window_manager_factory_ = factory;
-  registry_->OnWindowManagerFactorySet(this);
-}
-
-void WindowManagerFactoryService::OnConnectionLost() {
-  registry_->OnWindowManagerFactoryConnectionLost(this);
-}
-
-}  // namespace ws
-}  // namespace mus
diff --git a/components/mus/ws/window_manager_factory_service.h b/components/mus/ws/window_manager_factory_service.h
deleted file mode 100644
index 6e1b6cd..0000000
--- a/components/mus/ws/window_manager_factory_service.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_SERVICE_H_
-#define COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_SERVICE_H_
-
-#include <stdint.h>
-
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
-#include "components/mus/ws/user_id.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace mus {
-namespace ws {
-
-class ServerWindow;
-class WindowManagerFactoryRegistry;
-
-namespace test {
-class WindowManagerFactoryRegistryTestApi;
-}
-
-class WindowManagerFactoryService : public mojom::WindowManagerFactoryService {
- public:
-  WindowManagerFactoryService(
-      WindowManagerFactoryRegistry* registry,
-      const UserId& user_id,
-      mojo::InterfaceRequest<mojom::WindowManagerFactoryService> request);
-  ~WindowManagerFactoryService() override;
-
-  const UserId& user_id() const { return user_id_; }
-
-  mojom::WindowManagerFactory* window_manager_factory() {
-    return window_manager_factory_;
-  }
-
-  // mojom::WindowManagerFactoryService:
-  void SetWindowManagerFactory(mojom::WindowManagerFactoryPtr factory) override;
-
- private:
-  friend class test::WindowManagerFactoryRegistryTestApi;
-
-  // Used by tests.
-  WindowManagerFactoryService(WindowManagerFactoryRegistry* registry,
-                              const UserId& user_id);
-
-  void SetWindowManagerFactoryImpl(mojom::WindowManagerFactory* factory);
-  void OnConnectionLost();
-
-  WindowManagerFactoryRegistry* registry_;
-  const UserId user_id_;
-  mojo::Binding<mojom::WindowManagerFactoryService> binding_;
-  mojom::WindowManagerFactoryPtr window_manager_factory_ptr_;
-  // Typically the same as |window_manager_factory_ptr_|, but differs for
-  // tests that don't create bindings.
-  mojom::WindowManagerFactory* window_manager_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(WindowManagerFactoryService);
-};
-
-}  // namespace ws
-}  // namespace mus
-
-#endif  // COMPONENTS_MUS_WS_WINDOW_MANAGER_FACTORY_SERVICE_H_
diff --git a/components/mus/ws/window_manager_window_tree_factory.cc b/components/mus/ws/window_manager_window_tree_factory.cc
new file mode 100644
index 0000000..eaf8e93
--- /dev/null
+++ b/components/mus/ws/window_manager_window_tree_factory.cc
@@ -0,0 +1,89 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/mus/ws/window_manager_window_tree_factory.h"
+
+#include "base/bind.h"
+#include "components/mus/ws/window_manager_window_tree_factory_set.h"
+#include "components/mus/ws/window_server.h"
+#include "components/mus/ws/window_tree.h"
+
+namespace mus {
+namespace ws {
+
+struct WindowManagerWindowTreeFactory::PendingRequest {
+  mojom::WindowTreeRequest window_tree_request;
+  mojom::WindowTreeClientPtr window_tree_client;
+};
+
+WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
+    WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
+    const UserId& user_id,
+    mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request)
+    : window_manager_window_tree_factory_set_(
+          window_manager_window_tree_factory_set),
+      user_id_(user_id),
+      binding_(this),
+      window_tree_(nullptr) {
+  if (request.is_pending())
+    binding_.Bind(std::move(request));
+}
+
+WindowManagerWindowTreeFactory::~WindowManagerWindowTreeFactory() {}
+
+void WindowManagerWindowTreeFactory::BindPendingRequest() {
+  if (!pending_request_)
+    return;
+
+  SetWindowTree(GetWindowServer()->CreateTreeForWindowManager(
+      user_id_, std::move(pending_request_->window_tree_request),
+      std::move(pending_request_->window_tree_client)));
+  pending_request_.reset();
+}
+
+void WindowManagerWindowTreeFactory::CreateWindowTree(
+    mojom::WindowTreeRequest window_tree_request,
+    mojom::WindowTreeClientPtr window_tree_client) {
+  // CreateWindowTree() can only be called once, so there is no reason to keep
+  // the binding around.
+  if (binding_.is_bound())
+    binding_.Close();
+
+  if (GetWindowServer()->created_one_display()) {
+    SetWindowTree(GetWindowServer()->CreateTreeForWindowManager(
+        user_id_, std::move(window_tree_request),
+        std::move(window_tree_client)));
+  } else {
+    pending_request_.reset(new PendingRequest);
+    pending_request_->window_tree_request = std::move(window_tree_request);
+    pending_request_->window_tree_client = std::move(window_tree_client);
+    window_manager_window_tree_factory_set_
+        ->OnWindowManagerWindowTreeFactoryReady(this);
+  }
+}
+
+WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
+    WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
+    const UserId& user_id)
+    : window_manager_window_tree_factory_set_(
+          window_manager_window_tree_factory_set),
+      user_id_(user_id),
+      binding_(this),
+      window_tree_(nullptr) {}
+
+WindowServer* WindowManagerWindowTreeFactory::GetWindowServer() {
+  return window_manager_window_tree_factory_set_->window_server();
+}
+
+void WindowManagerWindowTreeFactory::SetWindowTree(WindowTree* window_tree) {
+  DCHECK(!window_tree_);
+  window_tree_ = window_tree;
+
+  if (!pending_request_)
+    window_manager_window_tree_factory_set_
+        ->OnWindowManagerWindowTreeFactoryReady(this);
+}
+
+}  // namespace ws
+}  // namespace mus
diff --git a/components/mus/ws/window_manager_window_tree_factory.h b/components/mus/ws/window_manager_window_tree_factory.h
new file mode 100644
index 0000000..7aed6c9d
--- /dev/null
+++ b/components/mus/ws/window_manager_window_tree_factory.h
@@ -0,0 +1,75 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_H_
+#define COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
+#include "components/mus/ws/user_id.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace mus {
+namespace ws {
+
+class ServerWindow;
+class WindowManagerWindowTreeFactorySet;
+class WindowServer;
+class WindowTree;
+
+namespace test {
+class WindowManagerWindowTreeFactorySetTestApi;
+}
+
+// Implementation of mojom::WindowManagerWindowTreeFactory.
+class WindowManagerWindowTreeFactory
+    : public mojom::WindowManagerWindowTreeFactory {
+ public:
+  WindowManagerWindowTreeFactory(
+      WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
+      const UserId& user_id,
+      mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
+  ~WindowManagerWindowTreeFactory() override;
+
+  const UserId& user_id() const { return user_id_; }
+
+  WindowTree* window_tree() { return window_tree_; }
+
+  void BindPendingRequest();
+
+  // mojom::WindowManagerWindowTreeFactory:
+  void CreateWindowTree(mojom::WindowTreeRequest window_tree_request,
+                        mojom::WindowTreeClientPtr window_tree_client) override;
+
+ private:
+  friend class test::WindowManagerWindowTreeFactorySetTestApi;
+  struct PendingRequest;
+
+  // Used by tests.
+  WindowManagerWindowTreeFactory(WindowManagerWindowTreeFactorySet* registry,
+                                 const UserId& user_id);
+
+  WindowServer* GetWindowServer();
+
+  void SetWindowTree(WindowTree* window_tree);
+
+  WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set_;
+  const UserId user_id_;
+  mojo::Binding<mojom::WindowManagerWindowTreeFactory> binding_;
+
+  // Owned by WindowServer.
+  WindowTree* window_tree_;
+
+  std::unique_ptr<PendingRequest> pending_request_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactory);
+};
+
+}  // namespace ws
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_H_
diff --git a/components/mus/ws/window_manager_window_tree_factory_set.cc b/components/mus/ws/window_manager_window_tree_factory_set.cc
new file mode 100644
index 0000000..d9bd63d
--- /dev/null
+++ b/components/mus/ws/window_manager_window_tree_factory_set.cc
@@ -0,0 +1,107 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/mus/ws/window_manager_window_tree_factory_set.h"
+
+#include "components/mus/ws/user_id_tracker_observer.h"
+#include "components/mus/ws/window_manager_window_tree_factory.h"
+#include "components/mus/ws/window_manager_window_tree_factory_set_observer.h"
+#include "components/mus/ws/window_server.h"
+
+namespace mus {
+namespace ws {
+
+WindowManagerWindowTreeFactorySet::WindowManagerWindowTreeFactorySet(
+    WindowServer* window_server,
+    UserIdTracker* id_tracker)
+    : id_tracker_(id_tracker), window_server_(window_server) {
+  id_tracker_->AddObserver(this);
+}
+
+WindowManagerWindowTreeFactorySet::~WindowManagerWindowTreeFactorySet() {
+  id_tracker_->RemoveObserver(this);
+}
+
+WindowManagerWindowTreeFactory* WindowManagerWindowTreeFactorySet::Add(
+    const UserId& user_id,
+    mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request) {
+  if (ContainsFactoryForUser(user_id)) {
+    DVLOG(1) << "can only have one factory per user";
+    return nullptr;
+  }
+
+  std::unique_ptr<WindowManagerWindowTreeFactory> factory_ptr(
+      new WindowManagerWindowTreeFactory(this, user_id, std::move(request)));
+  WindowManagerWindowTreeFactory* factory = factory_ptr.get();
+  factories_.push_back(std::move(factory_ptr));
+  return factory;
+}
+
+void WindowManagerWindowTreeFactorySet::DeleteFactoryAssociatedWithTree(
+    WindowTree* window_tree) {
+  for (auto it = factories_.begin(); it != factories_.end(); ++it) {
+    if ((*it)->window_tree() == window_tree) {
+      factories_.erase(it);
+      return;
+    }
+  }
+}
+
+std::vector<WindowManagerWindowTreeFactory*>
+WindowManagerWindowTreeFactorySet::GetFactories() {
+  std::vector<WindowManagerWindowTreeFactory*> result;
+  for (auto& factory : factories_)
+    result.push_back(factory.get());
+  return result;
+}
+
+void WindowManagerWindowTreeFactorySet::AddObserver(
+    WindowManagerWindowTreeFactorySetObserver* observer) {
+  observers_.AddObserver(observer);
+}
+
+void WindowManagerWindowTreeFactorySet::RemoveObserver(
+    WindowManagerWindowTreeFactorySetObserver* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool WindowManagerWindowTreeFactorySet::ContainsFactoryForUser(
+    const UserId& user_id) const {
+  for (auto& factory : factories_) {
+    if (factory->user_id() == user_id)
+      return true;
+  }
+  return false;
+}
+
+void WindowManagerWindowTreeFactorySet::OnWindowManagerWindowTreeFactoryReady(
+    WindowManagerWindowTreeFactory* factory) {
+  const bool is_first_valid_factory = !got_valid_factory_;
+  got_valid_factory_ = true;
+  FOR_EACH_OBSERVER(WindowManagerWindowTreeFactorySetObserver, observers_,
+                    OnWindowManagerWindowTreeFactoryReady(factory));
+
+  // Notify after other observers as WindowServer triggers other
+  // observers being added, which will have already processed the add.
+  if (is_first_valid_factory)
+    window_server_->OnFirstWindowManagerWindowTreeFactoryReady();
+}
+
+void WindowManagerWindowTreeFactorySet::OnActiveUserIdChanged(
+    const UserId& previously_active_id,
+    const UserId& active_id) {}
+
+void WindowManagerWindowTreeFactorySet::OnUserIdAdded(const UserId& id) {}
+
+void WindowManagerWindowTreeFactorySet::OnUserIdRemoved(const UserId& id) {
+  for (auto iter = factories_.begin(); iter != factories_.end(); ++iter) {
+    if ((*iter)->user_id() == id) {
+      factories_.erase(iter);
+      return;
+    }
+  }
+}
+
+}  // namespace ws
+}  // namespace mus
diff --git a/components/mus/ws/window_manager_window_tree_factory_set.h b/components/mus/ws/window_manager_window_tree_factory_set.h
new file mode 100644
index 0000000..4d27a88
--- /dev/null
+++ b/components/mus/ws/window_manager_window_tree_factory_set.h
@@ -0,0 +1,94 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
+#define COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
+#include "components/mus/ws/user_id_tracker_observer.h"
+
+namespace mus {
+namespace ws {
+
+class UserIdTracker;
+class WindowManagerWindowTreeFactory;
+class WindowManagerWindowTreeFactorySetObserver;
+class WindowServer;
+class WindowTree;
+
+namespace test {
+class WindowManagerWindowTreeFactorySetTestApi;
+}
+
+// WindowManagerWindowTreeFactorySet tracks the set of registered
+// WindowManagerWindowTreeHostFactories.
+class WindowManagerWindowTreeFactorySet : public UserIdTrackerObserver {
+ public:
+  WindowManagerWindowTreeFactorySet(WindowServer* window_server,
+                                    UserIdTracker* tracker);
+  ~WindowManagerWindowTreeFactorySet() override;
+
+  WindowServer* window_server() { return window_server_; }
+
+  // Creates a new WindowManagerWindowTreeFactory for the specified user,
+  // unless one has been set, in which case the call is ignored. The newly
+  // created WindowManagerWindowTreeFactory does not immediately have a
+  // WindowTree associated with it.
+  WindowManagerWindowTreeFactory* Add(
+      const UserId& user_id,
+      mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
+
+  // Deletes the WindowManagerWindowTreeFactory associated with |tree|. Does
+  // nothing if there is no WindowManagerWindowTreeFactory associated with
+  // |tree|.
+  void DeleteFactoryAssociatedWithTree(WindowTree* tree);
+
+  // Returns all the factories, even those that may not have a WindowTree
+  // associated with them.
+  std::vector<WindowManagerWindowTreeFactory*> GetFactories();
+
+  void AddObserver(WindowManagerWindowTreeFactorySetObserver* observer);
+  void RemoveObserver(WindowManagerWindowTreeFactorySetObserver* observer);
+
+ private:
+  friend class WindowManagerWindowTreeFactory;
+  friend class test::WindowManagerWindowTreeFactorySetTestApi;
+
+  // Returns true if a factory has been created for the specified user.
+  bool ContainsFactoryForUser(const UserId& user_id) const;
+
+  // Called by WindowManagerWindowTreeFactory when CreateWindowTree() has
+  // been called.
+  void OnWindowManagerWindowTreeFactoryReady(
+      WindowManagerWindowTreeFactory* factory);
+
+  // UserIdTrackerObserver:
+  void OnActiveUserIdChanged(const UserId& previously_active_id,
+                             const UserId& active_id) override;
+  void OnUserIdAdded(const UserId& id) override;
+  void OnUserIdRemoved(const UserId& id) override;
+
+  // Set to true the first time a valid factory has been found.
+  bool got_valid_factory_ = false;
+  UserIdTracker* id_tracker_;
+  WindowServer* window_server_;
+
+  std::vector<std::unique_ptr<WindowManagerWindowTreeFactory>> factories_;
+
+  base::ObserverList<WindowManagerWindowTreeFactorySetObserver> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactorySet);
+};
+
+}  // namespace ws
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
diff --git a/components/mus/ws/window_manager_window_tree_factory_set_observer.h b/components/mus/ws/window_manager_window_tree_factory_set_observer.h
new file mode 100644
index 0000000..dd5f876d
--- /dev/null
+++ b/components/mus/ws/window_manager_window_tree_factory_set_observer.h
@@ -0,0 +1,26 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
+#define COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
+
+namespace mus {
+namespace ws {
+
+class WindowManagerWindowTreeFactory;
+
+class WindowManagerWindowTreeFactorySetObserver {
+ public:
+  // Called when the WindowTree associated with |factory| has been set
+  virtual void OnWindowManagerWindowTreeFactoryReady(
+      WindowManagerWindowTreeFactory* factory) = 0;
+
+ protected:
+  virtual ~WindowManagerWindowTreeFactorySetObserver() {}
+};
+
+}  // namespace ws
+}  // namespace mus
+
+#endif  // COMPONENTS_MUS_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
diff --git a/components/mus/ws/window_server.cc b/components/mus/ws/window_server.cc
index 4f716c5..f3af2b9 100644
--- a/components/mus/ws/window_server.cc
+++ b/components/mus/ws/window_server.cc
@@ -18,8 +18,8 @@
 #include "components/mus/ws/server_window.h"
 #include "components/mus/ws/window_coordinate_conversions.h"
 #include "components/mus/ws/window_manager_access_policy.h"
-#include "components/mus/ws/window_manager_factory_service.h"
 #include "components/mus/ws/window_manager_state.h"
+#include "components/mus/ws/window_manager_window_tree_factory.h"
 #include "components/mus/ws/window_server_delegate.h"
 #include "components/mus/ws/window_tree.h"
 #include "components/mus/ws/window_tree_binding.h"
@@ -39,7 +39,7 @@
       current_operation_(nullptr),
       in_destructor_(false),
       next_wm_change_id_(0),
-      window_manager_factory_registry_(this, &user_id_tracker_) {}
+      window_manager_window_tree_factory_set_(this, &user_id_tracker_) {}
 
 WindowServer::~WindowServer() {
   in_destructor_ = true;
@@ -94,42 +94,34 @@
   return tree;
 }
 
-WindowTree* WindowServer::AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
-                                  std::unique_ptr<WindowTreeBinding> binding,
-                                  mojom::WindowTreePtr tree_ptr) {
+void WindowServer::AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
+                           std::unique_ptr<WindowTreeBinding> binding,
+                           mojom::WindowTreePtr tree_ptr) {
   CHECK_EQ(0u, tree_map_.count(tree_impl_ptr->id()));
   WindowTree* tree = tree_impl_ptr.get();
   tree_map_[tree->id()] = std::move(tree_impl_ptr);
   tree->Init(std::move(binding), std::move(tree_ptr));
-  return tree;
 }
 
 WindowTree* WindowServer::CreateTreeForWindowManager(
-    Display* display,
-    mojom::WindowManagerFactory* factory,
-    ServerWindow* root,
-    const UserId& user_id) {
-  mojom::DisplayPtr display_ptr = display->ToMojomDisplay();
-  mojom::WindowTreeClientPtr tree_client;
-  factory->CreateWindowManager(std::move(display_ptr), GetProxy(&tree_client));
-  std::unique_ptr<WindowTree> tree_ptr(new WindowTree(
-      this, user_id, root, base::WrapUnique(new WindowManagerAccessPolicy)));
-  WindowTree* tree = tree_ptr.get();
-  mojom::WindowTreePtr window_tree_ptr;
-  mojom::WindowTreeRequest tree_request;
-  std::unique_ptr<WindowTreeBinding> binding =
+    const UserId& user_id,
+    mojom::WindowTreeRequest window_tree_request,
+    mojom::WindowTreeClientPtr window_tree_client) {
+  std::unique_ptr<WindowTree> window_tree(new WindowTree(
+      this, user_id, nullptr, base::WrapUnique(new WindowManagerAccessPolicy)));
+  std::unique_ptr<WindowTreeBinding> window_tree_binding =
       delegate_->CreateWindowTreeBinding(
-          WindowServerDelegate::BindingType::WINDOW_MANAGER, this, tree,
-          &tree_request, &tree_client);
-  if (!binding) {
-    DefaultWindowTreeBinding* default_binding =
-        new DefaultWindowTreeBinding(tree_ptr.get(), std::move(tree_client));
-    binding.reset(default_binding);
-    window_tree_ptr = default_binding->CreateInterfacePtrAndBind();
+          WindowServerDelegate::BindingType::WINDOW_MANAGER, this,
+          window_tree.get(), &window_tree_request, &window_tree_client);
+  if (!window_tree_binding) {
+    window_tree_binding.reset(new DefaultWindowTreeBinding(
+        window_tree.get(), this, std::move(window_tree_request),
+        std::move(window_tree_client)));
   }
-  AddTree(std::move(tree_ptr), std::move(binding), std::move(window_tree_ptr));
-  tree->ConfigureWindowManager();
-  return tree;
+  WindowTree* window_tree_ptr = window_tree.get();
+  AddTree(std::move(window_tree), std::move(window_tree_binding), nullptr);
+  window_tree_ptr->ConfigureWindowManager();
+  return window_tree_ptr;
 }
 
 void WindowServer::DestroyTree(WindowTree* tree) {
@@ -159,6 +151,8 @@
     }
   }
 
+  window_manager_window_tree_factory_set_.DeleteFactoryAssociatedWithTree(tree);
+
   // Remove any requests from the client that resulted in a call to the window
   // manager and we haven't gotten a response back yet.
   std::set<uint32_t> to_remove;
@@ -224,7 +218,7 @@
   return nullptr;
 }
 
-void WindowServer::OnFirstWindowManagerFactorySet() {
+void WindowServer::OnFirstWindowManagerWindowTreeFactoryReady() {
   if (display_manager_->has_active_or_pending_displays())
     return;
 
@@ -653,6 +647,15 @@
 }
 
 void WindowServer::OnFirstDisplayReady() {
+  // TODO(sky): remove this, temporary until window manager state made
+  // global.
+  if (!created_one_display_) {
+    created_one_display_ = true;
+    std::vector<WindowManagerWindowTreeFactory*> factories =
+        window_manager_window_tree_factory_set_.GetFactories();
+    for (WindowManagerWindowTreeFactory* factory : factories)
+      factory->BindPendingRequest();
+  }
   delegate_->OnFirstDisplayReady();
 }
 
diff --git a/components/mus/ws/window_server.h b/components/mus/ws/window_server.h
index 0ec0a161..46b7c0c7 100644
--- a/components/mus/ws/window_server.h
+++ b/components/mus/ws/window_server.h
@@ -13,7 +13,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "components/mus/public/interfaces/window_manager_factory.mojom.h"
+#include "components/mus/public/interfaces/window_manager_window_tree_factory.mojom.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "components/mus/public/interfaces/window_tree_host.mojom.h"
 #include "components/mus/surfaces/surfaces_state.h"
@@ -24,7 +24,7 @@
 #include "components/mus/ws/server_window_delegate.h"
 #include "components/mus/ws/server_window_observer.h"
 #include "components/mus/ws/user_id_tracker.h"
-#include "components/mus/ws/window_manager_factory_registry.h"
+#include "components/mus/ws/window_manager_window_tree_factory_set.h"
 #include "mojo/public/cpp/bindings/array.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
@@ -59,6 +59,8 @@
     return display_manager_.get();
   }
 
+  bool created_one_display() const { return created_one_display_; }
+
   // Creates a new ServerWindow. The return value is owned by the caller, but
   // must be destroyed before WindowServer.
   ServerWindow* CreateServerWindow(
@@ -77,13 +79,13 @@
 
   // Adds |tree_impl_ptr| to the set of known trees. Use DestroyTree() to
   // destroy the tree.
-  WindowTree* AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
-                      std::unique_ptr<WindowTreeBinding> binding,
-                      mojom::WindowTreePtr tree_ptr);
-  WindowTree* CreateTreeForWindowManager(Display* display,
-                                         mojom::WindowManagerFactory* factory,
-                                         ServerWindow* root,
-                                         const UserId& user_id);
+  void AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
+               std::unique_ptr<WindowTreeBinding> binding,
+               mojom::WindowTreePtr tree_ptr);
+  WindowTree* CreateTreeForWindowManager(
+      const UserId& user_id,
+      mojom::WindowTreeRequest window_tree_request,
+      mojom::WindowTreeClientPtr window_tree_client);
   // Invoked when a WindowTree's connection encounters an error.
   void DestroyTree(WindowTree* tree);
 
@@ -125,10 +127,10 @@
   }
   const WindowTree* GetTreeWithRoot(const ServerWindow* window) const;
 
-  void OnFirstWindowManagerFactorySet();
+  void OnFirstWindowManagerWindowTreeFactoryReady();
 
-  WindowManagerFactoryRegistry* window_manager_factory_registry() {
-    return &window_manager_factory_registry_;
+  WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set() {
+    return &window_manager_window_tree_factory_set_;
   }
 
   // Sets focus to |window|. Returns true if |window| already has focus, or
@@ -310,7 +312,11 @@
 
   base::Callback<void(ServerWindow*)> window_paint_callback_;
 
-  WindowManagerFactoryRegistry window_manager_factory_registry_;
+  WindowManagerWindowTreeFactorySet window_manager_window_tree_factory_set_;
+
+  // TODO(sky): remove this, temporary until window manager state made global
+  // and not per display.
+  bool created_one_display_ = false;
 
   DISALLOW_COPY_AND_ASSIGN(WindowServer);
 };
diff --git a/components/mus/ws/window_tree.cc b/components/mus/ws/window_tree.cc
index 3593557..fa53c986 100644
--- a/components/mus/ws/window_tree.cc
+++ b/components/mus/ws/window_tree.cc
@@ -118,6 +118,7 @@
 void WindowTree::ConfigureWindowManager() {
   DCHECK(!window_manager_internal_);
   window_manager_internal_ = binding_->GetWindowManager();
+  window_manager_internal_->OnConnect(id_);
 }
 
 const ServerWindow* WindowTree::GetWindow(const WindowId& id) const {
@@ -164,6 +165,22 @@
              : nullptr;
 }
 
+void WindowTree::AddRootForWindowManager(const ServerWindow* root) {
+  DCHECK(window_manager_internal_);
+  const ClientWindowId client_window_id(WindowIdToTransportId(root->id()));
+  DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id));
+  client_id_to_window_id_map_[client_window_id] = root->id();
+  window_id_to_client_id_map_[root->id()] = client_window_id;
+  roots_.insert(root);
+
+  Display* display = GetDisplay(root);
+  DCHECK(display);
+
+  window_manager_internal_->WmNewDisplayAdded(display->ToMojomDisplay(),
+                                              WindowToWindowData(root),
+                                              root->parent()->IsDrawn());
+}
+
 void WindowTree::OnWindowDestroyingTreeImpl(WindowTree* tree) {
   if (event_source_wms_ && event_source_wms_->tree() == tree)
     event_source_wms_ = nullptr;
@@ -383,12 +400,16 @@
 }
 
 void WindowTree::AddActivationParent(const ClientWindowId& window_id) {
-  Display* host = GetDisplayForWindowManager();
-  if (!host)
-    return;
   ServerWindow* window = GetWindowByClientId(window_id);
-  if (window)
-    host->AddActivationParent(window);
+  if (window) {
+    Display* display = GetDisplay(window);
+    if (display)
+      display->AddActivationParent(window);
+    else
+      DVLOG(1) << "AddActivationParent window not associated with display";
+  } else {
+    DVLOG(1) << "AddActivationParent supplied invalid window id";
+  }
 }
 
 void WindowTree::OnChangeCompleted(uint32_t change_id, bool success) {
@@ -662,17 +683,15 @@
   return window_server_->display_manager();
 }
 
-Display* WindowTree::GetDisplayForWindowManager() {
-  return GetWindowManagerStateForWindowManager()->display();
-}
-
 WindowManagerState* WindowTree::GetWindowManagerStateForWindowManager() {
-  // The WindowTree for the wm has one and only one root.
-  CHECK_EQ(1u, roots_.size());
-
   // Indicates the client is the wm.
   DCHECK(window_manager_internal_);
 
+  if (roots_.size() > 1) {
+    // TODO(sky): fix the > 1 case, http://crbug.com/611563.
+    NOTIMPLEMENTED();
+  }
+
   WindowManagerState* wms = display_manager()
                                 ->GetWindowManagerAndDisplay(*roots_.begin())
                                 .window_manager_state;
@@ -1405,20 +1424,22 @@
 }
 
 void WindowTree::RemoveActivationParent(Id transport_window_id) {
-  Display* host = GetDisplayForWindowManager();
-  if (!host)
-    return;
   ServerWindow* window =
       GetWindowByClientId(ClientWindowId(transport_window_id));
-  if (window)
-    host->RemoveActivationParent(window);
+  if (window) {
+    Display* display = GetDisplay(window);
+    if (display)
+      display->RemoveActivationParent(window);
+    else
+      DVLOG(1) << "RemoveActivationParent window not associated with display";
+  } else {
+    DVLOG(1) << "RemoveActivationParent supplied invalid window id";
+  }
 }
 
 void WindowTree::ActivateNextWindow() {
-  Display* display = GetDisplayForWindowManager();
-  if (!display)
-    return;
-  display->ActivateNextWindow();
+  // TODO(sky): this needs to track active window. http://crbug.com/611563.
+  GetWindowManagerStateForWindowManager()->display()->ActivateNextWindow();
 }
 
 void WindowTree::SetUnderlaySurfaceOffsetAndExtendedHitArea(
@@ -1435,17 +1456,10 @@
 }
 
 void WindowTree::WmResponse(uint32_t change_id, bool response) {
-  // TODO(sky): think about what else case means.
-  if (GetDisplayForWindowManager())
-    window_server_->WindowManagerChangeCompleted(change_id, response);
+  window_server_->WindowManagerChangeCompleted(change_id, response);
 }
 
 void WindowTree::WmRequestClose(Id transport_window_id) {
-  // Only the WindowManager should be using this.
-  Display* host = GetDisplayForWindowManager();
-  if (!host)
-    return;
-
   ServerWindow* window =
       GetWindowByClientId(ClientWindowId(transport_window_id));
   WindowTree* tree = window_server_->GetTreeWithRoot(window);
@@ -1474,16 +1488,14 @@
 
 void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id,
                                            Id transport_window_id) {
-  if (GetDisplayForWindowManager()) {
-    ServerWindow* window =
-        GetWindowByClientId(ClientWindowId(transport_window_id));
-    if (window && window->id().client_id != id_) {
-      window_server_->WindowManagerSentBogusMessage();
-      window = nullptr;
-    }
-    window_server_->WindowManagerCreatedTopLevelWindow(this, change_id, window);
+  ServerWindow* window =
+      GetWindowByClientId(ClientWindowId(transport_window_id));
+  if (window && window->id().client_id != id_) {
+    DVLOG(1) << "OnWmCreatedTopLevelWindow supplied invalid window id";
+    window_server_->WindowManagerSentBogusMessage();
+    window = nullptr;
   }
-  // TODO(sky): think about what else case means.
+  window_server_->WindowManagerCreatedTopLevelWindow(this, change_id, window);
 }
 
 bool WindowTree::HasRootForAccessPolicy(const ServerWindow* window) const {
diff --git a/components/mus/ws/window_tree.h b/components/mus/ws/window_tree.h
index 2085ca77..4a03beb 100644
--- a/components/mus/ws/window_tree.h
+++ b/components/mus/ws/window_tree.h
@@ -129,6 +129,9 @@
         const_cast<const WindowTree*>(this)->GetWindowManagerState(window));
   }
 
+  // Adds a new root to this tree. This is only valid for window managers.
+  void AddRootForWindowManager(const ServerWindow* root);
+
   // Invoked when a tree is about to be destroyed.
   void OnWindowDestroyingTreeImpl(WindowTree* tree);
 
@@ -246,7 +249,6 @@
   const DisplayManager* display_manager() const;
 
   // Used when this tree is the window manager.
-  Display* GetDisplayForWindowManager();
   WindowManagerState* GetWindowManagerStateForWindowManager();
 
   bool ShouldRouteToWindowManager(const ServerWindow* window) const;
diff --git a/components/mus/ws/window_tree_binding.h b/components/mus/ws/window_tree_binding.h
index 729a8b1..a9472b3 100644
--- a/components/mus/ws/window_tree_binding.h
+++ b/components/mus/ws/window_tree_binding.h
@@ -17,9 +17,10 @@
 class WindowServer;
 class WindowTree;
 
-// WindowTreeBinding manages the binding between a WindowTree and its mojo
-// clients. WindowTreeBinding exists so that the client can be mocked for
-// tests. WindowTree owns its associated WindowTreeBinding.
+// WindowTreeBinding manages the binding between a WindowTree and its
+// WindowTreeClient. WindowTreeBinding exists so that a mock implementation
+// of WindowTreeClient can be injected for tests. WindowTree owns its
+// associated WindowTreeBinding.
 class WindowTreeBinding {
  public:
   explicit WindowTreeBinding(mojom::WindowTreeClient* client);
diff --git a/components/mus/ws/window_tree_client_unittest.cc b/components/mus/ws/window_tree_client_unittest.cc
index d8a1e40..5ec93ae 100644
--- a/components/mus/ws/window_tree_client_unittest.cc
+++ b/components/mus/ws/window_tree_client_unittest.cc
@@ -24,7 +24,6 @@
 using mojo::InterfaceRequest;
 using shell::ShellClient;
 using mojo::String;
-using mus::mojom::ErrorCode;
 using mus::mojom::WindowDataPtr;
 using mus::mojom::WindowTree;
 using mus::mojom::WindowTreeClient;
@@ -387,6 +386,12 @@
   }
 
   // mojom::WindowManager:
+  void OnConnect(uint16_t client_id) override {}
+  void WmNewDisplayAdded(mojom::DisplayPtr display,
+                         mojom::WindowDataPtr root_data,
+                         bool drawn) override {
+    NOTIMPLEMENTED();
+  }
   void WmSetBounds(uint32_t change_id,
                    uint32_t window_id,
                    const gfx::Rect& bounds) override {
diff --git a/components/nacl.gyp b/components/nacl.gyp
index 91068d9..677fbc4 100644
--- a/components/nacl.gyp
+++ b/components/nacl.gyp
@@ -140,13 +140,6 @@
                 '../sandbox/sandbox.gyp:sandbox_services',
               ]
             }],
-            ['OS=="win"', {
-              'dependencies': [
-                # TODO(fdoray): Remove this once the PreRead field trial has
-                # expired. crbug.com/577698
-                '../components/components.gyp:startup_metric_utils_win',
-              ]
-            }],
           ],
         },
         {
diff --git a/components/nacl/broker/BUILD.gn b/components/nacl/broker/BUILD.gn
index d191a04..a2fa9a67 100644
--- a/components/nacl/broker/BUILD.gn
+++ b/components/nacl/broker/BUILD.gn
@@ -158,7 +158,7 @@
       "//components/policy",
       "//content/public/common:static_switches",
       "//ipc",
-      "//third_party/kasko:kasko_features",
+      "//third_party/kasko",
     ]
   }
 }
diff --git a/components/nacl/browser/BUILD.gn b/components/nacl/browser/BUILD.gn
index 4d52280..6336573 100644
--- a/components/nacl/browser/BUILD.gn
+++ b/components/nacl/browser/BUILD.gn
@@ -63,14 +63,6 @@
     data_deps += [ "//components/nacl/loader:helper_nonsfi" ]
   }
 
-  if (is_win) {
-    deps += [
-      # TODO(fdoray): Remove this once the PreRead field trial has expired.
-      # crbug.com/577698
-      "//components/startup_metric_utils/common",
-    ]
-  }
-
   if (is_win && current_cpu == "x86") {
     data_deps += [ "//components/nacl/broker:nacl64" ]
   }
diff --git a/components/nacl/browser/DEPS b/components/nacl/browser/DEPS
index 2e1a96b..efbdb131 100644
--- a/components/nacl/browser/DEPS
+++ b/components/nacl/browser/DEPS
@@ -1,7 +1,4 @@
 include_rules = [
-  # TODO(fdoray): Remove this once the PreRead field trial has expired.
-  # crbug.com/577698
-  "+components/startup_metric_utils/common",
   "+components/url_formatter",
   "+content/public/browser",
   "+content/public/test",
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index b47ed16..45b02d5 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -77,7 +77,6 @@
 #include "base/win/scoped_handle.h"
 #include "components/nacl/browser/nacl_broker_service_win.h"
 #include "components/nacl/common/nacl_debug_exception_handler_win.h"
-#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h"
 #include "content/public/common/sandbox_init.h"
 #endif
 
@@ -645,8 +644,7 @@
     cmd_line->AppendSwitch(switches::kNoErrorDialogs);
 
 #if defined(OS_WIN)
-  if (startup_metric_utils::GetPreReadOptions().use_prefetch_argument)
-    cmd_line->AppendArg(switches::kPrefetchArgumentOther);
+  cmd_line->AppendArg(switches::kPrefetchArgumentOther);
 #endif  // defined(OS_WIN)
 
 // On Windows we might need to start the broker process to launch a new loader
diff --git a/components/offline_pages.gypi b/components/offline_pages.gypi
index c53dd5b..10902b1 100644
--- a/components/offline_pages.gypi
+++ b/components/offline_pages.gypi
@@ -61,6 +61,7 @@
         'keyed_service_core',
       ],
       'sources': [
+        'offline_pages/background/device_conditions.h',
         'offline_pages/background/offliner.h',
         'offline_pages/background/offliner_factory.h',
         'offline_pages/background/offliner_policy.h',
diff --git a/components/offline_pages/background/BUILD.gn b/components/offline_pages/background/BUILD.gn
index b0b12ca..fe04e4e 100644
--- a/components/offline_pages/background/BUILD.gn
+++ b/components/offline_pages/background/BUILD.gn
@@ -9,6 +9,7 @@
 # GYP: //components/offline_pages/offline_pages.gypi:background_offliner
 static_library("background_offliner") {
   sources = [
+    "device_conditions.h",
     "offliner.h",
     "offliner_factory.h",
     "offliner_policy.h",
diff --git a/components/offline_pages/background/device_conditions.h b/components/offline_pages/background/device_conditions.h
new file mode 100644
index 0000000..e26c7d1
--- /dev/null
+++ b/components/offline_pages/background/device_conditions.h
@@ -0,0 +1,42 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_BACKGROUND_DEVICE_CONDITIONS_H_
+#define COMPONENTS_OFFLINE_PAGES_BACKGROUND_DEVICE_CONDITIONS_H_
+
+#include "net/base/network_change_notifier.h"
+
+namespace offline_pages {
+
+// Device network and power conditions.
+class DeviceConditions {
+ public:
+  DeviceConditions(
+      bool power_connected,
+      int battery_percentage,
+      net::NetworkChangeNotifier::ConnectionType net_connection_type)
+      : power_connected_(power_connected),
+        battery_percentage_(battery_percentage),
+        net_connection_type_(net_connection_type) {}
+
+  // Returns whether power is connected.
+  bool IsPowerConnected() const { return power_connected_; }
+
+  // Returns percentage of remaining battery power (0-100).
+  int GetBatteryPercentage() const { return battery_percentage_; }
+
+  // Returns the current type of network connection, if any.
+  net::NetworkChangeNotifier::ConnectionType GetNetConnectionType() const {
+    return net_connection_type_;
+  }
+
+ private:
+  const bool power_connected_;
+  const int battery_percentage_;
+  const net::NetworkChangeNotifier::ConnectionType net_connection_type_;
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_BACKGROUND_DEVICE_CONDITIONS_H_
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc
index ffbd5bf3..d5e87d26 100644
--- a/components/offline_pages/background/request_coordinator.cc
+++ b/components/offline_pages/background/request_coordinator.cc
@@ -86,6 +86,7 @@
 }
 
 bool RequestCoordinator::StartProcessing(
+    const DeviceConditions& device_conditions,
     const base::Callback<void(bool)>& callback) {
   scheduler_callback_ = callback;
   // TODO(petewil): Check existing conditions (should be passed down from
@@ -136,18 +137,18 @@
            << __FUNCTION__;
   last_offlining_status_ = status;
 
-  // TODO(petewil): If the request succeeded, remove it from the Queue.
+  // If the request succeeded, remove it from the Queue and maybe schedule
+  // another one.
   if (status == Offliner::RequestStatus::SAVED) {
     queue_->RemoveRequest(request.request_id(),
                           base::Bind(&RequestCoordinator::UpdateRequestCallback,
                                      weak_ptr_factory_.GetWeakPtr()));
+
+    // TODO(petewil): Check time budget. Return to the scheduler if we are out.
+
+    // Start another request if we have time.
+    TryNextRequest();
   }
-
-  // TODO(petewil): Check time budget. Return to the scheduler if we are out.
-
-
-  // Start a request if we have time.
-  TryNextRequest();
 }
 
 }  // namespace offline_pages
diff --git a/components/offline_pages/background/request_coordinator.h b/components/offline_pages/background/request_coordinator.h
index dddcca8..ffbb857 100644
--- a/components/offline_pages/background/request_coordinator.h
+++ b/components/offline_pages/background/request_coordinator.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "components/offline_pages/background/device_conditions.h"
 #include "components/offline_pages/background/offliner.h"
 #include "components/offline_pages/background/request_queue.h"
 #include "url/gurl.h"
@@ -47,7 +48,8 @@
   // Starts processing of one or more queued save page later requests.
   // Returns whether processing was started and that caller should expect
   // a callback. If processing was already active, returns false.
-  bool StartProcessing(const base::Callback<void(bool)>& callback);
+  bool StartProcessing(const DeviceConditions& device_conditions,
+                       const base::Callback<void(bool)>& callback);
 
   // Stops the current request processing if active. This is a way for
   // caller to abort processing; otherwise, processing will complete on
diff --git a/components/offline_pages/background/request_coordinator_unittest.cc b/components/offline_pages/background/request_coordinator_unittest.cc
index 7e0ba5f..ebcbe14 100644
--- a/components/offline_pages/background/request_coordinator_unittest.cc
+++ b/components/offline_pages/background/request_coordinator_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/test/test_simple_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/background/device_conditions.h"
 #include "components/offline_pages/background/offliner.h"
 #include "components/offline_pages/background/offliner_factory.h"
 #include "components/offline_pages/background/offliner_policy.h"
@@ -165,11 +166,13 @@
 
 
 TEST_F(RequestCoordinatorTest, StartProcessingWithNoRequests) {
+  DeviceConditions device_conditions(false, 75,
+                                     net::NetworkChangeNotifier::CONNECTION_3G);
   base::Callback<void(bool)> callback =
       base::Bind(
           &RequestCoordinatorTest::EmptyCallbackFunction,
           base::Unretained(this));
-  EXPECT_TRUE(coordinator()->StartProcessing(callback));
+  EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
 }
 
 TEST_F(RequestCoordinatorTest, SavePageLater) {
@@ -194,8 +197,7 @@
   EXPECT_TRUE(scheduler_stub->schedule_called());
 }
 
-TEST_F(RequestCoordinatorTest, OfflinerDone) {
-
+TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
   // Add a request to the queue, wait for callbacks to finish.
   offline_pages::SavePageRequest request(
       kRequestId, kUrl, kClientId, base::Time::Now());
@@ -229,4 +231,37 @@
   EXPECT_EQ(0UL, last_requests().size());
 }
 
+TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
+  // Add a request to the queue, wait for callbacks to finish.
+  offline_pages::SavePageRequest request(
+      kRequestId, kUrl, kClientId, base::Time::Now());
+  coordinator()->queue()->AddRequest(
+      request,
+      base::Bind(&RequestCoordinatorTest::AddRequestDone,
+                 base::Unretained(this)));
+  PumpLoop();
+
+  // We need to give a callback to the request.
+  base::Callback<void(bool)> callback =
+      base::Bind(
+          &RequestCoordinatorTest::EmptyCallbackFunction,
+          base::Unretained(this));
+  coordinator()->SetProcessingCallbackForTest(callback);
+
+  // Call the OfflinerDoneCallback to simulate the request failed, wait
+  // for callbacks.
+  SendOfflinerDoneCallback(request, Offliner::RequestStatus::FAILED);
+  PumpLoop();
+
+  // Verify the request is not removed from the queue, and wait for callbacks.
+  coordinator()->queue()->GetRequests(
+      base::Bind(&RequestCoordinatorTest::GetRequestsDone,
+                 base::Unretained(this)));
+  PumpLoop();
+
+  // Still one request in the queue.
+  EXPECT_EQ(1UL, last_requests().size());
+  // TODO(dougarnett): Verify retry count gets incremented.
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_feature.cc b/components/offline_pages/offline_page_feature.cc
index 159ea9a8..d522bc96 100644
--- a/components/offline_pages/offline_page_feature.cc
+++ b/components/offline_pages/offline_page_feature.cc
@@ -22,9 +22,13 @@
    "OfflinePagesBackgroundLoading", base::FEATURE_DISABLED_BY_DEFAULT
 };
 
+const base::Feature kOfflinePagesCTFeature {
+   "OfflinePagesCT", base::FEATURE_DISABLED_BY_DEFAULT
+};
+
 bool IsOfflinePagesEnabled() {
   return IsOfflineBookmarksEnabled() || IsOffliningRecentPagesEnabled() ||
-         IsOfflinePagesBackgroundLoadingEnabled();
+         IsOfflinePagesBackgroundLoadingEnabled() || IsOfflinePagesCTEnabled();
 }
 
 bool IsOfflineBookmarksEnabled() {
@@ -39,4 +43,8 @@
   return base::FeatureList::IsEnabled(kOfflinePagesBackgroundLoadingFeature);
 }
 
+bool IsOfflinePagesCTEnabled() {
+  return base::FeatureList::IsEnabled(kOfflinePagesCTFeature);
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/offline_page_feature.h b/components/offline_pages/offline_page_feature.h
index 96fd5a1..bdfefaf 100644
--- a/components/offline_pages/offline_page_feature.h
+++ b/components/offline_pages/offline_page_feature.h
@@ -13,6 +13,7 @@
 extern const base::Feature kOfflineBookmarksFeature;
 extern const base::Feature kOffliningRecentPagesFeature;
 extern const base::Feature kOfflinePagesBackgroundLoadingFeature;
+extern const base::Feature kOfflinePagesCTFeature;
 
 // Returns true if offline pages, as result of one or more offline features
 // being enabled, is enabled.
@@ -27,6 +28,9 @@
 // Returns true if saving offline pages in the background is enabled.
 bool IsOfflinePagesBackgroundLoadingEnabled();
 
+// Returns true if offline CT features are enabled.  See crbug.com/620421.
+bool IsOfflinePagesCTEnabled();
+
 }  // namespace offline_pages
 
 #endif  // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_FEATURE_H_
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 65f7eda..75582b6 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -8434,7 +8434,7 @@
           'caption': '''Always send WiFi acess-points to server while resolving timezone.''',
         },
       ],
-      'supported_on': ['chrome_os:51-'],
+      'supported_on': ['chrome_os:53-'],
       'device_only': True,
       'features': {
         'dynamic_refresh': True,
diff --git a/components/safe_json/safe_json_parser_impl.cc b/components/safe_json/safe_json_parser_impl.cc
index 40edbc7..09909e1 100644
--- a/components/safe_json/safe_json_parser_impl.cc
+++ b/components/safe_json/safe_json_parser_impl.cc
@@ -4,23 +4,14 @@
 
 #include "components/safe_json/safe_json_parser_impl.h"
 
-#include <utility>
-
+#include "base/callback.h"
 #include "base/sequenced_task_runner.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/tuple.h"
 #include "base/values.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/utility_process_host.h"
-#include "content/public/common/service_registry.h"
 #include "grit/components_strings.h"
 #include "ui/base/l10n/l10n_util.h"
 
-using content::BrowserThread;
-using content::UtilityProcessHost;
-
 namespace safe_json {
 
 SafeJsonParserImpl::SafeJsonParserImpl(const std::string& unsafe_json,
@@ -32,90 +23,81 @@
   io_thread_checker_.DetachFromThread();
 }
 
-SafeJsonParserImpl::~SafeJsonParserImpl() {
-}
-
-void SafeJsonParserImpl::StartWorkOnIOThread() {
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  // TODO(amistry): This UtilityProcessHost dance is likely to be done multiple
-  // times as more tasks are migrated to Mojo. Create some sort of helper class
-  // to eliminate the code duplication.
-  utility_process_host_ = UtilityProcessHost::Create(
-      this, base::ThreadTaskRunnerHandle::Get().get())->AsWeakPtr();
-  utility_process_host_->SetName(
-      l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_JSON_PARSER_NAME));
-  if (!utility_process_host_->Start()) {
-    ReportResults();
-    return;
-  }
-
-  content::ServiceRegistry* service_registry =
-      utility_process_host_->GetServiceRegistry();
-  service_registry->ConnectToRemoteService(mojo::GetProxy(&service_));
-  service_.set_connection_error_handler(
-      base::Bind(&SafeJsonParserImpl::ReportResults, this));
-
-  service_->Parse(unsafe_json_,
-                  base::Bind(&SafeJsonParserImpl::OnParseDone, this));
-}
-
-void SafeJsonParserImpl::ReportResults() {
-  // There should be a DCHECK_CURRENTLY_ON(BrowserThread::IO) here. However, if
-  // the parser process is still alive on shutdown, this might run on the IO
-  // thread while the IO thread message loop is shutting down. This happens
-  // after the IO thread has unregistered from the BrowserThread list, causing
-  // the DCHECK to fail.
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  io_thread_checker_.DetachFromThread();
-
-  // Maintain a reference to |this| since either |utility_process_host_| or
-  // |service_| may have the last reference and destroying those might delete
-  // |this|.
-  scoped_refptr<SafeJsonParserImpl> ref(this);
-  // Shut down the utility process if it's still running.
-  delete utility_process_host_.get();
-  service_.reset();
-
-  caller_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&SafeJsonParserImpl::ReportResultsOnOriginThread, this));
-}
-
-void SafeJsonParserImpl::ReportResultsOnOriginThread() {
-  DCHECK(caller_task_runner_->RunsTasksOnCurrentThread());
-  if (error_.empty() && parsed_json_) {
-    if (!success_callback_.is_null())
-      success_callback_.Run(std::move(parsed_json_));
-  } else {
-    if (!error_callback_.is_null())
-      error_callback_.Run(error_);
-  }
-}
-
-bool SafeJsonParserImpl::OnMessageReceived(const IPC::Message& message) {
-  return false;
-}
-
-void SafeJsonParserImpl::OnParseDone(const base::ListValue& wrapper,
-                                     mojo::String error) {
-  DCHECK(io_thread_checker_.CalledOnValidThread());
-  if (!wrapper.empty()) {
-    const base::Value* value = NULL;
-    CHECK(wrapper.Get(0, &value));
-    parsed_json_.reset(value->DeepCopy());
-  } else {
-    error_ = error.get();
-  }
-  ReportResults();
-}
+SafeJsonParserImpl::~SafeJsonParserImpl() = default;
 
 void SafeJsonParserImpl::Start() {
   caller_task_runner_ = base::SequencedTaskRunnerHandle::Get();
 
-  BrowserThread::PostTask(
-      BrowserThread::IO, FROM_HERE,
-      base::Bind(&SafeJsonParserImpl::StartWorkOnIOThread, this));
+  content::BrowserThread::PostTask(
+      content::BrowserThread::IO, FROM_HERE,
+      base::Bind(&SafeJsonParserImpl::StartOnIOThread, base::Unretained(this)));
+}
+
+void SafeJsonParserImpl::StartOnIOThread() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK(io_thread_checker_.CalledOnValidThread());
+  mojo_json_parser_.reset(
+      new content::UtilityProcessMojoClient<mojom::SafeJsonParser>(
+          l10n_util::GetStringUTF16(IDS_UTILITY_PROCESS_JSON_PARSER_NAME),
+          base::Bind(&SafeJsonParserImpl::OnConnectionError,
+                     base::Unretained(this))));
+
+  mojo_json_parser_->Start();
+
+  mojo_json_parser_->service()->Parse(
+      std::move(unsafe_json_),
+      base::Bind(&SafeJsonParserImpl::OnParseDone, base::Unretained(this)));
+}
+
+void SafeJsonParserImpl::OnConnectionError() {
+  DCHECK(io_thread_checker_.CalledOnValidThread());
+
+  // Shut down the utility process.
+  mojo_json_parser_.reset();
+
+  caller_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&SafeJsonParserImpl::ReportResults,
+                            base::Unretained(this), nullptr, "Json error"));
+}
+
+void SafeJsonParserImpl::OnParseDone(const base::ListValue& wrapper,
+                                     const mojo::String& error) {
+  DCHECK(io_thread_checker_.CalledOnValidThread());
+
+  // Shut down the utility process.
+  mojo_json_parser_.reset();
+
+  std::unique_ptr<base::Value> parsed_json;
+  std::string error_message;
+  if (!wrapper.empty()) {
+    const base::Value* value = nullptr;
+    CHECK(wrapper.Get(0, &value));
+    parsed_json.reset(value->DeepCopy());
+  } else {
+    error_message = error.get();
+  }
+
+  // Call ReportResults() on caller's thread.
+  caller_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&SafeJsonParserImpl::ReportResults, base::Unretained(this),
+                 base::Passed(&parsed_json), error_message));
+}
+
+void SafeJsonParserImpl::ReportResults(std::unique_ptr<base::Value> parsed_json,
+                                       const std::string& error) {
+  DCHECK(caller_task_runner_->RunsTasksOnCurrentThread());
+  if (error.empty() && parsed_json) {
+    if (!success_callback_.is_null())
+      success_callback_.Run(std::move(parsed_json));
+  } else {
+    if (!error_callback_.is_null())
+      error_callback_.Run(error);
+  }
+
+  // The parsing is done whether an error occured or not, so this instance can
+  // be cleaned up.
+  delete this;
 }
 
 }  // namespace safe_json
diff --git a/components/safe_json/safe_json_parser_impl.h b/components/safe_json/safe_json_parser_impl.h
index eefa187d3..abc51945 100644
--- a/components/safe_json/safe_json_parser_impl.h
+++ b/components/safe_json/safe_json_parser_impl.h
@@ -8,13 +8,13 @@
 #include <memory>
 #include <string>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "components/safe_json/public/interfaces/safe_json.mojom.h"
 #include "components/safe_json/safe_json_parser.h"
-#include "content/public/browser/utility_process_host_client.h"
+#include "content/public/browser/utility_process_mojo_client.h"
 
 namespace base {
 class ListValue;
@@ -22,18 +22,9 @@
 class Value;
 }
 
-namespace content {
-class UtilityProcessHost;
-}
-
-namespace IPC {
-class Message;
-}
-
 namespace safe_json {
 
-class SafeJsonParserImpl : public content::UtilityProcessHostClient,
-                           public SafeJsonParser {
+class SafeJsonParserImpl : public SafeJsonParser {
  public:
   SafeJsonParserImpl(const std::string& unsafe_json,
                      const SuccessCallback& success_callback,
@@ -42,34 +33,32 @@
  private:
   ~SafeJsonParserImpl() override;
 
-  void StartWorkOnIOThread();
-
-  void ReportResults();
-  void ReportResultsOnOriginThread();
-
-  // Implementing pieces of the UtilityProcessHostClient interface.
-  bool OnMessageReceived(const IPC::Message& message) override;
-
   // SafeJsonParser implementation.
   void Start() override;
 
+  void StartOnIOThread();
+  void OnConnectionError();
+
   // mojom::SafeJsonParser::Parse callback.
-  void OnParseDone(const base::ListValue& wrapper, mojo::String error);
+  void OnParseDone(const base::ListValue& wrapper, const mojo::String& error);
+
+  // Reports the result on the calling task runner via the |success_callback_|
+  // or the |error_callback_|.
+  void ReportResults(std::unique_ptr<base::Value> parsed_json,
+                     const std::string& error);
 
   const std::string unsafe_json_;
   SuccessCallback success_callback_;
   ErrorCallback error_callback_;
   scoped_refptr<base::SequencedTaskRunner> caller_task_runner_;
 
-  std::unique_ptr<base::Value> parsed_json_;
-  std::string error_;
+  std::unique_ptr<content::UtilityProcessMojoClient<mojom::SafeJsonParser>>
+      mojo_json_parser_;
 
-  base::WeakPtr<content::UtilityProcessHost> utility_process_host_;
-
-  mojom::SafeJsonParserPtr service_;
-
-  // To ensure the UtilityProcessHost and Mojo service are only accessed on the
-  // IO thread.
+  // Used instead of DCHECK_CURRENTLY_ON(BrowserThread::IO) because it's
+  // posssible that it fails when the IO thread message loop is shutting down.
+  // This happens after the IO thread has unregistered from the BrowserThread
+  // list.
   base::ThreadChecker io_thread_checker_;
 
   DISALLOW_COPY_AND_ASSIGN(SafeJsonParserImpl);
diff --git a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc
index bed524ad..cb9207a 100644
--- a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc
+++ b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc
@@ -33,7 +33,6 @@
 const base::char16 kHighPriorityVariationName[] = L"HighPriority";
 const base::char16 kPrefetchVirtualMemoryVariationName[] =
     L"PrefetchVirtualMemory";
-const base::char16 kNoPrefetchArgumentVariationName[] = L"NoPrefetchArgument";
 const base::char16 kPreReadChromeChildInBrowser[] =
     L"PreReadChromeChildInBrowser";
 
@@ -78,8 +77,6 @@
   g_pre_read_options.high_priority = ReadBool(key, kHighPriorityVariationName);
   g_pre_read_options.prefetch_virtual_memory =
       ReadBool(key, kPrefetchVirtualMemoryVariationName);
-  g_pre_read_options.use_prefetch_argument =
-      !ReadBool(key, kNoPrefetchArgumentVariationName);
   g_pre_read_options.pre_read_chrome_child_in_browser =
       ReadBool(key, kPreReadChromeChildInBrowser);
 }
diff --git a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h
index f9e41a5d..beed901 100644
--- a/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h
+++ b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h
@@ -30,9 +30,6 @@
   // Pre-read DLLs using the ::PrefetchVirtualMemory function, if available.
   bool prefetch_virtual_memory : 1;
 
-  // Use a /prefetch argument when launching a process.
-  bool use_prefetch_argument : 1;
-
   // Pre-read chrome_child.dll in the browser process and not in child
   // processes.
   bool pre_read_chrome_child_in_browser : 1;
diff --git a/components/subresource_filter.gypi b/components/subresource_filter.gypi
index 3989f82..00c55cc 100644
--- a/components/subresource_filter.gypi
+++ b/components/subresource_filter.gypi
@@ -11,6 +11,7 @@
       'dependencies': [
         '../base/base.gyp:base',
         '../components/components.gyp:variations',
+        '../components/prefs/prefs.gyp:prefs',
         'subresource_filter_core_common',
       ],
       'include_dirs': [
@@ -18,6 +19,11 @@
       ],
       'sources': [
         # Note: sources list duplicated in GN build.
+        'subresource_filter/core/browser/ruleset_distributor.h',
+        'subresource_filter/core/browser/ruleset_service.cc',
+        'subresource_filter/core/browser/ruleset_service.h',
+        'subresource_filter/core/browser/subresource_filter_constants.cc',
+        'subresource_filter/core/browser/subresource_filter_constants.h',
         'subresource_filter/core/browser/subresource_filter_features.cc',
         'subresource_filter/core/browser/subresource_filter_features.h',
       ],
diff --git a/components/subresource_filter/DEPS b/components/subresource_filter/DEPS
index 9ec8520..f913c8b7 100644
--- a/components/subresource_filter/DEPS
+++ b/components/subresource_filter/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+components/prefs",
   "+components/variations",
   # subresource_filter is a layered component; subdirectories must explicitly
   # introduce the ability to use non-core layers as appropriate.
diff --git a/components/subresource_filter/core/browser/BUILD.gn b/components/subresource_filter/core/browser/BUILD.gn
index c6cb14a..63b8458 100644
--- a/components/subresource_filter/core/browser/BUILD.gn
+++ b/components/subresource_filter/core/browser/BUILD.gn
@@ -4,11 +4,17 @@
 
 source_set("browser") {
   sources = [
+    "ruleset_distributor.h",
+    "ruleset_service.cc",
+    "ruleset_service.h",
+    "subresource_filter_constants.cc",
+    "subresource_filter_constants.h",
     "subresource_filter_features.cc",
     "subresource_filter_features.h",
   ]
   deps = [
     "//base",
+    "//components/prefs:prefs",
     "//components/subresource_filter/core/common",
     "//components/variations",
   ]
@@ -31,12 +37,16 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "ruleset_service_unittest.cc",
     "subresource_filter_features_unittest.cc",
   ]
   deps = [
     ":browser",
     ":test_support",
     "//base",
+    "//base/test:test_support",
+    "//components/prefs:test_support",
+    "//testing/gmock",
     "//testing/gtest",
   ]
 }
diff --git a/components/subresource_filter/core/browser/ruleset_distributor.h b/components/subresource_filter/core/browser/ruleset_distributor.h
new file mode 100644
index 0000000..fe9e62e
--- /dev/null
+++ b/components/subresource_filter/core/browser/ruleset_distributor.h
@@ -0,0 +1,27 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_RULESET_DISTRIBUTOR_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_RULESET_DISTRIBUTOR_H_
+
+#include "base/files/file.h"
+
+namespace subresource_filter {
+
+// Defines the interface for the implementation responsible for distributing
+// updated versions of subresource filtering rules to consumers. It is not
+// intended as a general-purpose `subscriber` to the RulesetService. The extra
+// level of indirection exists to allow the service to not depend on content/.
+class RulesetDistributor {
+ public:
+  virtual ~RulesetDistributor() = default;
+
+  // Instructs the distributor to redistribute the new version of the |ruleset|
+  // to all existing consumers, and to distribute it to future consumers.
+  virtual void PublishNewVersion(base::File ruleset_data) = 0;
+};
+
+}  // namespace subresource_filter
+
+#endif  // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_RULESET_DISTRIBUTOR_H_
diff --git a/components/subresource_filter/core/browser/ruleset_service.cc b/components/subresource_filter/core/browser/ruleset_service.cc
new file mode 100644
index 0000000..d1af816
--- /dev/null
+++ b/components/subresource_filter/core/browser/ruleset_service.cc
@@ -0,0 +1,213 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/browser/ruleset_service.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file_proxy.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/rand_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/subresource_filter/core/browser/ruleset_distributor.h"
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+
+namespace subresource_filter {
+
+// Constant definitions and helper functions ---------------------------------
+
+namespace {
+
+// The current binary format version of the serialized ruleset.
+const int kCurrentRulesetFormatVersion = 10;
+
+// Names of the preferences storing the most recent ruleset version that
+// was successfully stored to disk.
+const char kSubresourceFilterRulesetContentVersion[] =
+    "subresource_filter.ruleset_version.content";
+const char kSubresourceFilterRulesetFormatVersion[] =
+    "subresource_filter.ruleset_version.format";
+
+base::FilePath GetSubdirectoryPathForVersion(const base::FilePath& base_dir,
+                                             const RulesetVersion& version) {
+  return base_dir.AppendASCII(version.AsString());
+}
+
+base::FilePath GetRulesetDataFilePath(const base::FilePath& version_directory) {
+  return version_directory.Append(kRulesetDataFileName);
+}
+
+// Returns a duplicate of the file wrapped by |file_proxy|. Temporary workaround
+// because base::FileProxy exposes neither the underlying file nor a Duplicate()
+// method.
+base::File DuplicateHandle(base::FileProxy* file_proxy) {
+  DCHECK(file_proxy);
+  DCHECK(file_proxy->IsValid());
+  base::File file = file_proxy->TakeFile();
+  base::File duplicate = file.Duplicate();
+  file_proxy->SetFile(std::move(file));
+  return duplicate;
+}
+
+}  // namespace
+
+// RulesetVersion ------------------------------------------------------------
+
+RulesetVersion::RulesetVersion() = default;
+RulesetVersion::RulesetVersion(const std::string& content_version,
+                               int format_version)
+    : content_version(content_version), format_version(format_version) {}
+RulesetVersion::~RulesetVersion() = default;
+RulesetVersion& RulesetVersion::operator=(const RulesetVersion&) = default;
+
+// static
+void RulesetVersion::RegisterPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(kSubresourceFilterRulesetContentVersion,
+                               std::string());
+  registry->RegisterIntegerPref(kSubresourceFilterRulesetFormatVersion, 0);
+}
+
+// static
+int RulesetVersion::CurrentFormatVersion() {
+  return kCurrentRulesetFormatVersion;
+}
+
+void RulesetVersion::ReadFromPrefs(PrefService* local_state) {
+  format_version =
+      local_state->GetInteger(kSubresourceFilterRulesetFormatVersion);
+  content_version =
+      local_state->GetString(kSubresourceFilterRulesetContentVersion);
+}
+
+bool RulesetVersion::IsValid() const {
+  return format_version != 0 && !content_version.empty();
+}
+
+bool RulesetVersion::IsCurrentFormatVersion() const {
+  return format_version == CurrentFormatVersion();
+}
+
+void RulesetVersion::SaveToPrefs(PrefService* local_state) const {
+  DCHECK(IsValid());
+  local_state->SetInteger(kSubresourceFilterRulesetFormatVersion,
+                          format_version);
+  local_state->SetString(kSubresourceFilterRulesetContentVersion,
+                         content_version);
+}
+
+std::string RulesetVersion::AsString() const {
+  DCHECK(IsValid());
+  return base::IntToString(format_version) + "_" + content_version;
+}
+
+// RulesetService ------------------------------------------------------------
+
+RulesetService::RulesetService(
+    PrefService* local_state,
+    scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+    const base::FilePath& base_dir)
+    : local_state_(local_state),
+      blocking_task_runner_(blocking_task_runner),
+      base_dir_(base_dir) {
+  DCHECK_NE(local_state_->GetInitializationStatus(),
+            PrefService::INITIALIZATION_STATUS_WAITING);
+  RulesetVersion version_on_disk;
+  version_on_disk.ReadFromPrefs(local_state_);
+  if (version_on_disk.IsCurrentFormatVersion())
+    OpenAndPublishRuleset(version_on_disk);
+}
+
+RulesetService::~RulesetService() {}
+
+void RulesetService::StoreAndPublishUpdatedRuleset(
+    std::vector<uint8_t> ruleset_data,
+    const std::string& new_content_version) {
+  // TODO(engedy): The |format_version| corresponds to the output of the
+  // indexing step that will ultimately be performed here.
+  RulesetVersion new_version(new_content_version,
+                             RulesetVersion::CurrentFormatVersion());
+  base::PostTaskAndReplyWithResult(
+      blocking_task_runner_.get(), FROM_HERE,
+      base::Bind(&WriteRuleset, base_dir_, new_version,
+                 std::move(ruleset_data)),
+      base::Bind(&RulesetService::OnWrittenRuleset, AsWeakPtr(), new_version));
+}
+
+void RulesetService::RegisterDistributor(
+    std::unique_ptr<RulesetDistributor> distributor) {
+  if (ruleset_data_ && ruleset_data_->IsValid())
+    distributor->PublishNewVersion(DuplicateHandle(ruleset_data_.get()));
+  distributors_.push_back(std::move(distributor));
+}
+
+// static
+bool RulesetService::WriteRuleset(const base::FilePath& base_dir,
+                                  const RulesetVersion& version,
+                                  std::vector<uint8_t> data) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::ScopedTempDir scratch_dir;
+  if (!scratch_dir.CreateUniqueTempDirUnderPath(base_dir))
+    return false;
+
+  static_assert(sizeof(uint8_t) == sizeof(char), "Expected char = byte.");
+  const int data_size_in_chars = base::checked_cast<int>(data.size());
+  if (base::WriteFile(GetRulesetDataFilePath(scratch_dir.path()),
+                      reinterpret_cast<const char*>(data.data()),
+                      data_size_in_chars) != data_size_in_chars) {
+    return false;
+  }
+
+  DCHECK(base::PathExists(base_dir));
+  if (base::ReplaceFile(scratch_dir.path(),
+                        GetSubdirectoryPathForVersion(base_dir, version),
+                        nullptr)) {
+    scratch_dir.Take();
+    return true;
+  }
+
+  return false;
+}
+
+void RulesetService::OnWrittenRuleset(const RulesetVersion& version,
+                                      bool success) {
+  if (!success)
+    return;
+
+  version.SaveToPrefs(local_state_);
+  OpenAndPublishRuleset(version);
+}
+
+void RulesetService::OpenAndPublishRuleset(const RulesetVersion& version) {
+  ruleset_data_.reset(new base::FileProxy(blocking_task_runner_.get()));
+  // On Windows, open the file with FLAG_SHARE_DELETE to allow deletion while
+  // there are handles to it still open. Note that creating a new file at the
+  // same path would still be impossible until after the last of those handles
+  // is closed.
+  ruleset_data_->CreateOrOpen(
+      GetRulesetDataFilePath(GetSubdirectoryPathForVersion(base_dir_, version)),
+      base::File::FLAG_OPEN | base::File::FLAG_READ |
+          base::File::FLAG_SHARE_DELETE,
+      base::Bind(&RulesetService::OnOpenedRuleset, AsWeakPtr()));
+}
+
+void RulesetService::OnOpenedRuleset(base::File::Error error) {
+  // This should not happen unless |base_dir| has been tampered with.
+  if (!ruleset_data_ || !ruleset_data_->IsValid())
+    return;
+  DCHECK_EQ(error, base::File::Error::FILE_OK);
+  for (auto& distributor : distributors_)
+    distributor->PublishNewVersion(DuplicateHandle(ruleset_data_.get()));
+}
+
+}  // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/ruleset_service.h b/components/subresource_filter/core/browser/ruleset_service.h
new file mode 100644
index 0000000..1a718184
--- /dev/null
+++ b/components/subresource_filter/core/browser/ruleset_service.h
@@ -0,0 +1,121 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_RULESET_SERVICE_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_RULESET_SERVICE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace base {
+class FileProxy;
+class SequencedTaskRunner;
+}  // namespace base
+
+namespace subresource_filter {
+
+class RulesetDistributor;
+
+// Encapsulates the combination of the binary format version of the ruleset, and
+// the version of the ruleset's contents.
+struct RulesetVersion {
+  RulesetVersion();
+  RulesetVersion(const std::string& content_version, int format_version);
+  ~RulesetVersion();
+  RulesetVersion& operator=(const RulesetVersion&);
+
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+  static int CurrentFormatVersion();
+
+  bool IsValid() const;
+  bool IsCurrentFormatVersion() const;
+
+  void SaveToPrefs(PrefService* local_state) const;
+  void ReadFromPrefs(PrefService* local_state);
+  std::string AsString() const;
+
+  std::string content_version;
+  int format_version = 0;
+};
+
+// Responsible for versioned storage of subresource filtering rules, and for
+// supplying the most up-to-date version to the registered RulesetDistributors
+// for distribution.
+//
+// Files corresponding to each version of the ruleset are stored in a separate
+// subdirectory inside |ruleset_base_dir| named after the version. The version
+// information of the most recent successfully stored ruleset is written into
+// |local_state|. The invariant is maintained that the version pointed to by
+// preferences will exist on disk at any point in time. All file operations are
+// posted to |blocking_task_runner|.
+class RulesetService : public base::SupportsWeakPtr<RulesetService> {
+ public:
+  RulesetService(PrefService* local_state,
+                 scoped_refptr<base::SequencedTaskRunner> blocking_task_runner,
+                 const base::FilePath& base_dir);
+  ~RulesetService();
+
+  // Persists a new |content_version| of the |ruleset_data|, then, on success,
+  // publishes it through the registered distributors. The |ruleset_data| must
+  // be a function of the |content_version| in the mathematical sense, i.e.
+  // different |ruleset_data| contents should have different |content_versions|.
+  //
+  // Trying to store a ruleset with the same version for a second time will
+  // silenty fail on Windows if the previously stored copy of the rules is
+  // still in use. This, however, means that the new rules must have been
+  // successfully stored on the first try, otherwise they would not have been
+  // published. Therefore, the operation would have been idempotent anyway.
+  void StoreAndPublishUpdatedRuleset(std::vector<uint8_t> ruleset_data,
+                                     const std::string& content_version);
+
+  // Registers a |distributor| that will be notified each time a new version of
+  // the ruleset becomes avalable. The |distributor| will be destroyed along
+  // with |this|.
+  void RegisterDistributor(std::unique_ptr<RulesetDistributor> distributor);
+
+ private:
+  friend class SubresourceFilteringRulesetServiceTest;
+
+  // Writes a new |version| of the ruleset |data| into the correspondingly named
+  // subdirectory under |base_dir|, and returns true on success.
+  //
+  // It will attempt to overwrite the previously stored ruleset with the same
+  // version, if any. Doing so is needed in case the earlier write was
+  // interrupted, but will silently fail on Windows in case the earlier write
+  // was successful and the ruleset is in use. See the comment above regarding
+  // why this is not an issue in practice.
+  static bool WriteRuleset(const base::FilePath& base_dir,
+                           const RulesetVersion& version,
+                           std::vector<uint8_t> data);
+
+  void OnWrittenRuleset(const RulesetVersion& version, bool success);
+  void OpenAndPublishRuleset(const RulesetVersion& version);
+  void OnOpenedRuleset(base::File::Error error);
+
+  PrefService* const local_state_;
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+
+  const base::FilePath base_dir_;
+  std::unique_ptr<base::FileProxy> ruleset_data_;
+  std::vector<std::unique_ptr<RulesetDistributor>> distributors_;
+
+  DISALLOW_COPY_AND_ASSIGN(RulesetService);
+};
+
+}  // namespace subresource_filter
+
+#endif  // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_RULESET_SERVICE_H_
diff --git a/components/subresource_filter/core/browser/ruleset_service_unittest.cc b/components/subresource_filter/core/browser/ruleset_service_unittest.cc
new file mode 100644
index 0000000..2165d7b1
--- /dev/null
+++ b/components/subresource_filter/core/browser/ruleset_service_unittest.cc
@@ -0,0 +1,363 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/browser/ruleset_service.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <iterator>
+#include <memory>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/subresource_filter/core/browser/ruleset_distributor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+const char kTestContentVersion1[] = "1.2.3.4";
+const char kTestContentVersion2[] = "1.2.3.5";
+
+const uint8_t kDummyRuleset1[] = {11, 0, 12, 13, 14};
+const uint8_t kDummyRuleset2[] = {21, 0, 22, 23};
+
+class MockRulesetDistributor : public RulesetDistributor {
+ public:
+  MockRulesetDistributor() = default;
+  ~MockRulesetDistributor() override = default;
+
+  void PublishNewVersion(base::File ruleset_data) override {
+    published_rulesets_.push_back(std::move(ruleset_data));
+  }
+
+  std::vector<base::File>& published_rulesets() { return published_rulesets_; }
+
+ private:
+  std::vector<base::File> published_rulesets_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockRulesetDistributor);
+};
+
+std::vector<uint8_t> ReadFileContents(base::File* file) {
+  size_t length = base::checked_cast<size_t>(file->GetLength());
+  std::vector<uint8_t> contents(length);
+  static_assert(sizeof(uint8_t) == sizeof(char), "Expected char = byte.");
+  file->Read(0, reinterpret_cast<char*>(contents.data()),
+             base::checked_cast<int>(length));
+  return contents;
+}
+
+template <typename T, int N>
+std::vector<T> AsVector(const T (&array)[N]) {
+  return std::vector<T>(std::begin(array), std::end(array));
+}
+
+}  // namespace
+
+class SubresourceFilteringRulesetServiceTest : public ::testing::Test {
+ public:
+  SubresourceFilteringRulesetServiceTest()
+      : task_runner_(new base::TestSimpleTaskRunner),
+        task_runner_handle_(task_runner_),
+        mock_distributor_(nullptr) {}
+
+ protected:
+  void SetUp() override {
+    RulesetVersion::RegisterPrefs(pref_service_.registry());
+
+    ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+    ResetService(CreateRulesetService());
+    RunUntilIdle();
+  }
+
+  std::unique_ptr<RulesetService> CreateRulesetService() {
+    return base::WrapUnique(
+        new RulesetService(&pref_service_, task_runner_, base_dir()));
+  }
+
+  void ResetService(std::unique_ptr<RulesetService> new_service = nullptr) {
+    service_ = std::move(new_service);
+    if (service_) {
+      service_->RegisterDistributor(
+          base::WrapUnique(mock_distributor_ = new MockRulesetDistributor()));
+    } else {
+      mock_distributor_ = nullptr;
+    }
+  }
+
+  void StoreAndPublishUpdatedRuleset(const std::vector<uint8_t>& ruleset_data,
+                                     const std::string& new_content_version) {
+    service()->StoreAndPublishUpdatedRuleset(ruleset_data, new_content_version);
+  }
+
+  void WritePreexistingRuleset(const RulesetVersion& version,
+                               const std::vector<uint8_t>& data) {
+    RulesetService::WriteRuleset(base_dir(), version, data);
+  }
+
+  void RunUntilIdle() { task_runner_->RunUntilIdle(); }
+
+  void RunPendingTasksNTimes(size_t n) {
+    while (n--)
+      task_runner_->RunPendingTasks();
+  }
+
+  void AssertValidRulesetFileWithContents(
+      base::File* file,
+      const std::vector<uint8_t>& expected_contents) {
+    ASSERT_TRUE(file->IsValid());
+    ASSERT_EQ(expected_contents, ReadFileContents(file));
+  }
+
+  void AssertReadonlyRulesetFile(base::File* file) {
+    const char kTest[] = "t";
+    ASSERT_TRUE(file->IsValid());
+    ASSERT_EQ(-1, file->Write(0, kTest, sizeof(kTest)));
+  }
+
+  PrefService* prefs() { return &pref_service_; }
+  RulesetService* service() { return service_.get(); }
+  MockRulesetDistributor* mock_distributor() { return mock_distributor_; }
+  base::FilePath base_dir() const {
+    return scoped_temp_dir_.path().AppendASCII("Ruleset Base Dir");
+  }
+
+ private:
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
+  base::ThreadTaskRunnerHandle task_runner_handle_;
+  TestingPrefServiceSimple pref_service_;
+
+  base::ScopedTempDir scoped_temp_dir_;
+  std::unique_ptr<RulesetService> service_;
+  MockRulesetDistributor* mock_distributor_;  // Weak, owned by |service_|.
+
+  DISALLOW_COPY_AND_ASSIGN(SubresourceFilteringRulesetServiceTest);
+};
+
+TEST_F(SubresourceFilteringRulesetServiceTest, Startup_NoRulesetNotPublished) {
+  EXPECT_EQ(0u, mock_distributor()->published_rulesets().size());
+}
+
+// It should not normally happen that Local State indicates that a usable
+// version of the ruleset had been stored, yet the file is nowhere to be found,
+// but ensure some sane behavior just in case.
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       Startup_MissingRulesetNotPublished) {
+  RulesetVersion current_version(kTestContentVersion1,
+                                 RulesetVersion::CurrentFormatVersion());
+  // `Forget` to write ruleset data.
+  current_version.SaveToPrefs(prefs());
+
+  ResetService(CreateRulesetService());
+  RunUntilIdle();
+  EXPECT_EQ(0u, mock_distributor()->published_rulesets().size());
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       Startup_LegacyFormatRulesetNotPublished) {
+  int legacy_format_version = RulesetVersion::CurrentFormatVersion() - 1;
+  RulesetVersion legacy_version(kTestContentVersion1, legacy_format_version);
+  ASSERT_TRUE(legacy_version.IsValid());
+  legacy_version.SaveToPrefs(prefs());
+  WritePreexistingRuleset(legacy_version, AsVector(kDummyRuleset1));
+
+  ResetService(CreateRulesetService());
+  RunUntilIdle();
+  EXPECT_EQ(0u, mock_distributor()->published_rulesets().size());
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       Startup_ExistingRulesetPublished) {
+  const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
+  RulesetVersion current_version(kTestContentVersion1,
+                                 RulesetVersion::CurrentFormatVersion());
+  current_version.SaveToPrefs(prefs());
+  WritePreexistingRuleset(current_version, AsVector(kDummyRuleset1));
+
+  ResetService(CreateRulesetService());
+  RunUntilIdle();
+
+  ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets()[0], dummy_ruleset));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_Published) {
+  const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
+  service()->StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+  RunUntilIdle();
+
+  ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets()[0], dummy_ruleset));
+
+  MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+  service()->RegisterDistributor(base::WrapUnique(new_distributor));
+  ASSERT_EQ(1u, new_distributor->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &new_distributor->published_rulesets()[0], dummy_ruleset));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, NewRuleset_Persisted) {
+  const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
+  service()->StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+  RunUntilIdle();
+
+  RulesetVersion stored_version;
+  stored_version.ReadFromPrefs(prefs());
+  EXPECT_EQ(kTestContentVersion1, stored_version.content_version);
+  EXPECT_EQ(RulesetVersion::CurrentFormatVersion(),
+            stored_version.format_version);
+
+  ResetService(CreateRulesetService());
+  RunUntilIdle();
+
+  ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets()[0], dummy_ruleset));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       NewRulesetTwice_SecondRulesetPrevails) {
+  const std::vector<uint8_t> dummy_ruleset_1(AsVector(kDummyRuleset1));
+  const std::vector<uint8_t> dummy_ruleset_2(AsVector(kDummyRuleset2));
+
+  StoreAndPublishUpdatedRuleset(dummy_ruleset_1, kTestContentVersion1);
+  RunUntilIdle();
+
+  StoreAndPublishUpdatedRuleset(dummy_ruleset_2, kTestContentVersion2);
+  RunUntilIdle();
+
+  // This verifies that the contents from the first version of the ruleset file
+  // can still be read after it has been deprecated.
+  ASSERT_EQ(2u, mock_distributor()->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets()[0], dummy_ruleset_1));
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets()[1], dummy_ruleset_2));
+
+  MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+  service()->RegisterDistributor(base::WrapUnique(new_distributor));
+  ASSERT_EQ(1u, new_distributor->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &new_distributor->published_rulesets()[0], dummy_ruleset_2));
+
+  RulesetVersion stored_version;
+  stored_version.ReadFromPrefs(prefs());
+  EXPECT_EQ(kTestContentVersion2, stored_version.content_version);
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       NewRulesetSetShortlyBeforeDestruction_NoCrashes) {
+  const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
+  for (size_t num_tasks_inbetween = 0; num_tasks_inbetween < 5u;
+       ++num_tasks_inbetween) {
+    SCOPED_TRACE(::testing::Message() << "#Tasks: " << num_tasks_inbetween);
+
+    StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+    RunPendingTasksNTimes(num_tasks_inbetween);
+    ResetService();
+    RunUntilIdle();
+
+    base::DeleteFile(base_dir(), false);
+    ResetService(CreateRulesetService());
+  }
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       NewRulesetTwiceInQuickSuccession_SecondRulesetPrevails) {
+  const std::vector<uint8_t> dummy_ruleset_1(AsVector(kDummyRuleset1));
+  const std::vector<uint8_t> dummy_ruleset_2(AsVector(kDummyRuleset2));
+  for (size_t num_tasks_inbetween = 0; num_tasks_inbetween < 5u;
+       ++num_tasks_inbetween) {
+    SCOPED_TRACE(::testing::Message() << "#Tasks: " << num_tasks_inbetween);
+
+    StoreAndPublishUpdatedRuleset(dummy_ruleset_1, kTestContentVersion1);
+    RunPendingTasksNTimes(num_tasks_inbetween);
+
+    StoreAndPublishUpdatedRuleset(dummy_ruleset_2, kTestContentVersion2);
+    RunUntilIdle();
+
+    // Optionally permit a "hazardous" publication of either the old or new
+    // version of the ruleset, but the last ruleset message must be the new one.
+    ASSERT_LE(1u, mock_distributor()->published_rulesets().size());
+    ASSERT_GE(2u, mock_distributor()->published_rulesets().size());
+    if (mock_distributor()->published_rulesets().size() == 2) {
+      base::File* file = &mock_distributor()->published_rulesets()[0];
+      ASSERT_TRUE(file->IsValid());
+      EXPECT_THAT(ReadFileContents(file),
+                  testing::AnyOf(testing::Eq(dummy_ruleset_1),
+                                 testing::Eq(dummy_ruleset_2)));
+    }
+    ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+        &mock_distributor()->published_rulesets().back(), dummy_ruleset_2));
+
+    MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+    service()->RegisterDistributor(base::WrapUnique(new_distributor));
+    ASSERT_EQ(1u, new_distributor->published_rulesets().size());
+    ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+        &new_distributor->published_rulesets()[0], dummy_ruleset_2));
+
+    RulesetVersion stored_version;
+    stored_version.ReadFromPrefs(prefs());
+    EXPECT_EQ(kTestContentVersion2, stored_version.content_version);
+  }
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest,
+       NewRulesetTwiceForTheSameVersion_SuccessAtLeastOnce) {
+  const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
+
+  StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+  RunUntilIdle();
+
+  StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+  RunUntilIdle();
+
+  ASSERT_LE(1u, mock_distributor()->published_rulesets().size());
+  ASSERT_GE(2u, mock_distributor()->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets().front(), dummy_ruleset));
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &mock_distributor()->published_rulesets().back(), dummy_ruleset));
+
+  MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+  service()->RegisterDistributor(base::WrapUnique(new_distributor));
+  ASSERT_EQ(1u, new_distributor->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(AssertValidRulesetFileWithContents(
+      &new_distributor->published_rulesets()[0], dummy_ruleset));
+}
+
+TEST_F(SubresourceFilteringRulesetServiceTest, RulesetIsReadonly) {
+  const std::vector<uint8_t> dummy_ruleset(AsVector(kDummyRuleset1));
+
+  service()->StoreAndPublishUpdatedRuleset(dummy_ruleset, kTestContentVersion1);
+  RunUntilIdle();
+
+  ASSERT_EQ(1u, mock_distributor()->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(
+      AssertReadonlyRulesetFile(&mock_distributor()->published_rulesets()[0]));
+
+  MockRulesetDistributor* new_distributor = new MockRulesetDistributor;
+  service()->RegisterDistributor(base::WrapUnique(new_distributor));
+  ASSERT_EQ(1u, new_distributor->published_rulesets().size());
+  ASSERT_NO_FATAL_FAILURE(
+      AssertReadonlyRulesetFile(&new_distributor->published_rulesets()[0]));
+}
+
+}  // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_constants.cc b/components/subresource_filter/core/browser/subresource_filter_constants.cc
new file mode 100644
index 0000000..664990e3
--- /dev/null
+++ b/components/subresource_filter/core/browser/subresource_filter_constants.cc
@@ -0,0 +1,15 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
+
+namespace subresource_filter {
+
+const base::FilePath::CharType kRulesetBaseDirectoryName[] =
+    FILE_PATH_LITERAL("Subresource Filtering Rules");
+
+const base::FilePath::CharType kRulesetDataFileName[] =
+    FILE_PATH_LITERAL("Ruleset Data");
+
+}  // namespace subresource_filter
diff --git a/components/subresource_filter/core/browser/subresource_filter_constants.h b/components/subresource_filter/core/browser/subresource_filter_constants.h
new file mode 100644
index 0000000..b06c400
--- /dev/null
+++ b/components/subresource_filter/core/browser/subresource_filter_constants.h
@@ -0,0 +1,21 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
+
+#include "base/files/file_path.h"
+
+namespace subresource_filter {
+
+// The name of the directory under the user data directory, where filtering
+// rules are stored.
+extern const base::FilePath::CharType kRulesetBaseDirectoryName[];
+
+// The name of the file that actually stores the ruleset contents.
+extern const base::FilePath::CharType kRulesetDataFileName[];
+
+}  // namespace subresource_filter
+
+#endif  // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_SUBRESOURCE_FILTER_CONSTANTS_H_
diff --git a/components/test_runner/test_preferences.cc b/components/test_runner/test_preferences.cc
index 318889f..e4fcd93 100644
--- a/components/test_runner/test_preferences.cc
+++ b/components/test_runner/test_preferences.cc
@@ -49,7 +49,6 @@
   disable_reading_from_canvas = false;
   strict_mixed_content_checking = false;
   strict_powerful_feature_restrictions = false;
-  spatial_navigation_enabled = false;
 }
 
 }  // namespace test_runner
diff --git a/components/test_runner/test_preferences.h b/components/test_runner/test_preferences.h
index 94fde32..cf06d50 100644
--- a/components/test_runner/test_preferences.h
+++ b/components/test_runner/test_preferences.h
@@ -43,7 +43,6 @@
     bool disable_reading_from_canvas;
     bool strict_mixed_content_checking;
     bool strict_powerful_feature_restrictions;
-    bool spatial_navigation_enabled;
 
     TestPreferences();
     void Reset();
diff --git a/components/test_runner/test_runner.cc b/components/test_runner/test_runner.cc
index 0639f8d6..2c09561 100644
--- a/components/test_runner/test_runner.cc
+++ b/components/test_runner/test_runner.cc
@@ -2321,8 +2321,6 @@
     prefs->should_respect_image_orientation = value->BooleanValue();
   } else if (key == "WebKitWebSecurityEnabled") {
     prefs->web_security_enabled = value->BooleanValue();
-  } else if (key == "WebKitSpatialNavigationEnabled") {
-    prefs->spatial_navigation_enabled = value->BooleanValue();
   } else {
     std::string message("Invalid name for preference: ");
     message.append(key);
diff --git a/components/toolbar/test_toolbar_model.cc b/components/toolbar/test_toolbar_model.cc
index e1f4cf5..6ad5b94 100644
--- a/components/toolbar/test_toolbar_model.cc
+++ b/components/toolbar/test_toolbar_model.cc
@@ -28,10 +28,6 @@
   return text_;
 }
 
-base::string16 TestToolbarModel::GetCorpusNameForMobile() const {
-  return base::string16();
-}
-
 GURL TestToolbarModel::GetURL() const {
   return url_;
 }
diff --git a/components/toolbar/test_toolbar_model.h b/components/toolbar/test_toolbar_model.h
index 0587453..5e5015c 100644
--- a/components/toolbar/test_toolbar_model.h
+++ b/components/toolbar/test_toolbar_model.h
@@ -25,7 +25,6 @@
   ~TestToolbarModel() override;
   base::string16 GetText() const override;
   base::string16 GetFormattedURL(size_t* prefix_end) const override;
-  base::string16 GetCorpusNameForMobile() const override;
   GURL GetURL() const override;
   bool WouldPerformSearchTermReplacement(bool ignore_editing) const override;
   security_state::SecurityStateModel::SecurityLevel GetSecurityLevel(
diff --git a/components/toolbar/toolbar_model.h b/components/toolbar/toolbar_model.h
index d0aee6b..afc86a9 100644
--- a/components/toolbar/toolbar_model.h
+++ b/components/toolbar/toolbar_model.h
@@ -45,13 +45,6 @@
   // portion of the resulting URL.
   virtual base::string16 GetFormattedURL(size_t* prefix_end) const = 0;
 
-  // Some search URLs bundle a special "corpus" param that we can extract and
-  // display next to users' search terms in cases where we'd show the search
-  // terms instead of the URL anyway.  For example, a Google image search might
-  // show the corpus "Images:" plus a search string.  This is only used on
-  // mobile.
-  virtual base::string16 GetCorpusNameForMobile() const = 0;
-
   // Returns the URL of the current navigation entry.
   virtual GURL GetURL() const = 0;
 
diff --git a/components/toolbar/toolbar_model_impl.cc b/components/toolbar/toolbar_model_impl.cc
index e8ae52e..f6c7410 100644
--- a/components/toolbar/toolbar_model_impl.cc
+++ b/components/toolbar/toolbar_model_impl.cc
@@ -8,7 +8,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "components/google/core/browser/google_util.h"
 #include "components/grit/components_scaled_resources.h"
 #include "components/prefs/pref_service.h"
 #include "components/security_state/security_state_model.h"
@@ -66,26 +65,6 @@
          gfx::kEllipsisUTF16;
 }
 
-base::string16 ToolbarModelImpl::GetCorpusNameForMobile() const {
-  if (!WouldPerformSearchTermReplacement(false))
-    return base::string16();
-  GURL url(GetURL());
-  // If there is a query in the url fragment look for the corpus name there,
-  // otherwise look for the corpus name in the query parameters.
-  const std::string& query_str(google_util::HasGoogleSearchQueryParam(
-      url.ref_piece()) ? url.ref() : url.query());
-  url::Component query(0, static_cast<int>(query_str.length())), key, value;
-  const char kChipKey[] = "sboxchip";
-  while (url::ExtractQueryKeyValue(query_str.c_str(), &query, &key, &value)) {
-    if (key.is_nonempty() && query_str.substr(key.begin, key.len) == kChipKey) {
-      return net::UnescapeAndDecodeUTF8URLComponent(
-          query_str.substr(value.begin, value.len),
-          net::UnescapeRule::NORMAL);
-    }
-  }
-  return base::string16();
-}
-
 GURL ToolbarModelImpl::GetURL() const {
   GURL url;
   return delegate_->GetURL(&url) ? url : GURL(url::kAboutBlankURL);
diff --git a/components/toolbar/toolbar_model_impl.h b/components/toolbar/toolbar_model_impl.h
index d50e82c..4b823f63 100644
--- a/components/toolbar/toolbar_model_impl.h
+++ b/components/toolbar/toolbar_model_impl.h
@@ -34,7 +34,6 @@
   // ToolbarModel:
   base::string16 GetText() const override;
   base::string16 GetFormattedURL(size_t* prefix_end) const override;
-  base::string16 GetCorpusNameForMobile() const override;
   GURL GetURL() const override;
   bool WouldPerformSearchTermReplacement(bool ignore_editing) const override;
   security_state::SecurityStateModel::SecurityLevel GetSecurityLevel(
diff --git a/components/url_formatter/OWNERS b/components/url_formatter/OWNERS
index 49e5b762..f180384 100644
--- a/components/url_formatter/OWNERS
+++ b/components/url_formatter/OWNERS
@@ -3,7 +3,7 @@
 # Backup reviewer
 brettw@chromium.org
 
-# Changes to FormatUrlForSecurityDisplay require a security review to avoid
-# introducing security bugs.
+# Changes to FormatUrlForSecurityDisplay and FormatOriginForSecurityDisplay
+# require a security review to avoid introducing security bugs.
 per-file elide_url.*=palmer@chromium.org
 per-file elide_url.*=felt@chromium.org
diff --git a/components/url_formatter/elide_url.h b/components/url_formatter/elide_url.h
index acdccbf..bb34f7c 100644
--- a/components/url_formatter/elide_url.h
+++ b/components/url_formatter/elide_url.h
@@ -84,6 +84,14 @@
 
 // This is a convenience function for formatting a url::Origin in a concise and
 // human-friendly way, to help users make security-related decisions.
+//
+// - Omits the port if it is 0 or the default for the scheme.
+//
+// Do not use this for origins which will be parsed or sent to other
+// applications.
+//
+// Generally, prefer SchemeDisplay::SHOW to omitting the scheme unless there is
+// plenty of indication as to whether the origin is secure elsewhere in the UX.
 base::string16 FormatOriginForSecurityDisplay(
     const url::Origin& origin,
     const SchemeDisplay scheme_display = SchemeDisplay::SHOW);
diff --git a/content/browser/DEPS b/content/browser/DEPS
index 0297668..d995fcd2 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -114,23 +114,3 @@
   # See https://sites.google.com/a/chromium.org/dev/developers/content-module
   # for more information.
 ]
-
-specific_include_rules = {
-  # See https://crbug.com/612337.
-  "(power_save_blocker_android\.cc"
-  "|power_save_blocker_android\.h"
-  "|power_save_blocker_chromeos\.cc"
-  "|power_save_blocker_impl\.cc"
-  "|power_save_blocker_impl\.h"
-  "|power_save_blocker_mac\.cc"
-  "|power_save_blocker_ozone\.cc"
-  "|power_save_blocker_win\.cc"
-  "|power_save_blocker_x11\.cc"
-  ")": [
-    "-content",
-
-    # These will move to //device/power_save_blocker.
-    "+content/browser/power_save_blocker_impl.h",
-    "+content/public/browser/power_save_blocker.h",
-  ],
-}
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index a4fbdcc..f5d9e58 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -68,6 +68,7 @@
       client_(client),
       ui_task_runner_(
           BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)),
+      process_id_(rwhva_->GetRenderWidgetHost()->GetProcess()->GetID()),
       routing_id_(rwhva_->GetRenderWidgetHost()->GetRoutingID()),
       sender_(rwhva_->GetRenderWidgetHost()),
       use_in_process_zero_copy_software_draw_(use_in_proc_software_draw),
@@ -76,11 +77,11 @@
       need_animate_scroll_(false),
       need_invalidate_count_(0u),
       did_activate_pending_tree_count_(0u) {
-  client_->DidInitializeCompositor(this);
+  client_->DidInitializeCompositor(this, process_id_, routing_id_);
 }
 
 SynchronousCompositorHost::~SynchronousCompositorHost() {
-  client_->DidDestroyCompositor(this);
+  client_->DidDestroyCompositor(this, process_id_, routing_id_);
 }
 
 bool SynchronousCompositorHost::OnMessageReceived(const IPC::Message& message) {
@@ -94,10 +95,6 @@
   return handled;
 }
 
-void SynchronousCompositorHost::DidBecomeCurrent() {
-  client_->DidBecomeCurrent(this);
-}
-
 SynchronousCompositor::Frame SynchronousCompositorHost::DemandDrawHw(
     const gfx::Size& surface_size,
     const gfx::Transform& transform,
diff --git a/content/browser/android/synchronous_compositor_host.h b/content/browser/android/synchronous_compositor_host.h
index 39f496f..b3c9a9d 100644
--- a/content/browser/android/synchronous_compositor_host.h
+++ b/content/browser/android/synchronous_compositor_host.h
@@ -68,7 +68,6 @@
   void DidOverscroll(const DidOverscrollParams& over_scroll_params);
   void DidSendBeginFrame();
   bool OnMessageReceived(const IPC::Message& message);
-  void DidBecomeCurrent();
 
  private:
   class ScopedSendZeroMemory;
@@ -89,6 +88,7 @@
   RenderWidgetHostViewAndroid* const rwhva_;
   SynchronousCompositorClient* const client_;
   const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+  const int process_id_;
   const int routing_id_;
   IPC::Sender* const sender_;
   const bool use_in_process_zero_copy_software_draw_;
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc
index d8e601c..0def4b5 100644
--- a/content/browser/child_process_security_policy_impl.cc
+++ b/content/browser/child_process_security_policy_impl.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/child_process_security_policy_impl.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/command_line.h"
@@ -628,6 +629,15 @@
   return HasPermissionsForFile(child_id, file, READ_FILE_GRANT);
 }
 
+bool ChildProcessSecurityPolicyImpl::CanReadAllFiles(
+    int child_id,
+    const std::vector<base::FilePath>& files) {
+  return std::all_of(files.begin(), files.end(),
+                     [this, child_id](const base::FilePath& file) {
+                       return CanReadFile(child_id, file);
+                     });
+}
+
 bool ChildProcessSecurityPolicyImpl::CanCreateReadWriteFile(
     int child_id,
     const base::FilePath& file) {
diff --git a/content/browser/child_process_security_policy_impl.h b/content/browser/child_process_security_policy_impl.h
index 2f2b810..271e69c 100644
--- a/content/browser/child_process_security_policy_impl.h
+++ b/content/browser/child_process_security_policy_impl.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
@@ -77,6 +78,9 @@
   void GrantSendMidiSysExMessage(int child_id) override;
   bool CanAccessDataForOrigin(int child_id, const GURL& url) override;
 
+  // Returns if |child_id| can read all of the |files|.
+  bool CanReadAllFiles(int child_id, const std::vector<base::FilePath>& files);
+
   // Pseudo schemes are treated differently than other schemes because they
   // cannot be requested like normal URLs.  There is no mechanism for revoking
   // pseudo schemes.
diff --git a/content/browser/compositor/browser_compositor_output_surface.cc b/content/browser/compositor/browser_compositor_output_surface.cc
index 3fa2f9e..b5fbbcf 100644
--- a/content/browser/compositor/browser_compositor_output_surface.cc
+++ b/content/browser/compositor/browser_compositor_output_surface.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "cc/base/switches.h"
 #include "cc/output/output_surface_client.h"
-#include "cc/scheduler/delay_based_time_source.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "components/display_compositor/compositor_overlay_candidate_validator.h"
 #include "content/browser/compositor/reflector_impl.h"
 #include "content/common/gpu/client/context_provider_command_buffer.h"
@@ -23,13 +23,12 @@
 BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
     scoped_refptr<cc::ContextProvider> context_provider,
     scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-    base::SingleThreadTaskRunner* task_runner,
+    cc::SyntheticBeginFrameSource* begin_frame_source,
     std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
         overlay_candidate_validator)
     : OutputSurface(std::move(context_provider), nullptr, nullptr),
       vsync_manager_(std::move(vsync_manager)),
-      synthetic_begin_frame_source_(new cc::DelayBasedBeginFrameSource(
-          base::MakeUnique<cc::DelayBasedTimeSource>(task_runner))),
+      synthetic_begin_frame_source_(begin_frame_source),
       reflector_(nullptr),
       use_begin_frame_scheduling_(
           base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -41,11 +40,10 @@
 BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
     std::unique_ptr<cc::SoftwareOutputDevice> software_device,
     const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-    base::SingleThreadTaskRunner* task_runner)
+    cc::SyntheticBeginFrameSource* begin_frame_source)
     : OutputSurface(nullptr, nullptr, std::move(software_device)),
       vsync_manager_(vsync_manager),
-      synthetic_begin_frame_source_(new cc::DelayBasedBeginFrameSource(
-          base::MakeUnique<cc::DelayBasedTimeSource>(task_runner))),
+      synthetic_begin_frame_source_(begin_frame_source),
       reflector_(nullptr),
       use_begin_frame_scheduling_(
           base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -56,11 +54,10 @@
 BrowserCompositorOutputSurface::BrowserCompositorOutputSurface(
     const scoped_refptr<cc::VulkanContextProvider>& vulkan_context_provider,
     const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-    base::SingleThreadTaskRunner* task_runner)
+    cc::SyntheticBeginFrameSource* begin_frame_source)
     : OutputSurface(std::move(vulkan_context_provider)),
       vsync_manager_(vsync_manager),
-      synthetic_begin_frame_source_(new cc::DelayBasedBeginFrameSource(
-          base::MakeUnique<cc::DelayBasedTimeSource>(task_runner))),
+      synthetic_begin_frame_source_(begin_frame_source),
       reflector_(nullptr) {
   Initialize();
 }
@@ -87,9 +84,6 @@
   if (!OutputSurface::BindToClient(client))
     return false;
 
-  // Pass begin frame source up to Display to use for DisplayScheduler.
-  client->SetBeginFrameSource(synthetic_begin_frame_source_.get());
-
   // Don't want vsync notifications until there is a client.
   if (!use_begin_frame_scheduling_)
     vsync_manager_->AddObserver(this);
diff --git a/content/browser/compositor/browser_compositor_output_surface.h b/content/browser/compositor/browser_compositor_output_surface.h
index e2dbb9b2..f0e8fd3 100644
--- a/content/browser/compositor/browser_compositor_output_surface.h
+++ b/content/browser/compositor/browser_compositor_output_surface.h
@@ -9,12 +9,12 @@
 #include "base/threading/non_thread_safe.h"
 #include "build/build_config.h"
 #include "cc/output/output_surface.h"
-#include "cc/scheduler/begin_frame_source.h"
 #include "content/common/content_export.h"
 #include "ui/compositor/compositor_vsync_manager.h"
 
 namespace cc {
 class SoftwareOutputDevice;
+class SyntheticBeginFrameSource;
 }
 
 namespace display_compositor {
@@ -74,16 +74,12 @@
   virtual void SetSurfaceSuspendedForRecycle(bool suspended) = 0;
 #endif
 
-  cc::SyntheticBeginFrameSource* begin_frame_source() {
-    return synthetic_begin_frame_source_.get();
-  }
-
  protected:
   // Constructor used by the accelerated implementation.
   BrowserCompositorOutputSurface(
       scoped_refptr<cc::ContextProvider> context,
       scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-      base::SingleThreadTaskRunner* task_runner,
+      cc::SyntheticBeginFrameSource* begin_frame_source,
       std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
           overlay_candidate_validator);
 
@@ -91,16 +87,16 @@
   BrowserCompositorOutputSurface(
       std::unique_ptr<cc::SoftwareOutputDevice> software_device,
       const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-      base::SingleThreadTaskRunner* task_runner);
+      cc::SyntheticBeginFrameSource* begin_frame_source);
 
   // Constructor used by the Vulkan implementation.
   BrowserCompositorOutputSurface(
       const scoped_refptr<cc::VulkanContextProvider>& vulkan_context_provider,
       const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-      base::SingleThreadTaskRunner* task_runner);
+      cc::SyntheticBeginFrameSource* begin_frame_source);
 
   scoped_refptr<ui::CompositorVSyncManager> vsync_manager_;
-  std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source_;
+  cc::SyntheticBeginFrameSource* synthetic_begin_frame_source_;
   ReflectorImpl* reflector_;
 
   // True when BeginFrame scheduling is enabled.
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
index ab2597ac..a17c34d 100644
--- a/content/browser/compositor/gpu_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/gpu_browser_compositor_output_surface.cc
@@ -22,20 +22,19 @@
 GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface(
     scoped_refptr<ContextProviderCommandBuffer> context,
     scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-    base::SingleThreadTaskRunner* task_runner,
+    cc::SyntheticBeginFrameSource* begin_frame_source,
     std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
         overlay_candidate_validator)
     : BrowserCompositorOutputSurface(std::move(context),
                                      std::move(vsync_manager),
-                                     task_runner,
+                                     begin_frame_source,
                                      std::move(overlay_candidate_validator)),
       swap_buffers_completion_callback_(base::Bind(
           &GpuBrowserCompositorOutputSurface::OnGpuSwapBuffersCompleted,
           base::Unretained(this))),
       update_vsync_parameters_callback_(base::Bind(
           &BrowserCompositorOutputSurface::OnUpdateVSyncParametersFromGpu,
-          base::Unretained(this))) {
-}
+          base::Unretained(this))) {}
 
 GpuBrowserCompositorOutputSurface::~GpuBrowserCompositorOutputSurface() {}
 
diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.h b/content/browser/compositor/gpu_browser_compositor_output_surface.h
index cc66681..0e468827 100644
--- a/content/browser/compositor/gpu_browser_compositor_output_surface.h
+++ b/content/browser/compositor/gpu_browser_compositor_output_surface.h
@@ -37,7 +37,7 @@
   GpuBrowserCompositorOutputSurface(
       scoped_refptr<ContextProviderCommandBuffer> context,
       scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-      base::SingleThreadTaskRunner* task_runner,
+      cc::SyntheticBeginFrameSource* begin_frame_source,
       std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
           overlay_candidate_validator);
 
diff --git a/content/browser/compositor/gpu_output_surface_mac.h b/content/browser/compositor/gpu_output_surface_mac.h
index f5a6547..0f7a734 100644
--- a/content/browser/compositor/gpu_output_surface_mac.h
+++ b/content/browser/compositor/gpu_output_surface_mac.h
@@ -16,7 +16,7 @@
       scoped_refptr<ContextProviderCommandBuffer> context,
       gpu::SurfaceHandle surface_handle,
       scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-      base::SingleThreadTaskRunner* task_runner,
+      cc::SyntheticBeginFrameSource* begin_frame_source,
       std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
           overlay_candidate_validator,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager);
diff --git a/content/browser/compositor/gpu_output_surface_mac.mm b/content/browser/compositor/gpu_output_surface_mac.mm
index 4f46585..04d14da9 100644
--- a/content/browser/compositor/gpu_output_surface_mac.mm
+++ b/content/browser/compositor/gpu_output_surface_mac.mm
@@ -49,7 +49,7 @@
     scoped_refptr<ContextProviderCommandBuffer> context,
     gpu::SurfaceHandle surface_handle,
     scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-    base::SingleThreadTaskRunner* task_runner,
+    cc::SyntheticBeginFrameSource* begin_frame_source,
     std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
         overlay_candidate_validator,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
@@ -57,7 +57,7 @@
           std::move(context),
           surface_handle,
           std::move(vsync_manager),
-          task_runner,
+          begin_frame_source,
           std::move(overlay_candidate_validator),
           GL_TEXTURE_RECTANGLE_ARB,
           GL_RGBA,
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc
index 6fdb92e..2c0e145 100644
--- a/content/browser/compositor/gpu_process_transport_factory.cc
+++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -20,10 +20,14 @@
 #include "cc/base/histograms.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/output_surface.h"
+#include "cc/output/texture_mailbox_deleter.h"
 #include "cc/output/vulkan_in_process_context_provider.h"
 #include "cc/raster/single_thread_task_graph_runner.h"
 #include "cc/raster/task_graph_runner.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/scheduler/delay_based_time_source.h"
 #include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface_display_output_surface.h"
 #include "cc/surfaces/surface_manager.h"
 #include "components/display_compositor/compositor_overlay_candidate_validator.h"
@@ -152,6 +156,7 @@
 struct GpuProcessTransportFactory::PerCompositorData {
   gpu::SurfaceHandle surface_handle = gpu::kNullSurfaceHandle;
   BrowserCompositorOutputSurface* display_output_surface = nullptr;
+  cc::SyntheticBeginFrameSource* begin_frame_source = nullptr;
   ReflectorImpl* reflector = nullptr;
   std::unique_ptr<cc::Display> display;
   bool output_is_secure = false;
@@ -279,6 +284,7 @@
     // TODO(danakj): We can destroy the |data->display| here when the compositor
     // destroys its OutputSurface before calling back here.
     data->display_output_surface = nullptr;
+    data->begin_frame_source = nullptr;
   }
 
 #if defined(OS_WIN)
@@ -420,6 +426,17 @@
     }
   }
 
+  std::unique_ptr<cc::SyntheticBeginFrameSource> begin_frame_source;
+  if (!compositor->GetRendererSettings().disable_display_vsync) {
+    begin_frame_source.reset(new cc::DelayBasedBeginFrameSource(
+        base::MakeUnique<cc::DelayBasedTimeSource>(
+            compositor->task_runner().get())));
+  } else {
+    begin_frame_source.reset(new cc::BackToBackBeginFrameSource(
+        base::MakeUnique<cc::DelayBasedTimeSource>(
+            compositor->task_runner().get())));
+  }
+
   std::unique_ptr<BrowserCompositorOutputSurface> display_output_surface;
 #if defined(ENABLE_VULKAN)
   std::unique_ptr<VulkanBrowserCompositorOutputSurface> vulkan_surface;
@@ -441,7 +458,7 @@
       display_output_surface =
           base::WrapUnique(new SoftwareBrowserCompositorOutputSurface(
               CreateSoftwareOutputDevice(compositor.get()),
-              compositor->vsync_manager(), compositor->task_runner().get()));
+              compositor->vsync_manager(), begin_frame_source.get()));
     } else {
       DCHECK(context_provider);
       const auto& capabilities = context_provider->ContextCapabilities();
@@ -449,21 +466,21 @@
         display_output_surface =
             base::WrapUnique(new OffscreenBrowserCompositorOutputSurface(
                 context_provider, compositor->vsync_manager(),
-                compositor->task_runner().get(),
+                begin_frame_source.get(),
                 std::unique_ptr<display_compositor::
                                     CompositorOverlayCandidateValidator>()));
       } else if (capabilities.surfaceless) {
 #if defined(OS_MACOSX)
         display_output_surface = base::WrapUnique(new GpuOutputSurfaceMac(
             context_provider, data->surface_handle, compositor->vsync_manager(),
-            compositor->task_runner().get(),
+            begin_frame_source.get(),
             CreateOverlayCandidateValidator(compositor->widget()),
             BrowserGpuMemoryBufferManager::current()));
 #else
         display_output_surface =
             base::WrapUnique(new GpuSurfacelessBrowserCompositorOutputSurface(
                 context_provider, data->surface_handle,
-                compositor->vsync_manager(), compositor->task_runner().get(),
+                compositor->vsync_manager(), begin_frame_source.get(),
                 CreateOverlayCandidateValidator(compositor->widget()),
                 GL_TEXTURE_2D, GL_RGB,
                 BrowserGpuMemoryBufferManager::current()));
@@ -478,12 +495,13 @@
         display_output_surface =
             base::WrapUnique(new GpuBrowserCompositorOutputSurface(
                 context_provider, compositor->vsync_manager(),
-                compositor->task_runner().get(), std::move(validator)));
+                begin_frame_source.get(), std::move(validator)));
       }
     }
   }
 
   data->display_output_surface = display_output_surface.get();
+  data->begin_frame_source = begin_frame_source.get();
   if (data->reflector)
     data->reflector->OnSourceSurfaceReady(data->display_output_surface);
 
@@ -492,13 +510,19 @@
       compositor->widget());
 #endif
 
+  std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
+      begin_frame_source.get(), compositor->task_runner().get(),
+      display_output_surface->capabilities().max_frames_pending));
+
   // The Display owns and uses the |display_output_surface| created above.
   data->display = base::MakeUnique<cc::Display>(
       surface_manager_.get(), HostSharedBitmapManager::current(),
       BrowserGpuMemoryBufferManager::current(),
       compositor->GetRendererSettings(),
       compositor->surface_id_allocator()->id_namespace(),
-      compositor->task_runner().get(), std::move(display_output_surface));
+      std::move(begin_frame_source), std::move(display_output_surface),
+      std::move(scheduler), base::MakeUnique<cc::TextureMailboxDeleter>(
+                                compositor->task_runner().get()));
 
   // The |delegated_output_surface| is given back to the compositor, it
   // delegates to the Display as its root surface. Importantly, it shares the
@@ -631,10 +655,8 @@
     return;
   PerCompositorData* data = it->second;
   DCHECK(data);
-  if (data->display_output_surface) {
-    data->display_output_surface->begin_frame_source()
-        ->SetAuthoritativeVSyncInterval(interval);
-  }
+  if (data->begin_frame_source)
+    data->begin_frame_source->SetAuthoritativeVSyncInterval(interval);
 }
 
 void GpuProcessTransportFactory::SetOutputIsSecure(ui::Compositor* compositor,
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
index 02a1c4e..ba54c59 100644
--- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.cc
@@ -23,7 +23,7 @@
         scoped_refptr<ContextProviderCommandBuffer> context,
         gpu::SurfaceHandle surface_handle,
         scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-        base::SingleThreadTaskRunner* task_runner,
+        cc::SyntheticBeginFrameSource* begin_frame_source,
         std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
             overlay_candidate_validator,
         unsigned int target,
@@ -31,7 +31,7 @@
         gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager)
     : GpuBrowserCompositorOutputSurface(std::move(context),
                                         std::move(vsync_manager),
-                                        task_runner,
+                                        begin_frame_source,
                                         std::move(overlay_candidate_validator)),
       internalformat_(internalformat),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager) {
diff --git a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
index ac28d08..c9dc80a 100644
--- a/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
+++ b/content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h
@@ -28,7 +28,7 @@
       scoped_refptr<ContextProviderCommandBuffer> context,
       gpu::SurfaceHandle surface_handle,
       scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-      base::SingleThreadTaskRunner* task_runner,
+      cc::SyntheticBeginFrameSource* begin_frame_source,
       std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
           overlay_candidate_validator,
       unsigned int target,
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
index 2e4fe4c7..10b13f08 100644
--- a/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.cc
@@ -34,12 +34,12 @@
     OffscreenBrowserCompositorOutputSurface(
         scoped_refptr<ContextProviderCommandBuffer> context,
         scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-        base::SingleThreadTaskRunner* task_runner,
+        cc::SyntheticBeginFrameSource* begin_frame_source,
         std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
             overlay_candidate_validator)
     : BrowserCompositorOutputSurface(std::move(context),
                                      std::move(vsync_manager),
-                                     task_runner,
+                                     begin_frame_source,
                                      std::move(overlay_candidate_validator)),
       fbo_(0),
       is_backbuffer_discarded_(false),
diff --git a/content/browser/compositor/offscreen_browser_compositor_output_surface.h b/content/browser/compositor/offscreen_browser_compositor_output_surface.h
index 3f753a86..d9d35e9 100644
--- a/content/browser/compositor/offscreen_browser_compositor_output_surface.h
+++ b/content/browser/compositor/offscreen_browser_compositor_output_surface.h
@@ -29,7 +29,7 @@
   OffscreenBrowserCompositorOutputSurface(
       scoped_refptr<ContextProviderCommandBuffer> context,
       scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-      base::SingleThreadTaskRunner* task_runner,
+      cc::SyntheticBeginFrameSource* begin_frame_source,
       std::unique_ptr<display_compositor::CompositorOverlayCandidateValidator>
           overlay_candidate_validator);
 
diff --git a/content/browser/compositor/reflector_impl_unittest.cc b/content/browser/compositor/reflector_impl_unittest.cc
index 69557e1..94ddb8f 100644
--- a/content/browser/compositor/reflector_impl_unittest.cc
+++ b/content/browser/compositor/reflector_impl_unittest.cc
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
 #include "build/build_config.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/scheduler/delay_based_time_source.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "cc/test/test_context_provider.h"
 #include "cc/test/test_web_graphics_context_3d.h"
@@ -74,10 +77,10 @@
  public:
   TestOutputSurface(scoped_refptr<cc::ContextProvider> context_provider,
                     scoped_refptr<ui::CompositorVSyncManager> vsync_manager,
-                    base::SingleThreadTaskRunner* task_runner)
+                    cc::SyntheticBeginFrameSource* begin_frame_source)
       : BrowserCompositorOutputSurface(std::move(context_provider),
                                        std::move(vsync_manager),
-                                       task_runner,
+                                       begin_frame_source,
                                        CreateTestValidatorOzone()) {
     surface_size_ = gfx::Size(256, 256);
     device_scale_factor_ = 1.f;
@@ -127,12 +130,15 @@
     message_loop_.reset(new base::MessageLoop());
     task_runner_ = message_loop_->task_runner();
     compositor_task_runner_ = new FakeTaskRunner();
+    begin_frame_source_.reset(new cc::DelayBasedBeginFrameSource(
+        base::MakeUnique<cc::DelayBasedTimeSource>(
+            compositor_task_runner_.get())));
     compositor_.reset(
         new ui::Compositor(context_factory, compositor_task_runner_.get()));
     compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
-    output_surface_ = std::unique_ptr<TestOutputSurface>(new TestOutputSurface(
+    output_surface_ = base::MakeUnique<TestOutputSurface>(
         cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create()),
-        compositor_->vsync_manager(), compositor_task_runner_.get()));
+        compositor_->vsync_manager(), begin_frame_source_.get());
     CHECK(output_surface_->BindToClient(&output_surface_client_));
 
     root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
@@ -166,6 +172,7 @@
 
  protected:
   scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+  std::unique_ptr<cc::SyntheticBeginFrameSource> begin_frame_source_;
   cc::FakeOutputSurfaceClient output_surface_client_;
   std::unique_ptr<base::MessageLoop> message_loop_;
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc
index 23a7f76..14e78eb5 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -8,7 +8,6 @@
 
 #include "base/location.h"
 #include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
@@ -24,10 +23,10 @@
 SoftwareBrowserCompositorOutputSurface::SoftwareBrowserCompositorOutputSurface(
     std::unique_ptr<cc::SoftwareOutputDevice> software_device,
     const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-    base::SingleThreadTaskRunner* task_runner)
+    cc::SyntheticBeginFrameSource* begin_frame_source)
     : BrowserCompositorOutputSurface(std::move(software_device),
                                      vsync_manager,
-                                     task_runner),
+                                     begin_frame_source),
       weak_factory_(this) {}
 
 SoftwareBrowserCompositorOutputSurface::
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.h b/content/browser/compositor/software_browser_compositor_output_surface.h
index 44a508de..cd9d40d 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface.h
+++ b/content/browser/compositor/software_browser_compositor_output_surface.h
@@ -27,7 +27,7 @@
   SoftwareBrowserCompositorOutputSurface(
       std::unique_ptr<cc::SoftwareOutputDevice> software_device,
       const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-      base::SingleThreadTaskRunner* task_runner);
+      cc::SyntheticBeginFrameSource* begin_frame_source);
 
   ~SoftwareBrowserCompositorOutputSurface() override;
 
diff --git a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
index d5b5276..a3aab5d 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
+++ b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc
@@ -7,8 +7,12 @@
 #include <utility>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/test/test_message_loop.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "cc/output/compositor_frame.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/scheduler/delay_based_time_source.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/compositor/compositor.h"
@@ -60,8 +64,10 @@
 
 class SoftwareBrowserCompositorOutputSurfaceTest : public testing::Test {
  public:
-  SoftwareBrowserCompositorOutputSurfaceTest();
-  ~SoftwareBrowserCompositorOutputSurfaceTest() override;
+  SoftwareBrowserCompositorOutputSurfaceTest()
+      : begin_frame_source_(base::MakeUnique<cc::DelayBasedTimeSource>(
+            message_loop_.task_runner().get())) {}
+  ~SoftwareBrowserCompositorOutputSurfaceTest() override = default;
 
   void SetUp() override;
   void TearDown() override;
@@ -72,29 +78,23 @@
  protected:
   std::unique_ptr<content::BrowserCompositorOutputSurface> output_surface_;
 
-  std::unique_ptr<base::MessageLoop> message_loop_;
+  // TODO(crbug.com/616973): We shouldn't be using ThreadTaskRunnerHandle::Get()
+  // inside the OutputSurface, so we shouldn't need a MessageLoop. The
+  // OutputSurface should be using the TaskRunner given to the compositor.
+  base::TestMessageLoop message_loop_;
+  cc::DelayBasedBeginFrameSource begin_frame_source_;
   std::unique_ptr<ui::Compositor> compositor_;
 
   DISALLOW_COPY_AND_ASSIGN(SoftwareBrowserCompositorOutputSurfaceTest);
 };
 
-SoftwareBrowserCompositorOutputSurfaceTest::
-    SoftwareBrowserCompositorOutputSurfaceTest() {
-  // |message_loop_| is not used, but the main thread still has to exist for the
-  // compositor to use.
-  message_loop_.reset(new base::MessageLoopForUI);
-}
-
-SoftwareBrowserCompositorOutputSurfaceTest::
-    ~SoftwareBrowserCompositorOutputSurfaceTest() {}
-
 void SoftwareBrowserCompositorOutputSurfaceTest::SetUp() {
   bool enable_pixel_output = false;
   ui::ContextFactory* context_factory =
       ui::InitializeContextFactoryForTests(enable_pixel_output);
 
   compositor_.reset(
-      new ui::Compositor(context_factory, base::ThreadTaskRunnerHandle::Get()));
+      new ui::Compositor(context_factory, message_loop_.task_runner().get()));
   compositor_->SetAcceleratedWidget(gfx::kNullAcceleratedWidget);
 }
 
@@ -107,10 +107,8 @@
 std::unique_ptr<content::BrowserCompositorOutputSurface>
 SoftwareBrowserCompositorOutputSurfaceTest::CreateSurface(
     std::unique_ptr<cc::SoftwareOutputDevice> device) {
-  return std::unique_ptr<content::BrowserCompositorOutputSurface>(
-      new content::SoftwareBrowserCompositorOutputSurface(
-          std::move(device), compositor_->vsync_manager(),
-          message_loop_->task_runner().get()));
+  return base::MakeUnique<content::SoftwareBrowserCompositorOutputSurface>(
+      std::move(device), compositor_->vsync_manager(), &begin_frame_source_);
 }
 
 TEST_F(SoftwareBrowserCompositorOutputSurfaceTest, NoVSyncProvider) {
diff --git a/content/browser/compositor/vulkan_browser_compositor_output_surface.cc b/content/browser/compositor/vulkan_browser_compositor_output_surface.cc
index d933aad..de0edfdf 100644
--- a/content/browser/compositor/vulkan_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/vulkan_browser_compositor_output_surface.cc
@@ -13,8 +13,10 @@
 VulkanBrowserCompositorOutputSurface::VulkanBrowserCompositorOutputSurface(
     const scoped_refptr<cc::VulkanContextProvider>& context,
     const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-    base::SingleThreadTaskRunner* task_runner)
-    : BrowserCompositorOutputSurface(context, vsync_manager, task_runner) {}
+    cc::SyntheticBeginFrameSource* begin_frame_source)
+    : BrowserCompositorOutputSurface(context,
+                                     vsync_manager,
+                                     begin_frame_source) {}
 
 VulkanBrowserCompositorOutputSurface::~VulkanBrowserCompositorOutputSurface() {
   Destroy();
diff --git a/content/browser/compositor/vulkan_browser_compositor_output_surface.h b/content/browser/compositor/vulkan_browser_compositor_output_surface.h
index 8aaf97a..ed53ac0b 100644
--- a/content/browser/compositor/vulkan_browser_compositor_output_surface.h
+++ b/content/browser/compositor/vulkan_browser_compositor_output_surface.h
@@ -23,7 +23,7 @@
   VulkanBrowserCompositorOutputSurface(
       const scoped_refptr<cc::VulkanContextProvider>& context,
       const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager,
-      base::SingleThreadTaskRunner* task_runner);
+      cc::SyntheticBeginFrameSource* begin_frame_source);
 
   ~VulkanBrowserCompositorOutputSurface() override;
 
diff --git a/content/browser/cross_site_transfer_browsertest.cc b/content/browser/cross_site_transfer_browsertest.cc
index 986cd23..38327b7 100644
--- a/content/browser/cross_site_transfer_browsertest.cc
+++ b/content/browser/cross_site_transfer_browsertest.cc
@@ -2,11 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
+
 #include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/strings/stringprintf.h"
+#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/render_process_host.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_throttle.h"
 #include "content/public/browser/web_contents.h"
@@ -17,11 +24,13 @@
 #include "content/shell/browser/shell.h"
 #include "content/shell/browser/shell_content_browser_client.h"
 #include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
+#include "content/test/content_browser_test_utils_internal.h"
 #include "net/base/escape.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_status.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -418,4 +427,71 @@
   shell()->web_contents()->SetDelegate(old_delegate);
 }
 
+// Test that verifies that a cross-process transfer retains ability to read
+// files encapsulated by HTTP POST body that is forwarded to the new renderer.
+// Invalid handling of this scenario has been suspected as the cause of at least
+// some of the renderer kills tracked in https://crbug.com/613260.
+IN_PROC_BROWSER_TEST_F(CrossSiteTransferTest, PostWithFileData) {
+  // Navigate to the page with form that posts via 307 redirection to
+  // |redirect_target_url| (cross-site from |form_url|).  Using 307 (rather than
+  // 302) redirection is important to preserve the HTTP method and POST body.
+  GURL form_url(embedded_test_server()->GetURL(
+      "a.com", "/form_that_posts_cross_site.html"));
+  GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
+  EXPECT_TRUE(NavigateToURL(shell(), form_url));
+
+  // Prepare a file to upload.
+  base::ScopedTempDir temp_dir;
+  base::FilePath file_path;
+  std::string file_content("test-file-content");
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &file_path));
+  ASSERT_LT(
+      0, base::WriteFile(file_path, file_content.data(), file_content.size()));
+
+  // Fill out the form to refer to the test file.
+  std::unique_ptr<FileChooserDelegate> delegate(
+      new FileChooserDelegate(file_path));
+  shell()->web_contents()->SetDelegate(delegate.get());
+  EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
+                            "document.getElementById('file').click();"));
+  EXPECT_TRUE(delegate->file_chosen());
+
+  // Remember the old process id for a sanity check below.
+  int old_process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
+
+  // Submit the form.
+  TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
+  EXPECT_TRUE(
+      ExecuteScript(shell(), "document.getElementById('file-form').submit();"));
+  form_post_observer.Wait();
+
+  // Verify that we arrived at the expected, redirected location.
+  EXPECT_EQ(redirect_target_url,
+            shell()->web_contents()->GetLastCommittedURL());
+
+  // Verify that the test really verifies access of a *new* renderer process.
+  int new_process_id = shell()->web_contents()->GetRenderProcessHost()->GetID();
+  ASSERT_NE(new_process_id, old_process_id);
+
+  // MAIN VERIFICATION: Check if the new renderer process is able to read the
+  // file.
+  EXPECT_TRUE(ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(
+      new_process_id, file_path));
+
+  // Verify that POST body got preserved by 307 redirect.  This expectation
+  // comes from: https://tools.ietf.org/html/rfc7231#section-6.4.7
+  std::string actual_page_body;
+  EXPECT_TRUE(ExecuteScriptAndExtractString(
+      shell()->web_contents(),
+      "window.domAutomationController.send("
+      "document.getElementsByTagName('pre')[0].innerText);",
+      &actual_page_body));
+  EXPECT_THAT(actual_page_body, ::testing::HasSubstr(file_content));
+  EXPECT_THAT(actual_page_body,
+              ::testing::HasSubstr(file_path.BaseName().AsUTF8Unsafe()));
+  EXPECT_THAT(actual_page_body,
+              ::testing::HasSubstr("form-data; name=\"file\""));
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 47e3fb4..0f019c7 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -40,9 +40,8 @@
 #include "content/public/common/browser_side_navigation_policy.h"
 
 #if defined(OS_ANDROID)
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/render_widget_host_view.h"
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #endif
 
 namespace content {
@@ -501,11 +500,11 @@
 
   frame_trace_recorder_.reset(new DevToolsFrameTraceRecorder());
 #if defined(OS_ANDROID)
-  power_save_blocker_.reset(static_cast<device::PowerSaveBlockerImpl*>(
-      CreatePowerSaveBlocker(
-          device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-          device::PowerSaveBlocker::kReasonOther, "DevTools")
-          .release()));
+  power_save_blocker_.reset(new device::PowerSaveBlocker(
+      device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      device::PowerSaveBlocker::kReasonOther, "DevTools",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
   if (web_contents()->GetNativeView()) {
     view_weak_factory_.reset(new base::WeakPtrFactory<ui::ViewAndroid>(
         web_contents()->GetNativeView()));
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index 249d9d2d..a2c6ef8 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -25,7 +25,7 @@
 
 #if defined(OS_ANDROID)
 namespace device {
-class PowerSaveBlockerImpl;
+class PowerSaveBlocker;
 }  // namespace device
 #endif
 
@@ -173,7 +173,7 @@
   std::unique_ptr<devtools::emulation::EmulationHandler> emulation_handler_;
   std::unique_ptr<DevToolsFrameTraceRecorder> frame_trace_recorder_;
 #if defined(OS_ANDROID)
-  std::unique_ptr<device::PowerSaveBlockerImpl> power_save_blocker_;
+  std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
   std::unique_ptr<base::WeakPtrFactory<ui::ViewAndroid>> view_weak_factory_;
 #endif
   std::unique_ptr<DevToolsProtocolHandler> protocol_handler_;
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 06393fab..352f7a2 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -30,7 +30,6 @@
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/download/download_resource_handler.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/download_danger_type.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
@@ -48,6 +47,7 @@
 #include "content/shell/browser/shell_browser_context.h"
 #include "content/shell/browser/shell_download_manager_delegate.h"
 #include "content/shell/browser/shell_network_delegate.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -255,9 +255,11 @@
     std::unique_ptr<ByteStreamReader> stream,
     const net::BoundNetLog& bound_net_log,
     base::WeakPtr<DownloadDestinationObserver> observer) {
-  std::unique_ptr<device::PowerSaveBlocker> psb(CreatePowerSaveBlocker(
+  std::unique_ptr<device::PowerSaveBlocker> psb(new device::PowerSaveBlocker(
       device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      device::PowerSaveBlocker::kReasonOther, "Download in progress"));
+      device::PowerSaveBlocker::kReasonOther, "Download in progress",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
   return new DownloadFileWithDelay(std::move(save_info),
                                    default_download_directory,
                                    std::move(stream),
@@ -352,9 +354,11 @@
       std::unique_ptr<ByteStreamReader> stream,
       const net::BoundNetLog& bound_net_log,
       base::WeakPtr<DownloadDestinationObserver> observer) override {
-    std::unique_ptr<device::PowerSaveBlocker> psb(CreatePowerSaveBlocker(
+    std::unique_ptr<device::PowerSaveBlocker> psb(new device::PowerSaveBlocker(
         device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-        device::PowerSaveBlocker::kReasonOther, "Download in progress"));
+        device::PowerSaveBlocker::kReasonOther, "Download in progress",
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
     return new CountingDownloadFile(std::move(save_info),
                                     default_downloads_directory,
                                     std::move(stream),
diff --git a/content/browser/download/download_request_core.cc b/content/browser/download/download_request_core.cc
index 27965757..67029c4 100644
--- a/content/browser/download/download_request_core.cc
+++ b/content/browser/download/download_request_core.cc
@@ -24,7 +24,6 @@
 #include "content/browser/download/download_request_handle.h"
 #include "content/browser/download/download_stats.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/download_interrupt_reasons.h"
 #include "content/public/browser/download_item.h"
@@ -32,6 +31,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/web_contents.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "net/base/elements_upload_data_stream.h"
 #include "net/base/io_buffer.h"
 #include "net/base/load_flags.h"
@@ -204,9 +204,11 @@
   DCHECK(request_);
   DCHECK(delegate_);
   RecordDownloadCount(UNTHROTTLED_COUNT);
-  power_save_blocker_ = CreatePowerSaveBlocker(
+  power_save_blocker_.reset(new device::PowerSaveBlocker(
       device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      device::PowerSaveBlocker::kReasonOther, "Download in progress");
+      device::PowerSaveBlocker::kReasonOther, "Download in progress",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
   DownloadRequestData* request_data = DownloadRequestData::Get(request_);
   if (request_data) {
     save_info_ = request_data->TakeSaveInfo();
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index aa02e59a..ffa1cd1 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -21,7 +21,6 @@
 #include "content/browser/accessibility/browser_accessibility_state_impl.h"
 #include "content/browser/bluetooth/web_bluetooth_service_impl.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
 #include "content/browser/download/mhtml_generation_manager.h"
 #include "content/browser/frame_host/cross_process_frame_connector.h"
@@ -161,6 +160,17 @@
   bool disabled_;
 };
 
+void GrantFileAccess(int child_id,
+                     const std::vector<base::FilePath>& file_paths) {
+  ChildProcessSecurityPolicyImpl* policy =
+      ChildProcessSecurityPolicyImpl::GetInstance();
+
+  for (const auto& file : file_paths) {
+    if (!policy->CanReadFile(child_id, file))
+      policy->GrantReadFile(child_id, file);
+  }
+}
+
 }  // namespace
 
 // static
@@ -1085,8 +1095,7 @@
 
   // Without this check, the renderer can trick the browser into using
   // filenames it can't access in a future session restore.
-  if (!render_view_host_->CanAccessFilesOfPageState(
-          validated_params.page_state)) {
+  if (!CanAccessFilesOfPageState(validated_params.page_state)) {
     bad_message::ReceivedBadMessage(
         GetProcess(), bad_message::RFH_CAN_ACCESS_FILES_OF_PAGE_STATE);
     return;
@@ -1177,8 +1186,7 @@
 
   // Without this check, the renderer can trick the browser into using
   // filenames it can't access in a future session restore.
-  // TODO(creis): Move CanAccessFilesOfPageState to RenderFrameHostImpl.
-  if (!render_view_host_->CanAccessFilesOfPageState(state)) {
+  if (!CanAccessFilesOfPageState(state)) {
     bad_message::ReceivedBadMessage(
         GetProcess(), bad_message::RFH_CAN_ACCESS_FILES_OF_PAGE_STATE);
     return;
@@ -2757,6 +2765,20 @@
           ->last_committed_url().GetOrigin());
 }
 
+bool RenderFrameHostImpl::CanAccessFilesOfPageState(const PageState& state) {
+  return ChildProcessSecurityPolicyImpl::GetInstance()->CanReadAllFiles(
+      GetProcess()->GetID(), state.GetReferencedFiles());
+}
+
+void RenderFrameHostImpl::GrantFileAccessFromPageState(const PageState& state) {
+  GrantFileAccess(GetProcess()->GetID(), state.GetReferencedFiles());
+}
+
+void RenderFrameHostImpl::GrantFileAccessFromResourceRequestBody(
+    const ResourceRequestBodyImpl& body) {
+  GrantFileAccess(GetProcess()->GetID(), body.GetReferencedFiles());
+}
+
 void RenderFrameHostImpl::UpdatePermissionsForNavigation(
     const CommonNavigationParams& common_params,
     const RequestNavigationParams& request_params) {
@@ -2776,11 +2798,20 @@
 
   // We may be returning to an existing NavigationEntry that had been granted
   // file access.  If this is a different process, we will need to grant the
-  // access again.  The files listed in the page state are validated when they
-  // are received from the renderer to prevent abuse.
-  if (request_params.page_state.IsValid()) {
-    render_view_host_->GrantFileAccessFromPageState(request_params.page_state);
-  }
+  // access again.  Abuse is prevented, because the files listed in the page
+  // state are validated earlier, when they are received from the renderer (in
+  // RenderFrameHostImpl::CanAccessFilesOfPageState).
+  if (request_params.page_state.IsValid())
+    GrantFileAccessFromPageState(request_params.page_state);
+
+  // We may be here after transferring navigation to a different renderer
+  // process.  In this case, we need to ensure that the new renderer retains
+  // ability to access files that the old renderer could access.  Abuse is
+  // prevented, because the files listed in ResourceRequestBody are validated
+  // earlier, when they are recieved from the renderer (in ShouldServiceRequest
+  // called from ResourceDispatcherHostImpl::BeginRequest).
+  if (common_params.post_data)
+    GrantFileAccessFromResourceRequestBody(*common_params.post_data);
 }
 
 bool RenderFrameHostImpl::CanExecuteJavaScript() {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index ff79b653..990d305 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -732,6 +732,23 @@
   // Informs the content client that geolocation permissions were used.
   void DidUseGeolocationPermission();
 
+  // Returns whether the current RenderProcessHost has read access to all the
+  // files reported in |state|.
+  bool CanAccessFilesOfPageState(const PageState& state);
+
+  // Grants the current RenderProcessHost read access to any file listed in
+  // |validated_state|.  It is important that the PageState has been validated
+  // upon receipt from the renderer process to prevent it from forging access to
+  // files without the user's consent.
+  void GrantFileAccessFromPageState(const PageState& validated_state);
+
+  // Grants the current RenderProcessHost read access to any file listed in
+  // |body|.  It is important that the ResourceRequestBody has been validated
+  // upon receipt from the renderer process to prevent it from forging access to
+  // files without the user's consent.
+  void GrantFileAccessFromResourceRequestBody(
+      const ResourceRequestBodyImpl& body);
+
   void UpdatePermissionsForNavigation(
       const CommonNavigationParams& common_params,
       const RequestNavigationParams& request_params);
diff --git a/content/browser/frame_host/render_frame_host_manager_browsertest.cc b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
index 10fa48b..6100a74 100644
--- a/content/browser/frame_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/frame_host/render_frame_host_manager_browsertest.cc
@@ -5,6 +5,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
 #include <set>
 
 #include "base/command_line.h"
@@ -38,8 +39,6 @@
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/content_switches.h"
-#include "content/public/common/file_chooser_file_info.h"
-#include "content/public/common/file_chooser_params.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
@@ -1930,30 +1929,6 @@
   EXPECT_FALSE(handler->IsJavascriptAllowed());
 }
 
-class FileChooserDelegate : public WebContentsDelegate {
- public:
-  FileChooserDelegate(const base::FilePath& file)
-      : file_(file), file_chosen_(false) {}
-
-  void RunFileChooser(RenderFrameHost* render_frame_host,
-                      const FileChooserParams& params) override {
-    // Send the selected file to the renderer process.
-    FileChooserFileInfo file_info;
-    file_info.file_path = file_;
-    std::vector<FileChooserFileInfo> files;
-    files.push_back(file_info);
-    render_frame_host->FilesSelectedInChooser(files, FileChooserParams::Open);
-
-    file_chosen_ = true;
-  }
-
-  bool file_chosen() { return file_chosen_; }
-
- private:
-  base::FilePath file_;
-  bool file_chosen_;
-};
-
 // Test for http://crbug.com/262948.
 IN_PROC_BROWSER_TEST_F(RenderFrameHostManagerTest,
                        RestoreFileAccessForHistoryNavigation) {
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index 98bd0fd..bbffcca 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -122,6 +122,9 @@
 
   void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
                            int* renderer_id) override {
+    // base::kNullProcessHandle indicates that the channel will be used by the
+    // browser itself. Make sure we never output that value here.
+    CHECK_NE(base::kNullProcessHandle, filter_->PeerHandle());
     *renderer_handle = filter_->PeerHandle();
     *renderer_id = filter_->render_process_id_;
   }
@@ -155,6 +158,9 @@
 
   void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
                            int* renderer_id) override {
+    // base::kNullProcessHandle indicates that the channel will be used by the
+    // browser itself. Make sure we never output that value here.
+    CHECK_NE(base::kNullProcessHandle, filter()->PeerHandle());
     *renderer_handle = filter()->PeerHandle();
     *renderer_id = filter()->render_process_id_;
   }
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 93e57a7..67113b67 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -1008,8 +1008,7 @@
   BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line);
 
 #if defined(OS_WIN)
-  if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument())
-    cmd_line->AppendArg(switches::kPrefetchArgumentGpu);
+  cmd_line->AppendArg(switches::kPrefetchArgumentGpu);
 #endif  // defined(OS_WIN)
 
   if (kind_ == GPU_PROCESS_KIND_UNSANDBOXED)
diff --git a/content/browser/loader/DEPS b/content/browser/loader/DEPS
index 24dd2400..3d395e59 100644
--- a/content/browser/loader/DEPS
+++ b/content/browser/loader/DEPS
@@ -95,7 +95,6 @@
 
     # TODO: these all have to be removed.
     "+content/public/browser/browser_thread.h",
-    "+content/public/browser/power_save_blocker_factory.h",
   ],
   "resource_dispatcher_host_impl\.(cc|h)": [
     "-content",
@@ -113,6 +112,7 @@
     "+content/browser/loader/sync_resource_handler.h",
     "+content/browser/loader/throttling_resource_handler.h",
     "+content/common/resource_request_body_impl.h",
+    "+content/common/ssl_status_serialization.h",
     "+content/public/browser/global_request_id.h",
     "+content/public/browser/resource_dispatcher_host.h",
     "+content/public/browser/resource_dispatcher_host_delegate.h",
@@ -153,7 +153,6 @@
     "+content/common/navigation_params.h",
     "+content/common/net/url_request_service_worker_data.h",
     "+content/common/site_isolation_policy.h",
-    "+content/common/ssl_status_serialization.h",
     "+content/public/browser/browser_thread.h",
     "+content/public/browser/content_browser_client.h",
     "+content/public/browser/notification_types.h",
@@ -187,7 +186,10 @@
     "+content/browser/loader/resource_loader.h",
     "+content/browser/loader/resource_loader_delegate.h",
     "+content/browser/loader/resource_request_info_impl.h",
+    "+content/browser/ssl/ssl_client_auth_handler.h",
+    "+content/browser/ssl/ssl_error_handler.h",
     "+content/common/content_export.h",
+    "+content/common/ssl_status_serialization.h",
     "+content/public/browser/resource_controller.h",
     "+content/public/browser/resource_dispatcher_host_login_delegate.h",
     "+content/public/common/resource_response.h",
@@ -199,11 +201,8 @@
     "+content/browser/loader/detachable_resource_handler.h",
     "+content/browser/service_worker/service_worker_request_handler.h",
     "+content/browser/service_worker/service_worker_response_info.h",
-    "+content/browser/ssl/ssl_client_auth_handler.h",
-    "+content/browser/ssl/ssl_error_handler.h",
     "+content/browser/ssl/ssl_manager.h",
     "+content/browser/ssl/ssl_policy.h",
-    "+content/common/ssl_status_serialization.h",
     "+content/public/browser/cert_store.h",
     "+content/public/browser/resource_context.h",
     "+content/public/browser/signed_certificate_timestamp_store.h",
diff --git a/content/browser/loader/power_save_block_resource_throttle.cc b/content/browser/loader/power_save_block_resource_throttle.cc
index 47ce12b..97ceac0 100644
--- a/content/browser/loader/power_save_block_resource_throttle.cc
+++ b/content/browser/loader/power_save_block_resource_throttle.cc
@@ -41,11 +41,11 @@
 }
 
 void PowerSaveBlockResourceThrottle::ActivatePowerSaveBlocker() {
-  power_save_blocker_ = device::PowerSaveBlocker::CreateWithTaskRunners(
+  power_save_blocker_.reset(new device::PowerSaveBlocker(
       device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
       device::PowerSaveBlocker::kReasonOther, "Uploading data to " + host_,
       BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
-      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
 }
 
 }  // namespace content
diff --git a/content/browser/media/capture/aura_window_capture_machine.cc b/content/browser/media/capture/aura_window_capture_machine.cc
index 86f9524..426bc89 100644
--- a/content/browser/media/capture/aura_window_capture_machine.cc
+++ b/content/browser/media/capture/aura_window_capture_machine.cc
@@ -14,8 +14,8 @@
 #include "components/display_compositor/gl_helper.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "media/base/video_capture_types.h"
 #include "media/base/video_util.h"
 #include "media/capture/content/thread_safe_capture_oracle.h"
@@ -85,12 +85,11 @@
     return false;
   compositor->AddAnimationObserver(this);
 
-  power_save_blocker_.reset(
-      CreatePowerSaveBlocker(
-          device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-          device::PowerSaveBlocker::kReasonOther,
-          "DesktopCaptureDevice is running")
-          .release());
+  power_save_blocker_.reset(new device::PowerSaveBlocker(
+      device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      device::PowerSaveBlocker::kReasonOther, "DesktopCaptureDevice is running",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
 
   return true;
 }
diff --git a/content/browser/media/capture/desktop_capture_device.cc b/content/browser/media/capture/desktop_capture_device.cc
index d468f01..f5a73646 100644
--- a/content/browser/media/capture/desktop_capture_device.cc
+++ b/content/browser/media/capture/desktop_capture_device.cc
@@ -20,9 +20,9 @@
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_media_id.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "media/base/video_util.h"
 #include "media/capture/content/capture_resolution_chooser.h"
 #include "third_party/libyuv/include/libyuv/scale_argb.h"
@@ -75,9 +75,10 @@
   void SetNotificationWindowId(gfx::NativeViewId window_id);
 
  private:
-
-  // webrtc::DesktopCapturer::Callback interface
-  void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
+  // webrtc::DesktopCapturer::Callback interface.
+  void OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) override;
 
   // Method that is scheduled on |task_runner_| to be called on regular interval
   // to capture a frame.
@@ -172,12 +173,11 @@
       params.requested_format.frame_size,
       params.resolution_change_policy));
 
-  power_save_blocker_.reset(
-      CreatePowerSaveBlocker(
-          device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-          device::PowerSaveBlocker::kReasonOther,
-          "DesktopCaptureDevice is running")
-          .release());
+  power_save_blocker_.reset(new device::PowerSaveBlocker(
+      device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+      device::PowerSaveBlocker::kReasonOther, "DesktopCaptureDevice is running",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
 
   desktop_capturer_->Start(this);
 
@@ -191,28 +191,32 @@
   desktop_capturer_->SetExcludedWindow(window_id);
 }
 
-void DesktopCaptureDevice::Core::OnCaptureCompleted(
-    webrtc::DesktopFrame* frame) {
+void DesktopCaptureDevice::Core::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK(capture_in_progress_);
+  capture_in_progress_ = false;
+
+  bool success = result == webrtc::DesktopCapturer::Result::SUCCESS;
 
   if (!first_capture_returned_) {
     first_capture_returned_ = true;
     if (capturer_type_ == DesktopMediaID::TYPE_SCREEN) {
-      IncrementDesktopCaptureCounter(frame ? FIRST_SCREEN_CAPTURE_SUCCEEDED
-                                           : FIRST_SCREEN_CAPTURE_FAILED);
+      IncrementDesktopCaptureCounter(success ? FIRST_SCREEN_CAPTURE_SUCCEEDED
+                                             : FIRST_SCREEN_CAPTURE_FAILED);
     } else {
-      IncrementDesktopCaptureCounter(frame ? FIRST_WINDOW_CAPTURE_SUCCEEDED
-                                           : FIRST_WINDOW_CAPTURE_FAILED);
+      IncrementDesktopCaptureCounter(success ? FIRST_WINDOW_CAPTURE_SUCCEEDED
+                                             : FIRST_WINDOW_CAPTURE_FAILED);
     }
   }
 
-  capture_in_progress_ = false;
-
-  if (!frame) {
-    client_->OnError(FROM_HERE, "Failed to capture a frame.");
+  if (!success) {
+    if (result == webrtc::DesktopCapturer::Result::ERROR_PERMANENT)
+      client_->OnError(FROM_HERE, "The desktop capturer has failed.");
     return;
   }
+  DCHECK(frame);
 
   if (!client_)
     return;
@@ -228,8 +232,6 @@
     UMA_HISTOGRAM_TIMES(kUmaWindowCaptureTime, capture_time);
   }
 
-  std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame);
-
   // If the frame size has changed, drop the output frame (if any), and
   // determine the new output size.
   if (!previous_frame_size_.equals(frame->size())) {
@@ -246,26 +248,22 @@
   if (output_size.is_empty())
     return;
 
-  // On OSX We receive a 1x1 frame when the shared window is minimized. It
-  // cannot be subsampled to I420 and will be dropped downstream. So we replace
-  // it with a black frame to avoid the video appearing frozen at the last
-  // frame.
-  if (frame->size().width() == 1 || frame->size().height() == 1) {
-    if (!black_frame_) {
-      black_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
-      memset(black_frame_->data(),
-             0,
-             black_frame_->stride() * black_frame_->size().height());
-    }
-    owned_frame.reset();
-    frame = black_frame_.get();
-  }
-
   size_t output_bytes = output_size.width() * output_size.height() *
       webrtc::DesktopFrame::kBytesPerPixel;
-  const uint8_t* output_data = NULL;
+  const uint8_t* output_data = nullptr;
 
-  if (!frame->size().equals(output_size)) {
+  if (frame->size().equals(webrtc::DesktopSize(1, 1))) {
+    // On OSX We receive a 1x1 frame when the shared window is minimized. It
+    // cannot be subsampled to I420 and will be dropped downstream. So we
+    // replace it with a black frame to avoid the video appearing frozen at the
+    // last frame.
+    if (!black_frame_ || !black_frame_->size().equals(output_size)) {
+      black_frame_.reset(new webrtc::BasicDesktopFrame(output_size));
+      memset(black_frame_->data(), 0,
+             black_frame_->stride() * black_frame_->size().height());
+    }
+    output_data = black_frame_->data();
+  } else if (!frame->size().equals(output_size)) {
     // Down-scale and/or letterbox to the target format if the frame does not
     // match the output size.
 
@@ -282,16 +280,14 @@
     // using ARGBScaleClip().
     const webrtc::DesktopRect output_rect =
         ComputeLetterboxRect(output_size, frame->size());
-    uint8_t* output_rect_data = output_frame_->data() +
-        output_frame_->stride() * output_rect.top() +
-        webrtc::DesktopFrame::kBytesPerPixel * output_rect.left();
-    libyuv::ARGBScale(frame->data(), frame->stride(),
-                      frame->size().width(), frame->size().height(),
-                      output_rect_data, output_frame_->stride(),
-                      output_rect.width(), output_rect.height(),
-                      libyuv::kFilterBilinear);
+    uint8_t* output_rect_data =
+        output_frame_->GetFrameDataAtPos(output_rect.top_left());
+    libyuv::ARGBScale(frame->data(), frame->stride(), frame->size().width(),
+                      frame->size().height(), output_rect_data,
+                      output_frame_->stride(), output_rect.width(),
+                      output_rect.height(), libyuv::kFilterBilinear);
     output_data = output_frame_->data();
-  } else if (IsFrameUnpackedOrInverted(frame)) {
+  } else if (IsFrameUnpackedOrInverted(frame.get())) {
     // If |frame| is not packed top-to-bottom then create a packed top-to-bottom
     // copy.
     // This is required if the frame is inverted (see crbug.com/306876), or if
@@ -301,10 +297,8 @@
       memset(output_frame_->data(), 0, output_bytes);
     }
 
-    output_frame_->CopyPixelsFrom(
-        *frame,
-        webrtc::DesktopVector(),
-        webrtc::DesktopRect::MakeSize(frame->size()));
+    output_frame_->CopyPixelsFrom(*frame, webrtc::DesktopVector(),
+                                  webrtc::DesktopRect::MakeSize(frame->size()));
     output_data = output_frame_->data();
   } else {
     // If the captured frame matches the output size, we can return the pixel
diff --git a/content/browser/media/capture/desktop_capture_device_unittest.cc b/content/browser/media/capture/desktop_capture_device_unittest.cc
index 738c85d8..63f655f4 100644
--- a/content/browser/media/capture/desktop_capture_device_unittest.cc
+++ b/content/browser/media/capture/desktop_capture_device_unittest.cc
@@ -111,15 +111,15 @@
 // Creates a DesktopFrame that has the first pixel bytes set to
 // kFakePixelValueFirst, and the rest of the bytes set to kFakePixelValue, for
 // UnpackedFrame and InvertedFrame verification.
-webrtc::BasicDesktopFrame* CreateBasicFrame(const webrtc::DesktopSize& size) {
-  webrtc::BasicDesktopFrame* frame = new webrtc::BasicDesktopFrame(size);
+std::unique_ptr<webrtc::BasicDesktopFrame> CreateBasicFrame(
+    const webrtc::DesktopSize& size) {
+  std::unique_ptr<webrtc::BasicDesktopFrame> frame(
+      new webrtc::BasicDesktopFrame(size));
   DCHECK_EQ(frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel,
             frame->stride());
-  memset(frame->data(),
-         kFakePixelValue,
+  memset(frame->data(), kFakePixelValue,
          frame->stride() * frame->size().height());
-  memset(frame->data(),
-         kFakePixelValueFirst,
+  memset(frame->data(), kFakePixelValueFirst,
          webrtc::DesktopFrame::kBytesPerPixel);
   return frame;
 }
@@ -129,16 +129,16 @@
 class InvertedDesktopFrame : public webrtc::DesktopFrame {
  public:
   // Takes ownership of |frame|.
-  explicit InvertedDesktopFrame(webrtc::DesktopFrame* frame)
+  explicit InvertedDesktopFrame(std::unique_ptr<webrtc::DesktopFrame> frame)
       : webrtc::DesktopFrame(
             frame->size(),
             -frame->stride(),
             frame->data() + (frame->size().height() - 1) * frame->stride(),
-            frame->shared_memory()),
-        original_frame_(frame) {
+            frame->shared_memory()) {
     set_dpi(frame->dpi());
     set_capture_time_ms(frame->capture_time_ms());
     mutable_updated_region()->Swap(frame->mutable_updated_region());
+    original_frame_ = std::move(frame);
   }
   ~InvertedDesktopFrame() override {}
 
@@ -152,17 +152,15 @@
 class UnpackedDesktopFrame : public webrtc::DesktopFrame {
  public:
   // Takes ownership of |frame|.
-  explicit UnpackedDesktopFrame(webrtc::DesktopFrame* frame)
+  explicit UnpackedDesktopFrame(std::unique_ptr<webrtc::DesktopFrame> frame)
       : webrtc::DesktopFrame(
             frame->size(),
             frame->stride() * 2,
             new uint8_t[frame->stride() * 2 * frame->size().height()],
-            NULL) {
+            nullptr) {
     memset(data(), kFramePaddingValue, stride() * size().height());
-    CopyPixelsFrom(*frame,
-                   webrtc::DesktopVector(),
+    CopyPixelsFrom(*frame, webrtc::DesktopVector(),
                    webrtc::DesktopRect::MakeSize(size()));
-    delete frame;
   }
   ~UnpackedDesktopFrame() override {
     delete[] data_;
@@ -203,14 +201,15 @@
     }
     frame_index_++;
 
-    webrtc::DesktopFrame* frame = CreateBasicFrame(size);
+    std::unique_ptr<webrtc::DesktopFrame> frame = CreateBasicFrame(size);
 
     if (generate_inverted_frames_) {
-      frame = new InvertedDesktopFrame(frame);
+      frame.reset(new InvertedDesktopFrame(std::move(frame)));
     } else if (generate_cropped_frames_) {
-      frame = new UnpackedDesktopFrame(frame);
+      frame.reset(new UnpackedDesktopFrame(std::move(frame)));
     }
-    callback_->OnCaptureCompleted(frame);
+    callback_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
+                               std::move(frame));
   }
 
   bool GetScreenList(ScreenList* screens) override { return false; }
@@ -498,8 +497,8 @@
 
   // Verifies that |output_frame_| has the same data as a packed frame of the
   // same size.
-  std::unique_ptr<webrtc::BasicDesktopFrame> expected_frame(CreateBasicFrame(
-      webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
+  std::unique_ptr<webrtc::BasicDesktopFrame> expected_frame = CreateBasicFrame(
+      webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1));
   EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
             frame_size);
   EXPECT_EQ(
diff --git a/content/browser/media/media_web_contents_observer.cc b/content/browser/media/media_web_contents_observer.cc
index 55d8533a4..066d46fd 100644
--- a/content/browser/media/media_web_contents_observer.cc
+++ b/content/browser/media/media_web_contents_observer.cc
@@ -10,12 +10,11 @@
 #include "build/build_config.h"
 #include "content/browser/media/audible_metrics.h"
 #include "content/browser/media/audio_stream_monitor.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/media/media_player_delegate_messages.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 #include "ipc/ipc_message_macros.h"
 
 namespace content {
@@ -184,23 +183,27 @@
 
 void MediaWebContentsObserver::CreateAudioPowerSaveBlocker() {
   DCHECK(!audio_power_save_blocker_);
-  audio_power_save_blocker_ = CreatePowerSaveBlocker(
+  audio_power_save_blocker_.reset(new device::PowerSaveBlocker(
       device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
-      device::PowerSaveBlocker::kReasonAudioPlayback, "Playing audio");
+      device::PowerSaveBlocker::kReasonAudioPlayback, "Playing audio",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
 }
 
 void MediaWebContentsObserver::CreateVideoPowerSaveBlocker() {
   DCHECK(!video_power_save_blocker_);
   DCHECK(!active_video_players_.empty());
-  video_power_save_blocker_ = CreatePowerSaveBlocker(
+  video_power_save_blocker_.reset(new device::PowerSaveBlocker(
       device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-      device::PowerSaveBlocker::kReasonVideoPlayback, "Playing video");
+      device::PowerSaveBlocker::kReasonVideoPlayback, "Playing video",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
 #if defined(OS_ANDROID)
   if (web_contents()->GetNativeView()) {
     view_weak_factory_.reset(new base::WeakPtrFactory<ui::ViewAndroid>(
         web_contents()->GetNativeView()));
-    static_cast<device::PowerSaveBlockerImpl*>(video_power_save_blocker_.get())
-        ->InitDisplaySleepBlocker(view_weak_factory_->GetWeakPtr());
+    video_power_save_blocker_.get()->InitDisplaySleepBlocker(
+        view_weak_factory_->GetWeakPtr());
   }
 #endif
 }
diff --git a/content/browser/media/webrtc/webrtc_internals.cc b/content/browser/media/webrtc/webrtc_internals.cc
index de28bb0..1a1d57f1 100644
--- a/content/browser/media/webrtc/webrtc_internals.cc
+++ b/content/browser/media/webrtc/webrtc_internals.cc
@@ -9,12 +9,12 @@
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
 #include "content/browser/media/webrtc/webrtc_internals_ui_observer.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/browser/web_contents/web_contents_view.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 
 using base::ProcessId;
 using std::string;
@@ -500,10 +500,12 @@
   } else if (!peer_connection_data_.empty() && !power_save_blocker_) {
     DVLOG(1) << ("Preventing the application from being suspended while one or "
                  "more PeerConnections are active.");
-    power_save_blocker_ = content::CreatePowerSaveBlocker(
+    power_save_blocker_.reset(new device::PowerSaveBlocker(
         device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
         device::PowerSaveBlocker::kReasonOther,
-        "WebRTC has active PeerConnections");
+        "WebRTC has active PeerConnections",
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
   }
 }
 
diff --git a/content/browser/power_save_blocker_factory.cc b/content/browser/power_save_blocker_factory.cc
deleted file mode 100644
index 113e35b..0000000
--- a/content/browser/power_save_blocker_factory.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/power_save_blocker_factory.h"
-
-#include "base/threading/sequenced_worker_pool.h"
-#include "content/public/browser/browser_thread.h"
-
-namespace content {
-
-std::unique_ptr<device::PowerSaveBlocker> CreatePowerSaveBlocker(
-    device::PowerSaveBlocker::PowerSaveBlockerType type,
-    device::PowerSaveBlocker::Reason reason,
-    const std::string& description) {
-  return device::PowerSaveBlocker::CreateWithTaskRunners(
-      type, reason, description,
-      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
-      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE));
-}
-
-}  // namespace content
diff --git a/content/browser/power_save_blocker_factory.h b/content/browser/power_save_blocker_factory.h
deleted file mode 100644
index 3d430d8a..0000000
--- a/content/browser/power_save_blocker_factory.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
-#define CONTENT_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
-
-#include <memory>
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "base/sequenced_task_runner.h"
-#include "content/common/content_export.h"
-#include "device/power_save_blocker/power_save_blocker.h"
-
-namespace content {
-
-CONTENT_EXPORT std::unique_ptr<device::PowerSaveBlocker> CreatePowerSaveBlocker(
-    device::PowerSaveBlocker::PowerSaveBlockerType type,
-    device::PowerSaveBlocker::Reason reason,
-    const std::string& description);
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_POWER_SAVE_BLOCKER_FACTORY_H_
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 0d8d170..19d43448 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -406,10 +406,8 @@
   cmd_line->AppendSwitchASCII(switches::kMojoChannelToken, mojo_channel_token);
 
 #if defined(OS_WIN)
-  if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument()) {
-    cmd_line->AppendArg(is_broker_ ? switches::kPrefetchArgumentPpapiBroker
-                                   : switches::kPrefetchArgumentPpapi);
-  }
+  cmd_line->AppendArg(is_broker_ ? switches::kPrefetchArgumentPpapiBroker
+                                 : switches::kPrefetchArgumentPpapi);
 #endif  // defined(OS_WIN)
 
   // These switches are forwarded to both plugin and broker pocesses.
@@ -471,8 +469,12 @@
   int renderer_child_id;
   client->GetPpapiChannelInfo(&process_handle, &renderer_child_id);
 
-  base::ProcessId process_id = (process_handle == base::kNullProcessHandle) ?
-      0 : base::GetProcId(process_handle);
+  base::ProcessId process_id = base::kNullProcessId;
+  if (process_handle != base::kNullProcessHandle) {
+    // This channel is not used by the browser itself.
+    process_id = base::GetProcId(process_handle);
+    CHECK_NE(base::kNullProcessId, process_id);
+  }
 
   // We can't send any sync messages from the browser because it might lead to
   // a hang. See the similar code in PluginProcessHost for more description.
diff --git a/content/browser/ppapi_plugin_process_host.h b/content/browser/ppapi_plugin_process_host.h
index 48c007bb..90c9b09 100644
--- a/content/browser/ppapi_plugin_process_host.h
+++ b/content/browser/ppapi_plugin_process_host.h
@@ -36,6 +36,8 @@
   class Client {
    public:
     // Gets the information about the renderer that's requesting the channel.
+    // If |renderer_handle| is base::kNullProcessHandle, this channel is used by
+    // the browser itself.
     virtual void GetPpapiChannelInfo(base::ProcessHandle* renderer_handle,
                                      int* renderer_id) = 0;
 
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index b308c52..a206534 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -36,10 +36,12 @@
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface.h"
 #include "cc/output/output_surface_client.h"
+#include "cc/output/texture_mailbox_deleter.h"
 #include "cc/output/vulkan_in_process_context_provider.h"
 #include "cc/raster/single_thread_task_graph_runner.h"
 #include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface_display_output_surface.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "cc/surfaces/surface_manager.h"
@@ -152,30 +154,25 @@
 }
 
 // Used to override capabilities_.adjust_deadline_for_parent to false
-class OutputSurfaceWithoutParent : public cc::OutputSurface,
-                                   public CompositorImpl::VSyncObserver {
+class OutputSurfaceWithoutParent : public cc::OutputSurface {
  public:
   OutputSurfaceWithoutParent(
-      CompositorImpl* compositor,
       scoped_refptr<ContextProviderCommandBuffer> context_provider,
       const base::Callback<void(gpu::Capabilities)>&
-          populate_gpu_capabilities_callback,
-      std::unique_ptr<ExternalBeginFrameSource> begin_frame_source)
+          populate_gpu_capabilities_callback)
       : cc::OutputSurface(std::move(context_provider), nullptr, nullptr),
-        compositor_(compositor),
         populate_gpu_capabilities_callback_(populate_gpu_capabilities_callback),
         swap_buffers_completion_callback_(
             base::Bind(&OutputSurfaceWithoutParent::OnSwapBuffersCompleted,
                        base::Unretained(this))),
         overlay_candidate_validator_(
             new display_compositor::
-                CompositorOverlayCandidateValidatorAndroid()),
-        begin_frame_source_(std::move(begin_frame_source)) {
+                CompositorOverlayCandidateValidatorAndroid()) {
     capabilities_.adjust_deadline_for_parent = false;
     capabilities_.max_frames_pending = kMaxDisplaySwapBuffers;
   }
 
-  ~OutputSurfaceWithoutParent() override { compositor_->RemoveObserver(this); }
+  ~OutputSurfaceWithoutParent() override = default;
 
   void SwapBuffers(cc::CompositorFrame* frame) override {
     GetCommandBufferProxy()->SetLatencyInfo(frame->metadata.latency_info);
@@ -198,18 +195,9 @@
 
     populate_gpu_capabilities_callback_.Run(
         context_provider_->ContextCapabilities());
-    compositor_->AddObserver(this);
-
-    client->SetBeginFrameSource(begin_frame_source_.get());
-
     return true;
   }
 
-  void DetachFromClient() override {
-    client_->SetBeginFrameSource(nullptr);
-    OutputSurface::DetachFromClient();
-  }
-
   cc::OverlayCandidateValidator* GetOverlayCandidateValidator() const override {
     return overlay_candidate_validator_.get();
   }
@@ -233,12 +221,7 @@
     OutputSurface::OnSwapBuffersComplete();
   }
 
-  void OnVSync(base::TimeTicks timebase, base::TimeDelta interval) override {
-    client_->CommitVSyncParameters(timebase, interval);
-  }
-
  private:
-  CompositorImpl* compositor_;
   base::Callback<void(gpu::Capabilities)> populate_gpu_capabilities_callback_;
   base::CancelableCallback<void(
       const std::vector<ui::LatencyInfo>&,
@@ -246,17 +229,14 @@
       const gpu::GpuProcessHostedCALayerTreeParamsMac* params_mac)>
       swap_buffers_completion_callback_;
   std::unique_ptr<cc::OverlayCandidateValidator> overlay_candidate_validator_;
-  std::unique_ptr<ExternalBeginFrameSource> begin_frame_source_;
 };
 
 #if defined(ENABLE_VULKAN)
 class VulkanOutputSurface : public cc::OutputSurface {
  public:
-  VulkanOutputSurface(
-      scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider,
-      std::unique_ptr<ExternalBeginFrameSource> begin_frame_source)
-      : OutputSurface(std::move(vulkan_context_provider)),
-        begin_frame_source_(std::move(begin_frame_source)) {}
+  explicit VulkanOutputSurface(
+      scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider)
+      : OutputSurface(std::move(vulkan_context_provider)) {}
 
   ~VulkanOutputSurface() override { Destroy(); }
 
@@ -276,7 +256,6 @@
   bool BindToClient(cc::OutputSurfaceClient* client) override {
     if (!OutputSurface::BindToClient(client))
       return false;
-    client->SetBeginFrameSource(begin_frame_source_.get());
     return true;
   }
 
@@ -301,7 +280,6 @@
 
  private:
   std::unique_ptr<gpu::VulkanSurface> surface_;
-  std::unique_ptr<ExternalBeginFrameSource> begin_frame_source_;
 
   DISALLOW_COPY_AND_ASSIGN(VulkanOutputSurface);
 };
@@ -618,9 +596,8 @@
 #if defined(ENABLE_VULKAN)
   std::unique_ptr<VulkanOutputSurface> vulkan_surface;
   if (vulkan_context_provider) {
-    vulkan_surface.reset(new VulkanOutputSurface(
-        std::move(vulkan_context_provider),
-        base::WrapUnique(new ExternalBeginFrameSource(this))));
+    vulkan_surface.reset(
+        new VulkanOutputSurface(std::move(vulkan_context_provider)));
     if (!vulkan_surface->Initialize(window_)) {
       vulkan_surface->Destroy();
       vulkan_surface.reset();
@@ -709,19 +686,25 @@
     DCHECK(context_provider.get());
 
     display_output_surface = base::WrapUnique(new OutputSurfaceWithoutParent(
-        this, context_provider,
-        base::Bind(&CompositorImpl::PopulateGpuCapabilities,
-                   base::Unretained(this)),
-        base::WrapUnique(new ExternalBeginFrameSource(this))));
+        context_provider, base::Bind(&CompositorImpl::PopulateGpuCapabilities,
+                                     base::Unretained(this))));
   }
 
   cc::SurfaceManager* manager = GetSurfaceManager();
-  display_.reset(new cc::Display(manager, HostSharedBitmapManager::current(),
-                                 BrowserGpuMemoryBufferManager::current(),
-                                 host_->settings().renderer_settings,
-                                 surface_id_allocator_->id_namespace(),
-                                 base::ThreadTaskRunnerHandle::Get().get(),
-                                 std::move(display_output_surface)));
+  auto* task_runner = base::ThreadTaskRunnerHandle::Get().get();
+  std::unique_ptr<ExternalBeginFrameSource> begin_frame_source(
+      new ExternalBeginFrameSource(this));
+  std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
+      begin_frame_source.get(), task_runner,
+      display_output_surface->capabilities().max_frames_pending));
+
+  display_.reset(new cc::Display(
+      manager, HostSharedBitmapManager::current(),
+      BrowserGpuMemoryBufferManager::current(),
+      host_->settings().renderer_settings,
+      surface_id_allocator_->id_namespace(), std::move(begin_frame_source),
+      std::move(display_output_surface), std::move(scheduler),
+      base::MakeUnique<cc::TextureMailboxDeleter>(task_runner)));
 
   std::unique_ptr<cc::SurfaceDisplayOutputSurface> delegated_output_surface(
       vulkan_context_provider
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index b1085f4d..4c2131cb 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1295,8 +1295,7 @@
                                   switches::kRendererProcess);
 
 #if defined(OS_WIN)
-  if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument())
-    command_line->AppendArg(switches::kPrefetchArgumentRenderer);
+  command_line->AppendArg(switches::kPrefetchArgumentRenderer);
 #endif  // defined(OS_WIN)
 
   // Now send any options from our own command line we want to propagate.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 6cbc87ff..1d2af26 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -930,7 +930,9 @@
 
   // Without this check, the renderer can trick the browser into using
   // filenames it can't access in a future session restore.
-  if (!CanAccessFilesOfPageState(state)) {
+  auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
+  int child_id = GetProcess()->GetID();
+  if (!policy->CanReadAllFiles(child_id, state.GetReferencedFiles())) {
     bad_message::ReceivedBadMessage(
         GetProcess(), bad_message::RVH_CAN_ACCESS_FILES_OF_PAGE_STATE);
     return;
@@ -1222,30 +1224,6 @@
 #endif
 }
 
-bool RenderViewHostImpl::CanAccessFilesOfPageState(
-    const PageState& state) const {
-  ChildProcessSecurityPolicyImpl* policy =
-      ChildProcessSecurityPolicyImpl::GetInstance();
-
-  const std::vector<base::FilePath>& file_paths = state.GetReferencedFiles();
-  for (const auto& file : file_paths) {
-    if (!policy->CanReadFile(GetProcess()->GetID(), file))
-      return false;
-  }
-  return true;
-}
-
-void RenderViewHostImpl::GrantFileAccessFromPageState(const PageState& state) {
-  ChildProcessSecurityPolicyImpl* policy =
-      ChildProcessSecurityPolicyImpl::GetInstance();
-
-  const std::vector<base::FilePath>& file_paths = state.GetReferencedFiles();
-  for (const auto& file : file_paths) {
-    if (!policy->CanReadFile(GetProcess()->GetID(), file))
-      policy->GrantReadFile(GetProcess()->GetID(), file);
-  }
-}
-
 void RenderViewHostImpl::SelectWordAroundCaret() {
   Send(new ViewMsg_SelectWordAroundCaret(GetRoutingID()));
 }
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 495ee21..42a811a 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -337,16 +337,6 @@
   // See https://crbug.com/304341.
   WebPreferences ComputeWebkitPrefs();
 
-  // Returns whether the current RenderProcessHost has read access to the files
-  // reported in |state|.
-  bool CanAccessFilesOfPageState(const PageState& state) const;
-
-  // Grants the current RenderProcessHost read access to any file listed in
-  // |validated_state|.  It is important that the PageState has been validated
-  // upon receipt from the renderer process to prevent it from forging access to
-  // files without the user's consent.
-  void GrantFileAccessFromPageState(const PageState& validated_state);
-
   // 1. Grants permissions to URL (if any)
   // 2. Grants permissions to filenames
   // 3. Grants permissions to file system files.
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index b9cc76e..aaba6a3 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -82,7 +82,6 @@
 #include "ui/snapshot/snapshot.h"
 
 #if defined(OS_MACOSX)
-#include "content/browser/power_save_blocker_factory.h"
 #include "device/power_save_blocker/power_save_blocker.h"
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #endif
@@ -1294,11 +1293,11 @@
   // does not go to sleep for the duration of reading a snapshot.
   if (pending_browser_snapshots_.empty()) {
     DCHECK(!power_save_blocker_);
-    power_save_blocker_.reset(
-        CreatePowerSaveBlocker(
-            device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-            device::PowerSaveBlocker::kReasonOther, "GetSnapshot")
-            .release());
+    power_save_blocker_.reset(new device::PowerSaveBlocker(
+        device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
+        device::PowerSaveBlocker::kReasonOther, "GetSnapshot",
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
   }
 #endif
   pending_browser_snapshots_.insert(std::make_pair(id, callback));
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index 2ecce76..fb5f0cc 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1137,11 +1137,6 @@
       new LastFrameInfo(output_surface_id, std::move(frame)));
 }
 
-SynchronousCompositorHost*
-RenderWidgetHostViewAndroid::GetSynchronousCompositor() {
-  return sync_compositor_.get();
-}
-
 void RenderWidgetHostViewAndroid::SynchronousFrameMetadata(
     const cc::CompositorFrameMetadata& frame_metadata) {
   if (!content_view_core_)
@@ -1782,8 +1777,6 @@
     sync_compositor_ = SynchronousCompositorHost::Create(
         this, content_view_core_->GetWebContents());
   }
-  if (sync_compositor_)
-    sync_compositor_->DidBecomeCurrent();
 }
 
 void RenderWidgetHostViewAndroid::RunAckCallbacks(
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 9afe73b..8b8b5d1 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -248,7 +248,6 @@
   void OnShowingPastePopup(const gfx::PointF& point);
   void OnShowUnhandledTapUIIfNeeded(int x_dip, int y_dip);
 
-  SynchronousCompositorHost* GetSynchronousCompositor();
   void SynchronousFrameMetadata(
       const cc::CompositorFrameMetadata& frame_metadata);
 
diff --git a/content/browser/service_worker/service_worker_version_unittest.cc b/content/browser/service_worker/service_worker_version_unittest.cc
index 2b1987f..dbdf4c8 100644
--- a/content/browser/service_worker/service_worker_version_unittest.cc
+++ b/content/browser/service_worker/service_worker_version_unittest.cc
@@ -164,6 +164,14 @@
     callback.Run();
   }
 
+  void DoTerminateProcess(const DoTerminateProcessCallback& callback) override {
+    NOTREACHED();
+  }
+
+  void CreateFolder(const CreateFolderCallback& callback) override {
+    NOTREACHED();
+  }
+
   void GetRequestorName(const GetRequestorNameCallback& callback) override {
     callback.Run(mojo::String(""));
   }
diff --git a/content/browser/session_history_browsertest.cc b/content/browser/session_history_browsertest.cc
index acd569d6..4f801271 100644
--- a/content/browser/session_history_browsertest.cc
+++ b/content/browser/session_history_browsertest.cc
@@ -506,7 +506,7 @@
 // redirects (as mandated by https://tools.ietf.org/html/rfc7231#section-6.4.7).
 IN_PROC_BROWSER_TEST_F(SessionHistoryTest, GoBackToCrossSitePostWithRedirect) {
   GURL form_url(embedded_test_server()->GetURL(
-      "a.com", "/session_history/form_that_posts_cross_site.html"));
+      "a.com", "/form_that_posts_cross_site.html"));
   GURL redirect_target_url(embedded_test_server()->GetURL("x.com", "/echoall"));
   GURL page_to_go_back_from(
       embedded_test_server()->GetURL("c.com", "/title1.html"));
@@ -518,7 +518,7 @@
   // Submit the form.
   TestNavigationObserver form_post_observer(shell()->web_contents(), 1);
   EXPECT_TRUE(
-      ExecuteScript(shell(), "document.getElementById('form').submit();"));
+      ExecuteScript(shell(), "document.getElementById('text-form').submit();"));
   form_post_observer.Wait();
 
   // Verify that we arrived at the expected, redirected location.
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index 1f421562..b211eeb 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -314,8 +314,7 @@
     cmd_line->AppendSwitchASCII(switches::kLang, locale);
 
 #if defined(OS_WIN)
-    if (GetContentClient()->browser()->ShouldUseWindowsPrefetchArgument())
-      cmd_line->AppendArg(switches::kPrefetchArgumentOther);
+    cmd_line->AppendArg(switches::kPrefetchArgumentOther);
 #endif  // defined(OS_WIN)
 
     if (no_sandbox_)
diff --git a/content/browser/utility_process_mojo_client_browsertest.cc b/content/browser/utility_process_mojo_client_browsertest.cc
new file mode 100644
index 0000000..8517017d
--- /dev/null
+++ b/content/browser/utility_process_mojo_client_browsertest.cc
@@ -0,0 +1,141 @@
+// 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/public/browser/utility_process_mojo_client.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/command_line.h"
+#include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/test_mojo_service.mojom.h"
+
+namespace content {
+
+// Test fixture used to make different Mojo calls to the utility process.
+class UtilityProcessMojoClientBrowserTest : public ContentBrowserTest {
+ public:
+  void StartMojoService(bool disable_sandbox) {
+    mojo_client_.reset(new UtilityProcessMojoClient<mojom::TestMojoService>(
+        base::ASCIIToUTF16("TestMojoProcess"),
+        base::Bind(&UtilityProcessMojoClientBrowserTest::OnConnectionError,
+                   base::Unretained(this))));
+
+    // This test case needs to have the sandbox disabled.
+    if (disable_sandbox)
+      mojo_client_->set_disable_sandbox();
+    mojo_client_->Start();
+  }
+
+  // Called when a response is received from a call to DoSomething() or
+  // DoTerminateProcess().
+  void OnResponseReceived() {
+    response_received_ = true;
+    done_closure_.Run();
+  }
+
+  // Called when a connection error happen between the test and the utility
+  // process.
+  void OnConnectionError() {
+    error_happened_ = true;
+    done_closure_.Run();
+  }
+
+  // Called when a responsed is received from a call to CreateFolder().
+  void OnCreateFolderFinished(bool succeeded) {
+    response_received_ = true;
+    sandbox_succeeded_ = succeeded;
+    done_closure_.Run();
+  }
+
+ protected:
+  std::unique_ptr<UtilityProcessMojoClient<mojom::TestMojoService>>
+      mojo_client_;
+  base::Closure done_closure_;
+
+  // The test result that is compared to the current test case.
+  bool response_received_ = false;
+  bool error_happened_ = false;
+  bool sandbox_succeeded_ = false;
+};
+
+// Successful call through the Mojo service with response back.
+IN_PROC_BROWSER_TEST_F(UtilityProcessMojoClientBrowserTest, CallService) {
+  base::RunLoop run_loop;
+  done_closure_ = run_loop.QuitClosure();
+
+  StartMojoService(false);
+
+  mojo_client_->service()->DoSomething(
+      base::Bind(&UtilityProcessMojoClientBrowserTest::OnResponseReceived,
+                 base::Unretained(this)));
+
+  run_loop.Run();
+  EXPECT_TRUE(response_received_);
+  EXPECT_FALSE(error_happened_);
+}
+
+// Call the Mojo service but the utility process terminates before getting
+// the result back.
+// TODO(pmonette): Re-enable when crbug.com/618206 is fixed.
+IN_PROC_BROWSER_TEST_F(UtilityProcessMojoClientBrowserTest,
+                       DISABLED_ConnectionError) {
+  base::RunLoop run_loop;
+  done_closure_ = run_loop.QuitClosure();
+
+  StartMojoService(false);
+
+  mojo_client_->service()->DoTerminateProcess(
+      base::Bind(&UtilityProcessMojoClientBrowserTest::OnResponseReceived,
+                 base::Unretained(this)));
+
+  run_loop.Run();
+  EXPECT_FALSE(response_received_);
+  EXPECT_TRUE(error_happened_);
+}
+
+// Android doesn't support non-sandboxed utility processes.
+#if !defined(OS_ANDROID)
+// Call a function that fails because the sandbox is still enabled.
+IN_PROC_BROWSER_TEST_F(UtilityProcessMojoClientBrowserTest, SandboxFailure) {
+  base::RunLoop run_loop;
+  done_closure_ = run_loop.QuitClosure();
+
+  StartMojoService(false);
+
+  mojo_client_->service()->CreateFolder(
+      base::Bind(&UtilityProcessMojoClientBrowserTest::OnCreateFolderFinished,
+                 base::Unretained(this)));
+
+  run_loop.Run();
+  EXPECT_TRUE(response_received_);
+  // If the sandbox is disabled by the command line, this will succeed.
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoSandbox))
+    EXPECT_FALSE(sandbox_succeeded_);
+  EXPECT_FALSE(error_happened_);
+}
+
+// Call a function that succeeds only when the sandbox is disabled.
+IN_PROC_BROWSER_TEST_F(UtilityProcessMojoClientBrowserTest, SandboxSuccess) {
+  base::RunLoop run_loop;
+  done_closure_ = run_loop.QuitClosure();
+
+  StartMojoService(true);
+
+  mojo_client_->service()->CreateFolder(
+      base::Bind(&UtilityProcessMojoClientBrowserTest::OnCreateFolderFinished,
+                 base::Unretained(this)));
+
+  run_loop.Run();
+  EXPECT_TRUE(response_received_);
+  EXPECT_TRUE(sandbox_succeeded_);
+  EXPECT_FALSE(error_happened_);
+}
+#endif
+
+}  // namespace content
diff --git a/content/browser/wake_lock/wake_lock_service_context.cc b/content/browser/wake_lock/wake_lock_service_context.cc
index 48d3454..cdb7e1c 100644
--- a/content/browser/wake_lock/wake_lock_service_context.cc
+++ b/content/browser/wake_lock/wake_lock_service_context.cc
@@ -8,13 +8,12 @@
 
 #include "base/bind.h"
 #include "build/build_config.h"
-#include "content/browser/power_save_blocker_factory.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/service_registry.h"
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 
 namespace content {
 
@@ -68,9 +67,11 @@
 
 void WakeLockServiceContext::CreateWakeLock() {
   DCHECK(!wake_lock_);
-  wake_lock_ = CreatePowerSaveBlocker(
+  wake_lock_.reset(new device::PowerSaveBlocker(
       device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep,
-      device::PowerSaveBlocker::kReasonOther, "Wake Lock API");
+      device::PowerSaveBlocker::kReasonOther, "Wake Lock API",
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
+      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE)));
 
 #if defined(OS_ANDROID)
   // On Android, additionaly associate the blocker with this WebContents.
@@ -79,8 +80,7 @@
   if (web_contents()->GetNativeView()) {
     view_weak_factory_.reset(new base::WeakPtrFactory<ui::ViewAndroid>(
         web_contents()->GetNativeView()));
-    static_cast<device::PowerSaveBlockerImpl*>(wake_lock_.get())
-        ->InitDisplaySleepBlocker(view_weak_factory_->GetWeakPtr());
+    wake_lock_.get()->InitDisplaySleepBlocker(view_weak_factory_->GetWeakPtr());
   }
 #endif
 }
diff --git a/content/common/page_state_serialization.h b/content/common/page_state_serialization.h
index c8bacb78..90484c4 100644
--- a/content/common/page_state_serialization.h
+++ b/content/common/page_state_serialization.h
@@ -58,9 +58,10 @@
 };
 
 struct CONTENT_EXPORT ExplodedPageState {
-  // TODO(creis): Move referenced_files to ExplodedFrameState.
-  // It currently contains a list from all frames, but cannot be deserialized
-  // into the files referenced by each frame.  See http://crbug.com/441966.
+  // TODO(creis, lukasza): Instead of storing them in |referenced_files|,
+  // extract referenced files from ExplodedHttpBody.  |referenced_files|
+  // currently contains a list from all frames, but cannot be deserialized into
+  // the files referenced by each frame.  See http://crbug.com/441966.
   std::vector<base::NullableString16> referenced_files;
   ExplodedFrameState top;
 
diff --git a/content/common/resource_request_body_impl.cc b/content/common/resource_request_body_impl.cc
index d375e0f1..80212bd9 100644
--- a/content/common/resource_request_body_impl.cc
+++ b/content/common/resource_request_body_impl.cc
@@ -46,6 +46,16 @@
                                            expected_modification_time);
 }
 
+std::vector<base::FilePath> ResourceRequestBodyImpl::GetReferencedFiles()
+    const {
+  std::vector<base::FilePath> result;
+  for (const auto& element : *elements()) {
+    if (element.type() == Element::TYPE_FILE)
+      result.push_back(element.path());
+  }
+  return result;
+}
+
 ResourceRequestBodyImpl::~ResourceRequestBodyImpl() {}
 
 }  // namespace content
diff --git a/content/common/resource_request_body_impl.h b/content/common/resource_request_body_impl.h
index 81e46d1..4cc8ad0 100644
--- a/content/common/resource_request_body_impl.h
+++ b/content/common/resource_request_body_impl.h
@@ -55,6 +55,9 @@
   void set_identifier(int64_t id) { identifier_ = id; }
   int64_t identifier() const { return identifier_; }
 
+  // Returns paths referred to by |elements| of type Element::TYPE_FILE.
+  std::vector<base::FilePath> GetReferencedFiles() const;
+
  private:
   ~ResourceRequestBodyImpl() override;
 
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 09ded70..d8ea67218 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -103,7 +103,6 @@
   ],
   'variables': {
     'public_browser_sources': [
-      'browser/power_save_blocker_factory.h',
       'public/browser/access_token_store.h',
       'public/browser/android/browser_media_player_manager_register.cc',
       'public/browser/android/browser_media_player_manager_register.h',
@@ -324,6 +323,7 @@
       'public/browser/url_data_source.h',
       'public/browser/user_metrics.h',
       'public/browser/utility_process_host.h',
+      'public/browser/utility_process_mojo_client.h',
       'public/browser/web_contents.cc',
       'public/browser/web_contents.h',
       'public/browser/web_contents_delegate.cc',
@@ -1174,7 +1174,6 @@
       'browser/permissions/permission_service_impl.h',
       'browser/power_monitor_message_broadcaster.cc',
       'browser/power_monitor_message_broadcaster.h',
-      'browser/power_save_blocker_factory.cc',
       'browser/power_usage_monitor_impl.cc',
       'browser/power_usage_monitor_impl.h',
       'browser/presentation/presentation_service_impl.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index bcd6f4c..201ba4d 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -276,6 +276,7 @@
       'browser/tracing/memory_tracing_browsertest.cc',
       'browser/tracing/tracing_controller_browsertest.cc',
       'browser/utility_process_host_impl_browsertest.cc',
+      'browser/utility_process_mojo_client_browsertest.cc',
       'browser/vibration_browsertest.cc',
       'browser/wake_lock/wake_lock_browsertest.cc',
       'browser/web_contents/opened_by_dom_browsertest.cc',
@@ -1391,6 +1392,7 @@
         '../base/base.gyp:test_support_base',
         '../device/battery/battery.gyp:device_battery',
         '../device/battery/battery.gyp:device_battery_mojo_bindings',
+        '../device/power_save_blocker/power_save_blocker.gyp:device_power_save_blocker',
         '../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
         '../gin/gin.gyp:gin',
         '../gpu/gpu.gyp:gpu',
diff --git a/content/ppapi_plugin/OWNERS b/content/ppapi_plugin/OWNERS
index 0620950..bf182062 100644
--- a/content/ppapi_plugin/OWNERS
+++ b/content/ppapi_plugin/OWNERS
@@ -1,4 +1,5 @@
 piman@chromium.org
+yzshen@chromium.org
 
 # Mac Sandbox profiles.
 per-file *.sb=set noparent
diff --git a/content/ppapi_plugin/broker_process_dispatcher.cc b/content/ppapi_plugin/broker_process_dispatcher.cc
index 01325531c..a6e5ba6 100644
--- a/content/ppapi_plugin/broker_process_dispatcher.cc
+++ b/content/ppapi_plugin/broker_process_dispatcher.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/child/child_process.h"
@@ -77,12 +78,14 @@
 
 BrokerProcessDispatcher::BrokerProcessDispatcher(
     PP_GetInterface_Func get_plugin_interface,
-    PP_ConnectInstance_Func connect_instance)
+    PP_ConnectInstance_Func connect_instance,
+    bool peer_is_browser)
     : ppapi::proxy::BrokerSideDispatcher(connect_instance),
       get_plugin_interface_(get_plugin_interface),
       flash_browser_operations_1_3_(NULL),
       flash_browser_operations_1_2_(NULL),
-      flash_browser_operations_1_0_(NULL) {
+      flash_browser_operations_1_0_(NULL),
+      peer_is_browser_(peer_is_browser) {
   if (get_plugin_interface) {
     flash_browser_operations_1_0_ =
         static_cast<const PPP_Flash_BrowserOperations_1_0*>(
@@ -110,17 +113,36 @@
 }
 
 bool BrokerProcessDispatcher::OnMessageReceived(const IPC::Message& msg) {
+  if (BrokerSideDispatcher::OnMessageReceived(msg))
+    return true;
+
+  if (!peer_is_browser_) {
+    // We might want to consider killing the peer instead is we see problems in
+    // the future.
+    if (msg.type() == PpapiMsg_GetSitesWithData::ID ||
+        msg.type() == PpapiMsg_ClearSiteData::ID ||
+        msg.type() == PpapiMsg_DeauthorizeContentLicenses::ID ||
+        msg.type() == PpapiMsg_GetPermissionSettings::ID ||
+        msg.type() == PpapiMsg_SetDefaultPermission::ID ||
+        msg.type() == PpapiMsg_SetSitePermission::ID) {
+      base::debug::DumpWithoutCrashing();
+    }
+    return false;
+  }
+
+  bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(BrokerProcessDispatcher, msg)
     IPC_MESSAGE_HANDLER(PpapiMsg_GetSitesWithData, OnGetSitesWithData)
     IPC_MESSAGE_HANDLER(PpapiMsg_ClearSiteData, OnClearSiteData)
     IPC_MESSAGE_HANDLER(PpapiMsg_DeauthorizeContentLicenses,
                         OnDeauthorizeContentLicenses)
-    IPC_MESSAGE_HANDLER(PpapiMsg_GetPermissionSettings, OnGetPermissionSettings)
+    IPC_MESSAGE_HANDLER(PpapiMsg_GetPermissionSettings,
+                        OnGetPermissionSettings)
     IPC_MESSAGE_HANDLER(PpapiMsg_SetDefaultPermission, OnSetDefaultPermission)
     IPC_MESSAGE_HANDLER(PpapiMsg_SetSitePermission, OnSetSitePermission)
-    IPC_MESSAGE_UNHANDLED(return BrokerSideDispatcher::OnMessageReceived(msg))
+    IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
-  return true;
+  return handled;
 }
 
 void BrokerProcessDispatcher::OnGetPermissionSettingsCompleted(
diff --git a/content/ppapi_plugin/broker_process_dispatcher.h b/content/ppapi_plugin/broker_process_dispatcher.h
index 9dca6df..95401dd0 100644
--- a/content/ppapi_plugin/broker_process_dispatcher.h
+++ b/content/ppapi_plugin/broker_process_dispatcher.h
@@ -24,7 +24,8 @@
       public base::SupportsWeakPtr<BrokerProcessDispatcher> {
  public:
   BrokerProcessDispatcher(PP_GetInterface_Func get_plugin_interface,
-                          PP_ConnectInstance_Func connect_instance);
+                          PP_ConnectInstance_Func connect_instance,
+                          bool peer_is_browser);
   ~BrokerProcessDispatcher() override;
 
   // IPC::Listener overrides.
@@ -88,6 +89,8 @@
   const PPP_Flash_BrowserOperations_1_2* flash_browser_operations_1_2_;
   const PPP_Flash_BrowserOperations_1_0* flash_browser_operations_1_0_;
 
+  bool peer_is_browser_;
+
   DISALLOW_COPY_AND_ASSIGN(BrokerProcessDispatcher);
 };
 
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 469fb784..ea5e4bc 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -444,8 +444,8 @@
   IPC::ChannelHandle channel_handle;
 
   if (!plugin_entry_points_.get_interface ||  // Plugin couldn't be loaded.
-      !SetupRendererChannel(renderer_pid, renderer_child_id, incognito,
-                            &channel_handle)) {
+      !SetupChannel(renderer_pid, renderer_child_id, incognito,
+                    &channel_handle)) {
     Send(new PpapiHostMsg_ChannelCreated(IPC::ChannelHandle()));
     return;
   }
@@ -483,10 +483,10 @@
     base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
 }
 
-bool PpapiThread::SetupRendererChannel(base::ProcessId renderer_pid,
-                                       int renderer_child_id,
-                                       bool incognito,
-                                       IPC::ChannelHandle* handle) {
+bool PpapiThread::SetupChannel(base::ProcessId renderer_pid,
+                               int renderer_child_id,
+                               bool incognito,
+                               IPC::ChannelHandle* handle) {
   DCHECK(is_broker_ == (connect_instance_func_ != NULL));
   IPC::ChannelHandle plugin_handle;
   plugin_handle.name = IPC::Channel::GenerateVerifiedChannelID(
@@ -496,15 +496,17 @@
   ppapi::proxy::ProxyChannel* dispatcher = NULL;
   bool init_result = false;
   if (is_broker_) {
+    bool peer_is_browser = renderer_pid == base::kNullProcessId;
     BrokerProcessDispatcher* broker_dispatcher =
         new BrokerProcessDispatcher(plugin_entry_points_.get_interface,
-                                    connect_instance_func_);
+                                    connect_instance_func_, peer_is_browser);
     init_result = broker_dispatcher->InitBrokerWithChannel(this,
                                                            renderer_pid,
                                                            plugin_handle,
                                                            false);
     dispatcher = broker_dispatcher;
   } else {
+    DCHECK_NE(base::kNullProcessId, renderer_pid);
     PluginProcessDispatcher* plugin_dispatcher =
         new PluginProcessDispatcher(plugin_entry_points_.get_interface,
                                     permissions_,
diff --git a/content/ppapi_plugin/ppapi_thread.h b/content/ppapi_plugin/ppapi_thread.h
index 44c1cebf..a3b322b 100644
--- a/content/ppapi_plugin/ppapi_thread.h
+++ b/content/ppapi_plugin/ppapi_thread.h
@@ -110,12 +110,14 @@
   void OnCrash();
   void OnHang();
 
-  // Sets up the channel to the given renderer. On success, returns true and
-  // fills the given ChannelHandle with the information from the new channel.
-  bool SetupRendererChannel(base::ProcessId renderer_pid,
-                            int renderer_child_id,
-                            bool incognito,
-                            IPC::ChannelHandle* handle);
+  // Sets up the channel to the given renderer. If |renderer_pid| is
+  // base::kNullProcessId, the channel is set up to the browser. On success,
+  // returns true and fills the given ChannelHandle with the information from
+  // the new channel.
+  bool SetupChannel(base::ProcessId renderer_pid,
+                    int renderer_child_id,
+                    bool incognito,
+                    IPC::ChannelHandle* handle);
 
   // Sets up the name of the plugin for logging using the given path.
   void SavePluginName(const base::FilePath& path);
diff --git a/content/public/browser/android/synchronous_compositor_client.h b/content/public/browser/android/synchronous_compositor_client.h
index 0fbd2a7..f4343a5c 100644
--- a/content/public/browser/android/synchronous_compositor_client.h
+++ b/content/public/browser/android/synchronous_compositor_client.h
@@ -18,19 +18,19 @@
 class SynchronousCompositorClient {
  public:
   // Indication to the client that |compositor| is now initialized on the
-  // compositor thread, and open for business.
-  virtual void DidInitializeCompositor(SynchronousCompositor* compositor) = 0;
+  // compositor thread, and open for business. |process_id| and |routing_id|
+  // belong to the RVH that owns the compositor.
+  virtual void DidInitializeCompositor(SynchronousCompositor* compositor,
+                                       int process_id,
+                                       int routing_id) = 0;
 
   // Indication to the client that |compositor| is going out of scope, and
   // must not be accessed within or after this call.
   // NOTE if the client goes away before the compositor it must call
   // SynchronousCompositor::SetClient(nullptr) to release the back pointer.
-  virtual void DidDestroyCompositor(SynchronousCompositor* compositor) = 0;
-
-  // Indication to the client that |compositor| just became the current one.
-  // The compositor has to be initialized first. An initialized compositor may
-  // not become current immediately.
-  virtual void DidBecomeCurrent(SynchronousCompositor* compositor) = 0;
+  virtual void DidDestroyCompositor(SynchronousCompositor* compositor,
+                                    int process_id,
+                                    int routing_id) = 0;
 
   // See LayerScrollOffsetDelegate for details.
   virtual void UpdateRootLayerState(const gfx::Vector2dF& total_scroll_offset,
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
index 64133b2..09c7ce9 100644
--- a/content/public/browser/content_browser_client.cc
+++ b/content/public/browser/content_browser_client.cc
@@ -423,10 +423,6 @@
   // is enabled by default in Chrome. See crbug.com/523278.
   return false;
 }
-
-bool ContentBrowserClient::ShouldUseWindowsPrefetchArgument() const {
-  return true;
-}
 #endif  // defined(OS_WIN)
 
 #if defined(VIDEO_HOLE)
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 16918a4..493cb42a 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -772,10 +772,6 @@
   // a process hosting a plugin with the specified |mime_type|.
   virtual bool IsWin32kLockdownEnabledForMimeType(
       const std::string& mime_type) const;
-
-  // Returns true if processes should be launched with a /prefetch:# argument.
-  // See the kPrefetchArgument* constants in content_switches.cc for details.
-  virtual bool ShouldUseWindowsPrefetchArgument() const;
 #endif
 
 #if defined(VIDEO_HOLE)
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc
index 0a67a9e0..7c26471 100644
--- a/content/public/browser/gpu_utils.cc
+++ b/content/public/browser/gpu_utils.cc
@@ -51,7 +51,7 @@
   gpu_preferences.enable_accelerated_vpx_decode =
       command_line->HasSwitch(switches::kEnableAcceleratedVpxDecode);
   gpu_preferences.enable_zero_copy_dxgi_video =
-      !command_line->HasSwitch(switches::kDisableZeroCopyDxgiVideo);
+      command_line->HasSwitch(switches::kEnableZeroCopyDxgiVideo);
 #endif
   gpu_preferences.compile_shader_always_succeeds =
       command_line->HasSwitch(switches::kCompileShaderAlwaysSucceeds);
diff --git a/content/public/browser/utility_process_mojo_client.h b/content/public/browser/utility_process_mojo_client.h
new file mode 100644
index 0000000..3bbe2e9
--- /dev/null
+++ b/content/public/browser/utility_process_mojo_client.h
@@ -0,0 +1,142 @@
+// 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_PUBLIC_BROWSER_UTILITY_PROCESS_MOJO_CLIENT_H_
+#define CONTENT_PUBLIC_BROWSER_UTILITY_PROCESS_MOJO_CLIENT_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/threading/thread_checker.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/utility_process_host.h"
+#include "content/public/browser/utility_process_host_client.h"
+#include "content/public/common/service_registry.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+
+namespace content {
+
+// Implements a client to a Mojo service running on a utility process. Takes
+// care of starting the utility process and connecting to the remote Mojo
+// service. The utility process is terminated in the destructor.
+// Note: This class is not thread-safe. It is bound to the
+// SingleThreadTaskRunner it is created on.
+template <class MojoInterface>
+class UtilityProcessMojoClient {
+ public:
+  UtilityProcessMojoClient(const base::string16& process_name,
+                           const base::Closure& on_error_callback)
+      : on_error_callback_(on_error_callback) {
+    DCHECK(!on_error_callback_.is_null());
+    helper_.reset(new Helper(process_name));
+  }
+
+  ~UtilityProcessMojoClient() {
+    BrowserThread::DeleteSoon(BrowserThread::IO, FROM_HERE, helper_.release());
+  }
+
+  // Disables the sandbox in the utility process.
+  void set_disable_sandbox() {
+    DCHECK(!start_called_);
+    helper_->set_disable_sandbox();
+  }
+
+  // Starts the utility process and connect to the remote Mojo service.
+  void Start() {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(!start_called_);
+
+    start_called_ = true;
+
+    mojo::InterfaceRequest<MojoInterface> req = mojo::GetProxy(&service_);
+
+    service_.set_connection_error_handler(on_error_callback_);
+
+    helper_->Start(MojoInterface::Name_, req.PassMessagePipe());
+  }
+
+  // Returns the Mojo service used to make calls to the utility process.
+  MojoInterface* service() WARN_UNUSED_RESULT {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    DCHECK(start_called_);
+
+    return service_.get();
+  }
+
+ private:
+  // Helper class that takes care of managing the lifetime of the utility
+  // process on the IO thread.
+  class Helper {
+   public:
+    explicit Helper(const base::string16& process_name)
+        : process_name_(process_name) {}
+
+    ~Helper() {
+      DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+      // |utility_host_| manages its own lifetime but this forces the process to
+      // terminate if it's still alive.
+      delete utility_host_.get();
+    }
+
+    // Starts the utility process on the IO thread.
+    void Start(const std::string& mojo_interface_name,
+               mojo::ScopedMessagePipeHandle interface_pipe) {
+      BrowserThread::PostTask(
+          BrowserThread::IO, FROM_HERE,
+          base::Bind(&Helper::StartOnIOThread, base::Unretained(this),
+                     mojo_interface_name, base::Passed(&interface_pipe)));
+    }
+
+    void set_disable_sandbox() { disable_sandbox_ = true; }
+
+   private:
+    // Starts the utility process and connects to the remote Mojo service.
+    void StartOnIOThread(const std::string& mojo_interface_name,
+                         mojo::ScopedMessagePipeHandle interface_pipe) {
+      DCHECK_CURRENTLY_ON(BrowserThread::IO);
+      utility_host_ = UtilityProcessHost::Create(nullptr, nullptr)->AsWeakPtr();
+      utility_host_->SetName(process_name_);
+      if (disable_sandbox_)
+        utility_host_->DisableSandbox();
+
+      utility_host_->Start();
+
+      ServiceRegistry* service_registry = utility_host_->GetServiceRegistry();
+      service_registry->ConnectToRemoteService(mojo_interface_name,
+                                               std::move(interface_pipe));
+    }
+
+    // Properties of the utility process.
+    base::string16 process_name_;
+    bool disable_sandbox_ = false;
+
+    // Must only be accessed on the IO thread.
+    base::WeakPtr<UtilityProcessHost> utility_host_;
+
+    DISALLOW_COPY_AND_ASSIGN(Helper);
+  };
+
+  std::unique_ptr<Helper> helper_;
+
+  // Called when a connection error happens or if the process didn't start.
+  base::Closure on_error_callback_;
+
+  mojo::InterfacePtr<MojoInterface> service_;
+
+  // Enforce calling Start() before getting the service.
+  bool start_called_ = false;
+
+  // Checks that this class is always accessed from the same thread.
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(UtilityProcessMojoClient);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_UTILITY_PROCESS_MOJO_CLIENT_H_
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index f93c0a9..f739f54 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -308,9 +308,6 @@
 // Disable rasterizer that writes directly to GPU memory associated with tiles.
 const char kDisableZeroCopy[]                = "disable-zero-copy";
 
-// Disable the video decoder from drawing directly to a texture.
-const char kDisableZeroCopyDxgiVideo[] = "disable-zero-copy-dxgi-video";
-
 // Specifies if the |DOMAutomationController| needs to be bound in the
 // renderer. This binding happens on per-frame basis and hence can potentially
 // be a performance bottleneck. One should only enable it when automating dom
@@ -519,6 +516,9 @@
 // Enable rasterizer that writes directly to GPU memory associated with tiles.
 const char kEnableZeroCopy[]                = "enable-zero-copy";
 
+// Enable the video decoder to draw directly to a texture.
+const char kEnableZeroCopyDxgiVideo[] = "enable-zero-copy-dxgi-video";
+
 // Explicitly allows additional ports using a comma-separated list of port
 // numbers.
 const char kExplicitlyAllowedPorts[]        = "explicitly-allowed-ports";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 75e3a36..af9700a 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -100,7 +100,6 @@
 CONTENT_EXPORT extern const char kDisableWebSecurity[];
 extern const char kDisableXSSAuditor[];
 CONTENT_EXPORT extern const char kDisableZeroCopy[];
-CONTENT_EXPORT extern const char kDisableZeroCopyDxgiVideo[];
 CONTENT_EXPORT extern const char kDomAutomationController[];
 CONTENT_EXPORT extern const char kDownloadProcess[];
 extern const char kEnable2dCanvasClipAntialiasing[];
@@ -159,6 +158,7 @@
 CONTENT_EXPORT extern const char kEnableWebGLImageChromium[];
 CONTENT_EXPORT extern const char kEnableWebVR[];
 CONTENT_EXPORT extern const char kEnableZeroCopy[];
+CONTENT_EXPORT extern const char kEnableZeroCopyDxgiVideo[];
 CONTENT_EXPORT extern const char kExplicitlyAllowedPorts[];
 CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
 CONTENT_EXPORT extern const char kForceGpuRasterization[];
diff --git a/content/public/test/test_mojo_app.cc b/content/public/test/test_mojo_app.cc
index c3e6498..1fd0b66 100644
--- a/content/public/test/test_mojo_app.cc
+++ b/content/public/test/test_mojo_app.cc
@@ -39,6 +39,15 @@
   base::MessageLoop::current()->QuitWhenIdle();
 }
 
+void TestMojoApp::DoTerminateProcess(
+    const DoTerminateProcessCallback& callback) {
+  NOTREACHED();
+}
+
+void TestMojoApp::CreateFolder(const CreateFolderCallback& callback) {
+  NOTREACHED();
+}
+
 void TestMojoApp::GetRequestorName(const GetRequestorNameCallback& callback) {
   callback.Run(requestor_name_);
 }
diff --git a/content/public/test/test_mojo_app.h b/content/public/test/test_mojo_app.h
index de9684b1..72f14e5c 100644
--- a/content/public/test/test_mojo_app.h
+++ b/content/public/test/test_mojo_app.h
@@ -5,6 +5,8 @@
 #ifndef CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
 #define CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
 
+#include <string>
+
 #include "base/macros.h"
 #include "content/public/test/test_mojo_service.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -34,6 +36,8 @@
 
   // TestMojoService:
   void DoSomething(const DoSomethingCallback& callback) override;
+  void DoTerminateProcess(const DoTerminateProcessCallback& callback) override;
+  void CreateFolder(const CreateFolderCallback& callback) override;
   void GetRequestorName(const GetRequestorNameCallback& callback) override;
 
   mojo::Binding<mojom::TestMojoService> service_binding_;
@@ -44,6 +48,6 @@
   DISALLOW_COPY_AND_ASSIGN(TestMojoApp);
 };
 
-}  // namespace
+}  // namespace content
 
 #endif  // CONTENT_PUBLIC_TEST_TEST_MOJO_APP_H_
diff --git a/content/public/test/test_mojo_service.mojom b/content/public/test/test_mojo_service.mojom
index ff845e80..06760f13 100644
--- a/content/public/test/test_mojo_service.mojom
+++ b/content/public/test/test_mojo_service.mojom
@@ -8,6 +8,13 @@
   // Doesn't actually do anything, just responds.
   DoSomething() => ();
 
+  // Terminates the current process to cause a connection error. Meant to test
+  // a connection error for the utility process.
+  DoTerminateProcess() => ();
+
+  // Tries to create a temporary folder. Requires a sandbox to succeed.
+  CreateFolder() => (bool succeeded);
+
   // Retrieve the requestor name as seen by the test app providing this service.
   GetRequestorName() => (string name);
 };
diff --git a/content/public/test/test_synchronous_compositor_android.cc b/content/public/test/test_synchronous_compositor_android.cc
index 04afeef..7f9bd23 100644
--- a/content/public/test/test_synchronous_compositor_android.cc
+++ b/content/public/test/test_synchronous_compositor_android.cc
@@ -19,11 +19,10 @@
 
 void TestSynchronousCompositor::SetClient(SynchronousCompositorClient* client) {
   if (client_)
-    client_->DidDestroyCompositor(this);
+    client_->DidDestroyCompositor(this, 0, 0);
   client_ = client;
   if (client_) {
-    client_->DidInitializeCompositor(this);
-    client_->DidBecomeCurrent(this);
+    client_->DidInitializeCompositor(this, 0, 0);
   }
 }
 
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index d87437e2..34ba982 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -762,12 +762,6 @@
 void BlinkTestController::OnOverridePreferences(const WebPreferences& prefs) {
   should_override_prefs_ = true;
   prefs_ = prefs;
-
-  // Notifies the main RenderViewHost that Blink preferences changed so to avoid
-  // re-usage of cached preferences that are now stale.
-  RenderViewHost* main_render_view_host =
-      main_window_->web_contents()->GetRenderViewHost();
-  main_render_view_host->OnWebkitPreferencesChanged();
 }
 
 void BlinkTestController::OnClearDevToolsLocalStorage() {
diff --git a/content/shell/renderer/layout_test/blink_test_helpers.cc b/content/shell/renderer/layout_test/blink_test_helpers.cc
index 376ba18..d686988 100644
--- a/content/shell/renderer/layout_test/blink_test_helpers.cc
+++ b/content/shell/renderer/layout_test/blink_test_helpers.cc
@@ -50,7 +50,6 @@
       from.strict_mixed_content_checking;
   to->strict_powerful_feature_restrictions =
       from.strict_powerful_feature_restrictions;
-  to->spatial_navigation_enabled = from.spatial_navigation_enabled;
 }
 
 // Applies settings that differ between layout tests and regular mode. Some
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc
index 98195872..901ad09 100644
--- a/content/shell/renderer/shell_content_renderer_client.cc
+++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -4,8 +4,11 @@
 
 #include "content/shell/renderer/shell_content_renderer_client.h"
 
+#include <string>
+
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "components/web_cache/renderer/web_cache_impl.h"
 #include "content/public/common/service_registry.h"
@@ -29,7 +32,7 @@
 // A test Mojo service which can be driven by browser tests for various reasons.
 class TestMojoServiceImpl : public mojom::TestMojoService {
  public:
-  TestMojoServiceImpl(mojom::TestMojoServiceRequest request)
+  explicit TestMojoServiceImpl(mojom::TestMojoServiceRequest request)
       : binding_(this, std::move(request)) {
     binding_.set_connection_error_handler(
         base::Bind(&TestMojoServiceImpl::OnConnectionError,
@@ -56,6 +59,14 @@
     OnConnectionError();
   }
 
+  void DoTerminateProcess(const DoTerminateProcessCallback& callback) override {
+    NOTREACHED();
+  }
+
+  void CreateFolder(const CreateFolderCallback& callback) override {
+    NOTREACHED();
+  }
+
   void GetRequestorName(const GetRequestorNameCallback& callback) override {
     callback.Run("Not implemented.");
   }
diff --git a/content/shell/utility/shell_content_utility_client.cc b/content/shell/utility/shell_content_utility_client.cc
index 0ed0358..4200576 100644
--- a/content/shell/utility/shell_content_utility_client.cc
+++ b/content/shell/utility/shell_content_utility_client.cc
@@ -8,8 +8,11 @@
 #include <utility>
 
 #include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/process/process.h"
 #include "content/public/common/service_registry.h"
 #include "content/public/test/test_mojo_app.h"
+#include "content/public/test/test_mojo_service.mojom.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace content {
@@ -27,6 +30,16 @@
     callback.Run();
   }
 
+  void DoTerminateProcess(const DoTerminateProcessCallback& callback) override {
+    base::Process::Current().Terminate(0, false);
+  }
+
+  void CreateFolder(const CreateFolderCallback& callback) override {
+    // Note: This is used to check if the sandbox is disabled or not since
+    //       creating a folder is forbidden when it is enabled.
+    callback.Run(base::ScopedTempDir().CreateUniqueTempDir());
+  }
+
   void GetRequestorName(const GetRequestorNameCallback& callback) override {
     NOTREACHED();
   }
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index a59f6e4f..2ca867a3 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -458,6 +458,7 @@
     "//content/test:test_support",
     "//device/battery",
     "//device/battery:mojo_bindings",
+    "//device/power_save_blocker",
     "//device/vibration:mojo_bindings",
     "//gin",
     "//gpu",
diff --git a/content/test/content_browser_test_utils_internal.cc b/content/test/content_browser_test_utils_internal.cc
index 408bd75..4f974b13 100644
--- a/content/test/content_browser_test_utils_internal.cc
+++ b/content/test/content_browser_test_utils_internal.cc
@@ -24,9 +24,12 @@
 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
 #include "content/browser/renderer_host/delegated_frame_host.h"
 #include "content/browser/renderer_host/render_widget_host_view_base.h"
+#include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/resource_dispatcher_host.h"
 #include "content/public/browser/resource_throttle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/file_chooser_file_info.h"
+#include "content/public/common/file_chooser_params.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_browser_test_utils.h"
 #include "content/shell/browser/shell.h"
@@ -424,4 +427,19 @@
     loop_runner_->Quit();
 }
 
+FileChooserDelegate::FileChooserDelegate(const base::FilePath& file)
+      : file_(file), file_chosen_(false) {}
+
+void FileChooserDelegate::RunFileChooser(RenderFrameHost* render_frame_host,
+                                         const FileChooserParams& params) {
+  // Send the selected file to the renderer process.
+  FileChooserFileInfo file_info;
+  file_info.file_path = file_;
+  std::vector<FileChooserFileInfo> files;
+  files.push_back(file_info);
+  render_frame_host->FilesSelectedInChooser(files, FileChooserParams::Open);
+
+  file_chosen_ = true;
+}
+
 }  // namespace content
diff --git a/content/test/content_browser_test_utils_internal.h b/content/test/content_browser_test_utils_internal.h
index 7596538..64b18e45 100644
--- a/content/test/content_browser_test_utils_internal.h
+++ b/content/test/content_browser_test_utils_internal.h
@@ -13,11 +13,13 @@
 #include <string>
 #include <vector>
 
+#include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "cc/surfaces/surface_id.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "url/gurl.h"
 
@@ -29,6 +31,7 @@
 
 class FrameTreeNode;
 class MessageLoopRunner;
+class RenderFrameHost;
 class RenderWidgetHostViewChildFrame;
 class Shell;
 class SiteInstance;
@@ -175,6 +178,25 @@
   DISALLOW_COPY_AND_ASSIGN(SurfaceHitTestReadyNotifier);
 };
 
+// Helper for mocking choosing a file via a file dialog.
+class FileChooserDelegate : public WebContentsDelegate {
+ public:
+  // Constructs a WebContentsDelegate that mocks a file dialog.
+  // The mocked file dialog will always reply that the user selected |file|.
+  FileChooserDelegate(const base::FilePath& file);
+
+  // Implementation of WebContentsDelegate::RunFileChooser.
+  void RunFileChooser(RenderFrameHost* render_frame_host,
+                      const FileChooserParams& params) override;
+
+  // Whether the file dialog was shown.
+  bool file_chosen() { return file_chosen_; }
+
+ private:
+  base::FilePath file_;
+  bool file_chosen_;
+};
+
 }  // namespace content
 
 #endif  // CONTENT_TEST_CONTENT_BROWSER_TEST_UTILS_INTERNAL_H_
diff --git a/content/test/data/form_that_posts_cross_site.html b/content/test/data/form_that_posts_cross_site.html
new file mode 100644
index 0000000..6317347
--- /dev/null
+++ b/content/test/data/form_that_posts_cross_site.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head></head>
+  <body>
+    <form id="text-form" method="POST" action="/cross-site-307/x.com/echoall">
+      <input type="text" id="text" name="text" value="value">
+      <input type="submit">
+    </form>
+    <form id="file-form" method="POST" action="/cross-site-307/x.com/echoall"
+          enctype="multipart/form-data">
+      <input type="file" id="file" name="file">
+      <input type="submit">
+    </form>
+  </body>
+</html>
diff --git a/content/test/data/session_history/form_that_posts_cross_site.html b/content/test/data/session_history/form_that_posts_cross_site.html
deleted file mode 100644
index 56b51955..0000000
--- a/content/test/data/session_history/form_that_posts_cross_site.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head></head>
-  <body>
-    <form id="form" method="POST" action="/cross-site-307/x.com/echoall">
-      <input type="text" name="text" value="value">
-      <input type="submit">
-    </form>
-  </body>
-</html>
diff --git a/content/test/gpu/gpu_tests/memory_test.py b/content/test/gpu/gpu_tests/memory_test.py
index b6c6870..fc98d75 100644
--- a/content/test/gpu/gpu_tests/memory_test.py
+++ b/content/test/gpu/gpu_tests/memory_test.py
@@ -87,7 +87,7 @@
     # ref builds are updated. crbug.com/386847
     config = tracing_config.TracingConfig()
     for c in ['webkit.console', 'blink.console', 'gpu']:
-      config.tracing_category_filter.AddIncludedCategory(c)
+      config.chrome_trace_config.tracing_category_filter.AddIncludedCategory(c)
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(config, 60)
 
diff --git a/content/test/gpu/gpu_tests/trace_test.py b/content/test/gpu/gpu_tests/trace_test.py
index 4b42a8a..44d235a 100644
--- a/content/test/gpu/gpu_tests/trace_test.py
+++ b/content/test/gpu/gpu_tests/trace_test.py
@@ -68,7 +68,8 @@
   def WillNavigateToPage(self, page, tab):
     config = tracing_config.TracingConfig()
     for cat in TOPLEVEL_CATEGORIES:
-      config.tracing_category_filter.AddDisabledByDefault(cat)
+      config.chrome_trace_config.tracing_category_filter.AddDisabledByDefault(
+          cat)
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(config, 60)
 
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index cd70017..ba8db9e7 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -159,6 +159,8 @@
         ['win', ('amd', 0x6779)], bug=483282)
     self.Fail('deqp/functional/gles3/shadertexturefunction/texturesize.html',
         ['win', ('amd', 0x6779)], bug=483282)
+    self.Fail('deqp/functional/gles3/shadercommonfunction.html',
+        ['win', ('amd', 0x6779)], bug=621201)
 
     # Win / Intel
     self.Fail('conformance2/buffers/uniform-buffers.html',
@@ -245,8 +247,6 @@
     self.Fail('deqp/functional/gles3/vertexarrays.html',
         ['mac'], bug=483282)
 
-    self.Fail('conformance2/reading/read-pixels-from-fbo-test.html',
-        ['mac'], bug=483282)
     self.Fail('conformance2/textures/misc/compressed-tex-image.html',
         ['mac'], bug=565438)
     self.Fail('conformance2/textures/misc/tex-new-formats.html',
@@ -404,6 +404,8 @@
     self.Fail('deqp/functional/gles3/shadertexturefunction/' +
         'texturesize.html',
         ['mac', 'intel'], bug=483282)
+    self.Fail('conformance2/reading/read-pixels-from-fbo-test.html',
+        ['mac', 'intel'], bug=483282)
 
     # Linux only.
     self.Fail('deqp/data/gles3/shaders/functions.html',
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
index 088a0d81..e350789 100644
--- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -379,12 +379,6 @@
     # Fails on all platforms
     self.Fail('deqp/data/gles2/shaders/functions.html',
         bug=478572)
-    # Under the Nexus 5X group is a list of failures for bug 609883.
-    # the ext-sRGB.html bug is failing on the Nexus 5X.
-    # If bug 540900 is fixed, double check whether the Nexus 5X
-    # needs a .Fail added for bug 609883 and ext-sRGB.html.
-    self.Fail('conformance/extensions/ext-sRGB.html',
-        bug=540900)
 
     # We need to add WebGL 1 check in command buffer that format/type from
     # TexSubImage2D have to match the current texture's.
diff --git a/device/power_save_blocker/BUILD.gn b/device/power_save_blocker/BUILD.gn
index abd1856..a4427c1 100644
--- a/device/power_save_blocker/BUILD.gn
+++ b/device/power_save_blocker/BUILD.gn
@@ -15,8 +15,6 @@
     "power_save_blocker_android.cc",
     "power_save_blocker_android.h",
     "power_save_blocker_chromeos.cc",
-    "power_save_blocker_impl.cc",
-    "power_save_blocker_impl.h",
     "power_save_blocker_mac.cc",
     "power_save_blocker_ozone.cc",
     "power_save_blocker_win.cc",
diff --git a/device/power_save_blocker/power_save_blocker.gyp b/device/power_save_blocker/power_save_blocker.gyp
index 23e779ac..75374ba 100644
--- a/device/power_save_blocker/power_save_blocker.gyp
+++ b/device/power_save_blocker/power_save_blocker.gyp
@@ -22,8 +22,6 @@
         # for Android isn't supported.
         'power_save_blocker.h',
         'power_save_blocker_chromeos.cc',
-        'power_save_blocker_impl.cc',
-        'power_save_blocker_impl.h',
         'power_save_blocker_mac.cc',
         'power_save_blocker_ozone.cc',
         'power_save_blocker_win.cc',
diff --git a/device/power_save_blocker/power_save_blocker.h b/device/power_save_blocker/power_save_blocker.h
index 096d816..ff77808 100644
--- a/device/power_save_blocker/power_save_blocker.h
+++ b/device/power_save_blocker/power_save_blocker.h
@@ -9,10 +9,15 @@
 #include <string>
 
 #include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "device/power_save_blocker/power_save_blocker_export.h"
 
+#if defined(OS_ANDROID)
+#include "ui/android/view_android.h"
+#endif  // OS_ANDROID
+
 namespace device {
 
 // A RAII-style class to block the system from entering low-power (sleep) mode.
@@ -44,19 +49,53 @@
     kReasonOther,
   };
 
-  virtual ~PowerSaveBlocker() = 0;
-
   // Pass in the type of power save blocking desired. If multiple types of
   // blocking are desired, instantiate one PowerSaveBlocker for each type.
   // |reason| and |description| (a more-verbose, human-readable justification of
   // the blocking) may be provided to the underlying system APIs on some
   // platforms.
-  static std::unique_ptr<PowerSaveBlocker> CreateWithTaskRunners(
+  PowerSaveBlocker(
       PowerSaveBlockerType type,
       Reason reason,
       const std::string& description,
       scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner);
+  virtual ~PowerSaveBlocker();
+
+#if defined(OS_ANDROID)
+  // On Android, the kPowerSaveBlockPreventDisplaySleep type of
+  // PowerSaveBlocker should associated with a View, so the blocker can be
+  // removed by the platform.
+  DEVICE_POWER_SAVE_BLOCKER_EXPORT void InitDisplaySleepBlocker(
+      const base::WeakPtr<ui::ViewAndroid>& view_android);
+#endif
+
+ private:
+  class Delegate;
+
+  // Implementations of this class may need a second object with different
+  // lifetime than the RAII container, or additional storage. This member is
+  // here for that purpose. If not used, just define the class as an empty
+  // RefCounted (or RefCountedThreadSafe) like so to make it compile:
+  // class PowerSaveBlocker::Delegate
+  //     : public base::RefCounted<PowerSaveBlocker::Delegate> {
+  //  private:
+  //   friend class base::RefCounted<Delegate>;
+  //   ~Delegate() {}
+  // };
+  scoped_refptr<Delegate> delegate_;
+
+#if defined(USE_X11)
+  // Since display sleep prevention also implies system suspend prevention, for
+  // the Linux FreeDesktop API case, there needs to be a second delegate to
+  // block system suspend when screen saver / display sleep is blocked.
+  scoped_refptr<Delegate> freedesktop_suspend_delegate_;
+#endif
+
+  scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
+  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerSaveBlocker);
 };
 
 }  // namespace device
diff --git a/device/power_save_blocker/power_save_blocker_android.cc b/device/power_save_blocker/power_save_blocker_android.cc
index 534ed5d4..252ff02d 100644
--- a/device/power_save_blocker/power_save_blocker_android.cc
+++ b/device/power_save_blocker/power_save_blocker_android.cc
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "device/power_save_blocker/power_save_blocker.h"
+
 #include "base/android/jni_android.h"
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "device/power_save_blocker/power_save_blocker_impl.h"
 #include "jni/PowerSaveBlocker_jni.h"
 #include "ui/android/view_android.h"
 
@@ -15,8 +16,8 @@
 
 using base::android::AttachCurrentThread;
 
-class PowerSaveBlockerImpl::Delegate
-    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+class PowerSaveBlocker::Delegate
+    : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
  public:
   Delegate(base::WeakPtr<ui::ViewAndroid> view_android,
            scoped_refptr<base::SequencedTaskRunner> ui_task_runner);
@@ -38,7 +39,7 @@
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
-PowerSaveBlockerImpl::Delegate::Delegate(
+PowerSaveBlocker::Delegate::Delegate(
     base::WeakPtr<ui::ViewAndroid> view_android,
     scoped_refptr<base::SequencedTaskRunner> ui_task_runner)
     : view_android_(view_android), ui_task_runner_(ui_task_runner) {
@@ -46,9 +47,9 @@
   java_power_save_blocker_.Reset(Java_PowerSaveBlocker_create(env));
 }
 
-PowerSaveBlockerImpl::Delegate::~Delegate() {}
+PowerSaveBlocker::Delegate::~Delegate() {}
 
-void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
+void PowerSaveBlocker::Delegate::ApplyBlock() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
 
   ScopedJavaLocalRef<jobject> obj(java_power_save_blocker_);
@@ -59,7 +60,7 @@
   }
 }
 
-void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
+void PowerSaveBlocker::Delegate::RemoveBlock() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   ScopedJavaLocalRef<jobject> obj(java_power_save_blocker_);
   JNIEnv* env = AttachCurrentThread();
@@ -69,7 +70,7 @@
   }
 }
 
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
+PowerSaveBlocker::PowerSaveBlocker(
     PowerSaveBlockerType type,
     Reason reason,
     const std::string& description,
@@ -80,14 +81,14 @@
   // Don't support kPowerSaveBlockPreventAppSuspension
 }
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
+PowerSaveBlocker::~PowerSaveBlocker() {
   if (delegate_.get()) {
     ui_task_runner_->PostTask(FROM_HERE,
                               base::Bind(&Delegate::RemoveBlock, delegate_));
   }
 }
 
-void PowerSaveBlockerImpl::InitDisplaySleepBlocker(
+void PowerSaveBlocker::InitDisplaySleepBlocker(
     const base::WeakPtr<ui::ViewAndroid>& view_android) {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   if (!view_android)
diff --git a/device/power_save_blocker/power_save_blocker_chromeos.cc b/device/power_save_blocker/power_save_blocker_chromeos.cc
index 31803583c..f24a0fe 100644
--- a/device/power_save_blocker/power_save_blocker_chromeos.cc
+++ b/device/power_save_blocker/power_save_blocker_chromeos.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 
 #include <string>
 
@@ -34,8 +34,8 @@
 
 }  // namespace
 
-class PowerSaveBlockerImpl::Delegate
-    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+class PowerSaveBlocker::Delegate
+    : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
  public:
   Delegate(PowerSaveBlockerType type,
            Reason reason,
@@ -91,7 +91,7 @@
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
+PowerSaveBlocker::PowerSaveBlocker(
     PowerSaveBlockerType type,
     Reason reason,
     const std::string& description,
@@ -104,7 +104,7 @@
                             base::Bind(&Delegate::ApplyBlock, delegate_));
 }
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
+PowerSaveBlocker::~PowerSaveBlocker() {
   ui_task_runner_->PostTask(FROM_HERE,
                             base::Bind(&Delegate::RemoveBlock, delegate_));
 }
diff --git a/device/power_save_blocker/power_save_blocker_impl.cc b/device/power_save_blocker/power_save_blocker_impl.cc
deleted file mode 100644
index c37e6db..0000000
--- a/device/power_save_blocker/power_save_blocker_impl.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "device/power_save_blocker/power_save_blocker_impl.h"
-
-#include "build/build_config.h"
-
-namespace device {
-
-PowerSaveBlocker::~PowerSaveBlocker() {}
-
-// static
-std::unique_ptr<PowerSaveBlocker> PowerSaveBlocker::CreateWithTaskRunners(
-    PowerSaveBlocker::PowerSaveBlockerType type,
-    PowerSaveBlocker::Reason reason,
-    const std::string& description,
-    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
-    scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner) {
-  return std::unique_ptr<PowerSaveBlocker>(new PowerSaveBlockerImpl(
-      type, reason, description, ui_task_runner, blocking_task_runner));
-}
-
-}  // namespace device
diff --git a/device/power_save_blocker/power_save_blocker_impl.h b/device/power_save_blocker/power_save_blocker_impl.h
deleted file mode 100644
index 2f7cadb..0000000
--- a/device/power_save_blocker/power_save_blocker_impl.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_IMPL_H_
-#define DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_IMPL_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
-#include "base/single_thread_task_runner.h"
-#include "build/build_config.h"
-#include "device/power_save_blocker/power_save_blocker.h"
-#include "device/power_save_blocker/power_save_blocker_export.h"
-
-#if defined(OS_ANDROID)
-#include "ui/android/view_android.h"
-#endif  // OS_ANDROID
-
-namespace device {
-
-class WebContents;
-
-class PowerSaveBlockerImpl : public PowerSaveBlocker {
- public:
-  PowerSaveBlockerImpl(
-      PowerSaveBlockerType type,
-      Reason reason,
-      const std::string& description,
-      scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner);
-  ~PowerSaveBlockerImpl() override;
-
-#if defined(OS_ANDROID)
-  // On Android, the kPowerSaveBlockPreventDisplaySleep type of
-  // PowerSaveBlocker should associated with a View, so the blocker can be
-  // removed by the platform.
-  DEVICE_POWER_SAVE_BLOCKER_EXPORT void InitDisplaySleepBlocker(
-      const base::WeakPtr<ui::ViewAndroid>& view_android);
-#endif
-
- private:
-  class Delegate;
-
-  // Implementations of this class may need a second object with different
-  // lifetime than the RAII container, or additional storage. This member is
-  // here for that purpose. If not used, just define the class as an empty
-  // RefCounted (or RefCountedThreadSafe) like so to make it compile:
-  // class PowerSaveBlocker::Delegate
-  //     : public base::RefCounted<PowerSaveBlocker::Delegate> {
-  //  private:
-  //   friend class base::RefCounted<Delegate>;
-  //   ~Delegate() {}
-  // };
-  scoped_refptr<Delegate> delegate_;
-
-#if defined(USE_X11)
-  // Since display sleep prevention also implies system suspend prevention, for
-  // the Linux FreeDesktop API case, there needs to be a second delegate to
-  // block system suspend when screen saver / display sleep is blocked.
-  scoped_refptr<Delegate> freedesktop_suspend_delegate_;
-#endif
-
-  scoped_refptr<base::SequencedTaskRunner> ui_task_runner_;
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerImpl);
-};
-
-}  // namespace device
-
-#endif  // DEVICE_POWER_SAVE_BLOCKER_POWER_SAVE_BLOCKER_IMPL_H_
diff --git a/device/power_save_blocker/power_save_blocker_mac.cc b/device/power_save_blocker/power_save_blocker_mac.cc
index 251cc22..7ecb2316 100644
--- a/device/power_save_blocker/power_save_blocker_mac.cc
+++ b/device/power_save_blocker/power_save_blocker_mac.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 
 #include <IOKit/pwr_mgt/IOPMLib.h>
 
@@ -39,8 +39,8 @@
 
 }  // namespace
 
-class PowerSaveBlockerImpl::Delegate
-    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+class PowerSaveBlocker::Delegate
+    : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
  public:
   Delegate(PowerSaveBlockerType type, const std::string& description)
       : type_(type),
@@ -59,7 +59,7 @@
   IOPMAssertionID assertion_;
 };
 
-void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
+void PowerSaveBlocker::Delegate::ApplyBlock() {
   DCHECK_EQ(base::PlatformThread::CurrentId(),
             g_power_thread.Pointer()->GetThreadId());
 
@@ -87,7 +87,7 @@
   }
 }
 
-void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
+void PowerSaveBlocker::Delegate::RemoveBlock() {
   DCHECK_EQ(base::PlatformThread::CurrentId(),
             g_power_thread.Pointer()->GetThreadId());
 
@@ -98,7 +98,7 @@
   }
 }
 
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
+PowerSaveBlocker::PowerSaveBlocker(
     PowerSaveBlockerType type,
     Reason reason,
     const std::string& description,
@@ -111,7 +111,7 @@
       FROM_HERE, base::Bind(&Delegate::ApplyBlock, delegate_));
 }
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
+PowerSaveBlocker::~PowerSaveBlocker() {
   g_power_thread.Pointer()->message_loop()->PostTask(
       FROM_HERE, base::Bind(&Delegate::RemoveBlock, delegate_));
 }
diff --git a/device/power_save_blocker/power_save_blocker_ozone.cc b/device/power_save_blocker/power_save_blocker_ozone.cc
index caf15a5..981794eb 100644
--- a/device/power_save_blocker/power_save_blocker_ozone.cc
+++ b/device/power_save_blocker/power_save_blocker_ozone.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -13,8 +13,8 @@
 // save is OS-specific, not display-system-specific.  This implementation
 // ends up being used for non-ChromeOS Ozone platforms such as Chromecast.
 // See crbug.com/495661 for more detail.
-class PowerSaveBlockerImpl::Delegate
-    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+class PowerSaveBlocker::Delegate
+    : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
  public:
   Delegate() {}
 
@@ -25,7 +25,7 @@
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
+PowerSaveBlocker::PowerSaveBlocker(
     PowerSaveBlockerType type,
     Reason reason,
     const std::string& description,
@@ -35,6 +35,6 @@
       ui_task_runner_(ui_task_runner),
       blocking_task_runner_(blocking_task_runner) {}
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {}
+PowerSaveBlocker::~PowerSaveBlocker() {}
 
 }  // namespace device
diff --git a/device/power_save_blocker/power_save_blocker_win.cc b/device/power_save_blocker/power_save_blocker_win.cc
index 8464c210..7b0166bd 100644
--- a/device/power_save_blocker/power_save_blocker_win.cc
+++ b/device/power_save_blocker/power_save_blocker_win.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "device/power_save_blocker/power_save_blocker.h"
+
 #include <windows.h>
 
 #include "base/bind.h"
@@ -10,7 +12,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
-#include "device/power_save_blocker/power_save_blocker_impl.h"
 
 namespace device {
 namespace {
@@ -83,8 +84,8 @@
 
 }  // namespace
 
-class PowerSaveBlockerImpl::Delegate
-    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+class PowerSaveBlocker::Delegate
+    : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
  public:
   Delegate(PowerSaveBlockerType type,
            const std::string& description,
@@ -112,7 +113,7 @@
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
-void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
+void PowerSaveBlocker::Delegate::ApplyBlock() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   if (base::win::GetVersion() < base::win::VERSION_WIN7)
     return ApplySimpleBlock(type_, 1);
@@ -120,7 +121,7 @@
   handle_.Set(CreatePowerRequest(RequestType(), description_));
 }
 
-void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
+void PowerSaveBlocker::Delegate::RemoveBlock() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   if (base::win::GetVersion() < base::win::VERSION_WIN7)
     return ApplySimpleBlock(type_, -1);
@@ -128,7 +129,7 @@
   DeletePowerRequest(RequestType(), handle_.Take());
 }
 
-POWER_REQUEST_TYPE PowerSaveBlockerImpl::Delegate::RequestType() {
+POWER_REQUEST_TYPE PowerSaveBlocker::Delegate::RequestType() {
   if (type_ == kPowerSaveBlockPreventDisplaySleep)
     return PowerRequestDisplayRequired;
 
@@ -138,7 +139,7 @@
   return PowerRequestExecutionRequired;
 }
 
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
+PowerSaveBlocker::PowerSaveBlocker(
     PowerSaveBlockerType type,
     Reason reason,
     const std::string& description,
@@ -151,7 +152,7 @@
                             base::Bind(&Delegate::ApplyBlock, delegate_));
 }
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
+PowerSaveBlocker::~PowerSaveBlocker() {
   ui_task_runner_->PostTask(FROM_HERE,
                             base::Bind(&Delegate::RemoveBlock, delegate_));
 }
diff --git a/device/power_save_blocker/power_save_blocker_x11.cc b/device/power_save_blocker/power_save_blocker_x11.cc
index ed66813..286e042 100644
--- a/device/power_save_blocker/power_save_blocker_x11.cc
+++ b/device/power_save_blocker/power_save_blocker_x11.cc
@@ -9,7 +9,8 @@
 
 #include <memory>
 
-#include "device/power_save_blocker/power_save_blocker_impl.h"
+#include "device/power_save_blocker/power_save_blocker.h"
+
 // Xlib #defines Status, but we can't have that for some of our headers.
 #ifdef Status
 #undef Status
@@ -70,8 +71,8 @@
 
 namespace device {
 
-class PowerSaveBlockerImpl::Delegate
-    : public base::RefCountedThreadSafe<PowerSaveBlockerImpl::Delegate> {
+class PowerSaveBlocker::Delegate
+    : public base::RefCountedThreadSafe<PowerSaveBlocker::Delegate> {
  public:
   // Picks an appropriate D-Bus API to use based on the desktop environment.
   Delegate(PowerSaveBlockerType type,
@@ -166,7 +167,7 @@
   DISALLOW_COPY_AND_ASSIGN(Delegate);
 };
 
-PowerSaveBlockerImpl::Delegate::Delegate(
+PowerSaveBlocker::Delegate::Delegate(
     PowerSaveBlockerType type,
     const std::string& description,
     bool freedesktop_only,
@@ -184,7 +185,7 @@
   // object yet. We'll do it later in ApplyBlock(), on the FILE thread.
 }
 
-void PowerSaveBlockerImpl::Delegate::Init() {
+void PowerSaveBlocker::Delegate::Init() {
   base::AutoLock lock(lock_);
   DCHECK(!enqueue_apply_);
   enqueue_apply_ = true;
@@ -195,7 +196,7 @@
                             base::Bind(&Delegate::InitOnUIThread, this));
 }
 
-void PowerSaveBlockerImpl::Delegate::CleanUp() {
+void PowerSaveBlocker::Delegate::CleanUp() {
   base::AutoLock lock(lock_);
   if (enqueue_apply_) {
     // If a call to ApplyBlock() has not yet been enqueued because we are still
@@ -213,7 +214,7 @@
   }
 }
 
-void PowerSaveBlockerImpl::Delegate::InitOnUIThread() {
+void PowerSaveBlocker::Delegate::InitOnUIThread() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   base::AutoLock lock(lock_);
   api_ = SelectAPI();
@@ -232,11 +233,11 @@
   enqueue_apply_ = false;
 }
 
-bool PowerSaveBlockerImpl::Delegate::ShouldBlock() const {
+bool PowerSaveBlocker::Delegate::ShouldBlock() const {
   return freedesktop_only_ ? api_ == FREEDESKTOP_API : api_ != NO_API;
 }
 
-void PowerSaveBlockerImpl::Delegate::ApplyBlock() {
+void PowerSaveBlocker::Delegate::ApplyBlock() {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(!bus_);  // ApplyBlock() should only be called once.
   DCHECK(!block_inflight_);
@@ -313,11 +314,10 @@
   block_inflight_ = true;
   object_proxy->CallMethod(
       method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-      base::Bind(&PowerSaveBlockerImpl::Delegate::ApplyBlockFinished, this));
+      base::Bind(&PowerSaveBlocker::Delegate::ApplyBlockFinished, this));
 }
 
-void PowerSaveBlockerImpl::Delegate::ApplyBlockFinished(
-    dbus::Response* response) {
+void PowerSaveBlocker::Delegate::ApplyBlockFinished(dbus::Response* response) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(bus_);
   DCHECK(block_inflight_);
@@ -343,7 +343,7 @@
   }
 }
 
-void PowerSaveBlockerImpl::Delegate::RemoveBlock() {
+void PowerSaveBlocker::Delegate::RemoveBlock() {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(bus_);  // RemoveBlock() should only be called once.
   DCHECK(!unblock_inflight_);
@@ -394,11 +394,10 @@
   unblock_inflight_ = true;
   object_proxy->CallMethod(
       method_call.get(), dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
-      base::Bind(&PowerSaveBlockerImpl::Delegate::RemoveBlockFinished, this));
+      base::Bind(&PowerSaveBlocker::Delegate::RemoveBlockFinished, this));
 }
 
-void PowerSaveBlockerImpl::Delegate::RemoveBlockFinished(
-    dbus::Response* response) {
+void PowerSaveBlocker::Delegate::RemoveBlockFinished(dbus::Response* response) {
   DCHECK(blocking_task_runner_->RunsTasksOnCurrentThread());
   DCHECK(bus_);
   unblock_inflight_ = false;
@@ -413,7 +412,7 @@
   bus_ = nullptr;
 }
 
-void PowerSaveBlockerImpl::Delegate::XSSSuspendSet(bool suspend) {
+void PowerSaveBlocker::Delegate::XSSSuspendSet(bool suspend) {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
 
   if (!XSSAvailable())
@@ -423,7 +422,7 @@
   XScreenSaverSuspend(display, suspend);
 }
 
-bool PowerSaveBlockerImpl::Delegate::DPMSEnabled() {
+bool PowerSaveBlocker::Delegate::DPMSEnabled() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   XDisplay* display = gfx::GetXDisplay();
   BOOL enabled = false;
@@ -435,7 +434,7 @@
   return enabled;
 }
 
-bool PowerSaveBlockerImpl::Delegate::XSSAvailable() {
+bool PowerSaveBlocker::Delegate::XSSAvailable() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   XDisplay* display = gfx::GetXDisplay();
   int dummy;
@@ -451,7 +450,7 @@
   return major > 1 || (major == 1 && minor >= 1);
 }
 
-DBusAPI PowerSaveBlockerImpl::Delegate::SelectAPI() {
+DBusAPI PowerSaveBlocker::Delegate::SelectAPI() {
   DCHECK(ui_task_runner_->RunsTasksOnCurrentThread());
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   switch (base::nix::GetDesktopEnvironment(env.get())) {
@@ -474,7 +473,7 @@
   return NO_API;
 }
 
-PowerSaveBlockerImpl::PowerSaveBlockerImpl(
+PowerSaveBlocker::PowerSaveBlocker(
     PowerSaveBlockerType type,
     Reason reason,
     const std::string& description,
@@ -497,7 +496,7 @@
   }
 }
 
-PowerSaveBlockerImpl::~PowerSaveBlockerImpl() {
+PowerSaveBlocker::~PowerSaveBlocker() {
   delegate_->CleanUp();
   if (freedesktop_suspend_delegate_)
     freedesktop_suspend_delegate_->CleanUp();
diff --git a/extensions/browser/api/power/power_api.cc b/extensions/browser/api/power/power_api.cc
index 8190896..62cb736 100644
--- a/extensions/browser/api/power/power_api.cc
+++ b/extensions/browser/api/power/power_api.cc
@@ -34,6 +34,16 @@
 base::LazyInstance<BrowserContextKeyedAPIFactory<PowerAPI>> g_factory =
     LAZY_INSTANCE_INITIALIZER;
 
+std::unique_ptr<device::PowerSaveBlocker> CreatePowerSaveBlocker(
+    device::PowerSaveBlocker::PowerSaveBlockerType type,
+    device::PowerSaveBlocker::Reason reason,
+    const std::string& description,
+    scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+    scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) {
+  return std::unique_ptr<device::PowerSaveBlocker>(new device::PowerSaveBlocker(
+      type, reason, description, ui_task_runner, file_task_runner));
+}
+
 }  // namespace
 
 bool PowerRequestKeepAwakeFunction::RunSync() {
@@ -74,9 +84,7 @@
 void PowerAPI::SetCreateBlockerFunctionForTesting(
     CreateBlockerFunction function) {
   create_blocker_function_ =
-      !function.is_null()
-          ? function
-          : base::Bind(&device::PowerSaveBlocker::CreateWithTaskRunners);
+      !function.is_null() ? function : base::Bind(&CreatePowerSaveBlocker);
 }
 
 void PowerAPI::OnExtensionUnloaded(content::BrowserContext* browser_context,
@@ -88,8 +96,7 @@
 
 PowerAPI::PowerAPI(content::BrowserContext* context)
     : browser_context_(context),
-      create_blocker_function_(
-          base::Bind(&device::PowerSaveBlocker::CreateWithTaskRunners)),
+      create_blocker_function_(base::Bind(&CreatePowerSaveBlocker)),
       current_level_(api::power::LEVEL_SYSTEM) {
   ExtensionRegistry::Get(browser_context_)->AddObserver(this);
 }
diff --git a/extensions/browser/api/power/power_api_unittest.cc b/extensions/browser/api/power/power_api_unittest.cc
index 06e4d8f3..da6ca03 100644
--- a/extensions/browser/api/power/power_api_unittest.cc
+++ b/extensions/browser/api/power/power_api_unittest.cc
@@ -42,9 +42,16 @@
 // destruction.
 class PowerSaveBlockerStub : public device::PowerSaveBlocker {
  public:
-  explicit PowerSaveBlockerStub(base::Closure unblock_callback)
-      : unblock_callback_(unblock_callback) {
-  }
+  PowerSaveBlockerStub(
+      base::Closure unblock_callback,
+      scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
+      scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner)
+      : PowerSaveBlocker(PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension,
+                         PowerSaveBlocker::kReasonOther,
+                         "test",
+                         ui_task_runner,
+                         blocking_task_runner),
+        unblock_callback_(unblock_callback) {}
 
   ~PowerSaveBlockerStub() override { unblock_callback_.Run(); }
 
@@ -93,7 +100,7 @@
       device::PowerSaveBlocker::Reason reason,
       const std::string& description,
       scoped_refptr<base::SequencedTaskRunner> ui_task_runner,
-      scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) {
+      scoped_refptr<base::SingleThreadTaskRunner> blocking_task_runner) {
     Request unblock_request = NONE;
     switch (type) {
       case device::PowerSaveBlocker::kPowerSaveBlockPreventAppSuspension:
@@ -107,7 +114,8 @@
     }
     return std::unique_ptr<device::PowerSaveBlocker>(new PowerSaveBlockerStub(
         base::Bind(&PowerSaveBlockerStubManager::AppendRequest,
-                   weak_ptr_factory_.GetWeakPtr(), unblock_request)));
+                   weak_ptr_factory_.GetWeakPtr(), unblock_request),
+        ui_task_runner, blocking_task_runner));
   }
 
   void AppendRequest(Request request) {
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index ee805dd..0371fb1 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -136,7 +136,8 @@
       ext_render_buffer_format_bgra8888(false),
       ext_multisample_compatibility(false),
       ext_blend_func_extended(false),
-      ext_read_format_bgra(false) {}
+      ext_read_format_bgra(false),
+      desktop_srgb_support(false) {}
 
 FeatureInfo::FeatureInfo() {
   InitializeBasicState(base::CommandLine::InitializedForCurrentProcess()
@@ -542,6 +543,12 @@
     validators_.index_type.AddValue(GL_UNSIGNED_INT);
   }
 
+  if (gl_version_info_->IsAtLeastGL(3, 2) ||
+      (gl_version_info_->IsAtLeastGL(2, 0) &&
+       (extensions.Contains("GL_EXT_framebuffer_sRGB") ||
+        extensions.Contains("GL_ARB_framebuffer_sRGB")))) {
+    feature_flags_.desktop_srgb_support = true;
+  }
   // With EXT_sRGB, unsized SRGB_EXT and SRGB_ALPHA_EXT are accepted by the
   // <format> and <internalformat> parameter of TexImage2D. GLES3 adds support
   // for SRGB Textures but the accepted internal formats for TexImage2D are only
@@ -551,7 +558,7 @@
   if ((((gl_version_info_->is_es3 ||
          extensions.Contains("GL_OES_rgb8_rgba8")) &&
         extensions.Contains("GL_EXT_sRGB")) ||
-       gl::HasDesktopGLFeatures()) &&
+       feature_flags_.desktop_srgb_support) &&
       (context_type_ == CONTEXT_TYPE_WEBGL1 ||
        context_type_ == CONTEXT_TYPE_OPENGLES2)) {
     AddExtensionString("GL_EXT_sRGB");
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index c8ea959f..cd0bab9 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -90,6 +90,7 @@
     bool ext_multisample_compatibility;
     bool ext_blend_func_extended;
     bool ext_read_format_bgra;
+    bool desktop_srgb_support;
   };
 
   FeatureInfo();
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index bd4a465..dafe9d3 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -232,6 +232,47 @@
   EXPECT_THAT(info_->extensions(), HasSubstr("GL_CHROMIUM_trace_marker"));
   EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_unpack_subimage"));
 
+  bool expect_ext_srgb = false;
+  switch (GetParam()) {
+    case ES2_on_Version3_0:
+    case ES3_on_Version3_0:
+    case ES3_on_Version3_2Compatibility:
+      break;
+    case ES2_on_Version3_2Compatibility:
+      // sRGB features are available as core GL 3.2.
+      expect_ext_srgb = true;
+      break;
+    default:
+      NOTREACHED();
+      break;
+  }
+  if (expect_ext_srgb) {
+    EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_sRGB"));
+    EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT));
+    EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_SRGB_ALPHA_EXT));
+    EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+        GL_SRGB_EXT));
+    EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+        GL_SRGB_ALPHA_EXT));
+    EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+        GL_SRGB8_ALPHA8_EXT));
+    EXPECT_TRUE(info_->validators()->frame_buffer_parameter.IsValid(
+        GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
+  } else {
+    EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_EXT_sRGB")));
+    EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_SRGB_EXT));
+    EXPECT_FALSE(info_->validators()->texture_format.IsValid(
+        GL_SRGB_ALPHA_EXT));
+    EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+        GL_SRGB_EXT));
+    EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+        GL_SRGB_ALPHA_EXT));
+    EXPECT_FALSE(info_->validators()->render_buffer_format.IsValid(
+        GL_SRGB8_ALPHA8_EXT));
+    EXPECT_FALSE(info_->validators()->frame_buffer_parameter.IsValid(
+        GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
+  }
+
   // Check a couple of random extensions that should not be there.
   EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_npot")));
   EXPECT_THAT(info_->extensions(),
@@ -250,8 +291,6 @@
               Not(HasSubstr("GL_AMD_compressed_ATC_texture")));
   EXPECT_THAT(info_->extensions(),
               Not(HasSubstr("GL_IMG_texture_compression_pvrtc")));
-  EXPECT_THAT(info_->extensions(),
-              Not(HasSubstr("GL_EXT_sRGB")));
   EXPECT_FALSE(info_->feature_flags().npot_ok);
   EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
       GL_COMPRESSED_RGB_S3TC_DXT1_EXT));
@@ -319,18 +358,6 @@
   EXPECT_FALSE(info_->validators()->equation.IsValid(GL_MIN_EXT));
   EXPECT_FALSE(info_->validators()->equation.IsValid(GL_MAX_EXT));
   EXPECT_FALSE(info_->feature_flags().chromium_sync_query);
-  EXPECT_FALSE(info_->validators()->texture_format.IsValid(
-      GL_SRGB_EXT));
-  EXPECT_FALSE(info_->validators()->texture_format.IsValid(
-      GL_SRGB_ALPHA_EXT));
-  EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
-      GL_SRGB_EXT));
-  EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
-      GL_SRGB_ALPHA_EXT));
-  EXPECT_FALSE(info_->validators()->render_buffer_format.IsValid(
-      GL_SRGB8_ALPHA8_EXT));
-  EXPECT_FALSE(info_->validators()->frame_buffer_parameter.IsValid(
-      GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT));
   EXPECT_FALSE(info_->feature_flags().chromium_image_ycbcr_422);
 }
 
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index e6cd445..1790ad9d 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -317,6 +317,7 @@
       have_context_(true),
       max_draw_buffers_(max_draw_buffers),
       max_color_attachments_(max_color_attachments),
+      framebuffer_srgb_(false),
       context_type_(context_type),
       framebuffer_combo_complete_cache_(framebuffer_combo_complete_cache) {
   DCHECK_GT(max_draw_buffers_, 0u);
@@ -339,6 +340,32 @@
   }
 }
 
+void FramebufferManager::UpdateFramebufferSRGBSetting(
+    const FeatureInfo* feature_info, Framebuffer* framebuffer) {
+  if (!feature_info->feature_flags().desktop_srgb_support)
+    return;
+
+  if (framebuffer) {
+    DCHECK(IsComplete(framebuffer));
+
+    bool has_srgb_attachments = framebuffer->HasSRGBAttachments();
+    if (framebuffer_srgb_ == has_srgb_attachments)
+      return;
+    framebuffer_srgb_ = has_srgb_attachments;
+    if (framebuffer_srgb_)
+      glEnable(GL_FRAMEBUFFER_SRGB);
+    else
+      glDisable(GL_FRAMEBUFFER_SRGB);
+  } else {
+    // Default fbo, always disable FRAMEBUFFER_SRGB.
+    // TODO(zmo): is there a case where default fbo is sRGB image?
+    if (!framebuffer_srgb_)
+      return;
+    framebuffer_srgb_ = false;
+    glDisable(GL_FRAMEBUFFER_SRGB);
+  }
+}
+
 void FramebufferManager::Destroy(bool have_context) {
   have_context_ = have_context;
   framebuffers_.clear();
@@ -453,6 +480,23 @@
   }
 }
 
+bool Framebuffer::HasSRGBAttachments() const {
+  for (AttachmentMap::const_iterator it = attachments_.begin();
+       it != attachments_.end(); ++it) {
+    GLenum internal_format = it->second->internal_format();
+    switch (internal_format) {
+      case GL_SRGB8:
+      case GL_SRGB8_ALPHA8:
+      case GL_SRGB_EXT:
+      case GL_SRGB_ALPHA_EXT:
+        return true;
+      default:
+        break;
+    }
+  }
+  return false;
+}
+
 bool Framebuffer::PrepareDrawBuffersForClear() const {
   std::unique_ptr<GLenum[]> buffers(new GLenum[manager_->max_draw_buffers_]);
   for (uint32_t i = 0; i < manager_->max_draw_buffers_; ++i)
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 30b478c..699d90a 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -84,6 +84,8 @@
   bool HasUnclearedAttachment(GLenum attachment) const;
   bool HasUnclearedColorAttachments() const;
 
+  bool HasSRGBAttachments() const;
+
   void ClearUnclearedIntOr3DTexturesOrPartiallyClearedTextures(
       GLES2Decoder* decoder,
       TextureManager* texture_manager);
@@ -298,6 +300,15 @@
 
   ContextType context_type() const { return context_type_; }
 
+  // If framebuffer contains sRGB images, then enable FRAMEBUFFER_SRGB.
+  // Otherwise, disable FRAMEBUFFER_SRGB.
+  // In theory, we can just leave FRAMEBUFFER_SRGB on. However, many drivers
+  // behave incorrectly when all images are linear encoding, they still apply
+  // the sRGB conversion, but when at least one image is sRGB, then they behave
+  // correctly.
+  void UpdateFramebufferSRGBSetting(
+      const FeatureInfo* feature_info, Framebuffer* framebuffer);
+
  private:
   friend class Framebuffer;
 
@@ -326,6 +337,8 @@
   uint32_t max_draw_buffers_;
   uint32_t max_color_attachments_;
 
+  bool framebuffer_srgb_;
+
   ContextType context_type_;
 
   scoped_refptr<FramebufferCompletenessCache> framebuffer_combo_complete_cache_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 71ee18f..0ecd8f3 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3964,6 +3964,10 @@
       GL_INVALID_FRAMEBUFFER_OPERATION, func_name);
   if (valid && !features().chromium_framebuffer_multisample)
     OnUseFramebuffer();
+  if (valid) {
+    framebuffer_manager()->UpdateFramebufferSRGBSetting(
+        feature_info_.get(), framebuffer);
+  }
   return valid;
 }
 
diff --git a/media/filters/frame_processor_unittest.cc b/media/filters/frame_processor_unittest.cc
index ec48d0f..7f636e56 100644
--- a/media/filters/frame_processor_unittest.cc
+++ b/media/filters/frame_processor_unittest.cc
@@ -85,15 +85,13 @@
       CreateAndConfigureStream(DemuxerStream::AUDIO);
       ASSERT_TRUE(audio_);
       EXPECT_TRUE(frame_processor_->AddTrack(audio_id_, audio_.get()));
-      audio_->Seek(base::TimeDelta());
-      audio_->StartReturningData();
+      seek(audio_.get(), base::TimeDelta());
     }
     if (has_video) {
       CreateAndConfigureStream(DemuxerStream::VIDEO);
       ASSERT_TRUE(video_);
       EXPECT_TRUE(frame_processor_->AddTrack(video_id_, video_.get()));
-      video_->Seek(base::TimeDelta());
-      video_->StartReturningData();
+      seek(video_.get(), base::TimeDelta());
     }
   }
 
@@ -252,6 +250,12 @@
            kNoDecodeTimestamp();
   }
 
+  void seek(ChunkDemuxerStream* stream, base::TimeDelta seek_time) {
+    stream->AbortReads();
+    stream->Seek(seek_time);
+    stream->StartReturningData();
+  }
+
   base::MessageLoop message_loop_;
   StrictMock<FrameProcessorTestCallbackHelper> callbacks_;
 
@@ -509,12 +513,9 @@
   } else {
     CheckExpectedRangesByTimestamp(audio_.get(), "{ [0,40) }");
     EXPECT_EQ(base::TimeDelta(), timestamp_offset_);
-    // TODO(wolenetz): Fix this need to seek to 0ms, possibly by having
-    // SourceBufferStream defer initial seek until next read. See
-    // http://crbug.com/371493.
-    audio_->AbortReads();
-    audio_->Seek(base::TimeDelta());
-    audio_->StartReturningData();
+    // Re-seek to 0ms now that we've appended data earlier than what has already
+    // satisfied our initial seek to start, above.
+    seek(audio_.get(), base::TimeDelta());
     CheckReadsThenReadStalls(audio_.get(), "0 10 20 30");
   }
 }
@@ -576,9 +577,7 @@
     CheckExpectedRangesByTimestamp(video_.get(), "{ [0,20) [50,60) }");
     CheckReadsThenReadStalls(audio_.get(), "0 10 30 40 50");
     CheckReadsThenReadStalls(video_.get(), "0 10");
-    video_->AbortReads();
-    video_->Seek(frame_duration_ * 5);
-    video_->StartReturningData();
+    seek(video_.get(), frame_duration_ * 5);
     CheckReadsThenReadStalls(video_.get(), "50");
   }
 }
@@ -655,12 +654,10 @@
   }
 
   // Verify the buffers.
-  audio_->AbortReads();
-  audio_->Seek(fifty_five_ms);
-  audio_->StartReturningData();
-  video_->AbortReads();
-  video_->Seek(fifty_five_ms);
-  video_->StartReturningData();
+  // Re-seek now that we've appended data earlier than what already satisfied
+  // our initial seek to start.
+  seek(audio_.get(), fifty_five_ms);
+  seek(video_.get(), fifty_five_ms);
   if (using_sequence_mode) {
     CheckReadsThenReadStalls(
         audio_.get(),
@@ -671,20 +668,12 @@
   } else {
     CheckReadsThenReadStalls(audio_.get(), "55:0 65:10 75:20");
     CheckReadsThenReadStalls(video_.get(), "65:10 75:20 85:30");
-    audio_->AbortReads();
-    audio_->Seek(frame_duration_ * 10);
-    audio_->StartReturningData();
-    video_->AbortReads();
-    video_->Seek(frame_duration_ * 10);
-    video_->StartReturningData();
+    seek(audio_.get(), frame_duration_ * 10);
+    seek(video_.get(), frame_duration_ * 10);
     CheckReadsThenReadStalls(audio_.get(), "100:0 110:10 120:20");
     CheckReadsThenReadStalls(video_.get(), "110:10 120:20 130:30");
-    audio_->AbortReads();
-    audio_->Seek(frame_duration_ * 20);
-    audio_->StartReturningData();
-    video_->AbortReads();
-    video_->Seek(frame_duration_ * 20);
-    video_->StartReturningData();
+    seek(audio_.get(), frame_duration_ * 20);
+    seek(video_.get(), frame_duration_ * 20);
     CheckReadsThenReadStalls(audio_.get(), "200:0 210:10 220:20");
     CheckReadsThenReadStalls(video_.get(), "210:10 220:20 230:30");
   }
@@ -871,9 +860,7 @@
   // Abort the reads from last stall. We don't want those reads to "complete"
   // when we append below. We will initiate new reads to confirm the buffer
   // looks as we expect.
-  audio_->AbortReads();
-  audio_->Seek(base::TimeDelta());
-  audio_->StartReturningData();
+  seek(audio_.get(), base::TimeDelta());
 
   // Append a frame with 10ms duration, with 9ms falling after the window start.
   base::TimeDelta expected_duration =
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 68f9f82ebd..bbfa699 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -194,6 +194,14 @@
     return;
   }
 
+  // TODO(sandersd): This should be moved to capabilities if we ever have a
+  // hardware decoder which supports alpha formats.
+  if (config.format() == PIXEL_FORMAT_YV12A) {
+    DVLOG(1) << "Alpha transparency formats are not supported.";
+    bound_init_cb.Run(false);
+    return;
+  }
+
   VideoDecodeAccelerator::Capabilities capabilities =
       factories_->GetVideoDecodeAcceleratorCapabilities();
   if (!IsProfileSupported(capabilities, config.profile(), config.coded_size(),
diff --git a/media/mojo/services/mojo_media_application.cc b/media/mojo/services/mojo_media_application.cc
index d1e8f8b..70e53cfe 100644
--- a/media/mojo/services/mojo_media_application.cc
+++ b/media/mojo/services/mojo_media_application.cc
@@ -48,10 +48,9 @@
     shell::Connection* connection,
     mojo::InterfaceRequest<mojom::ServiceFactory> request) {
   // The created object is owned by the pipe.
-  new ServiceFactoryImpl(
-      std::move(request),
-      connection->GetInterfaceRegistry()->GetRemoteInterfaces(), media_log_,
-      ref_factory_.CreateRef(), mojo_media_client_.get());
+  new ServiceFactoryImpl(std::move(request),
+                         connection->GetRemoteInterfaceProvider(), media_log_,
+                         ref_factory_.CreateRef(), mojo_media_client_.get());
 }
 
 }  // namespace media
diff --git a/media/renderers/audio_renderer_impl.cc b/media/renderers/audio_renderer_impl.cc
index c7e63e07..a1cbd485 100644
--- a/media/renderers/audio_renderer_impl.cc
+++ b/media/renderers/audio_renderer_impl.cc
@@ -14,6 +14,7 @@
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "base/power_monitor/power_monitor.h"
 #include "base/single_thread_task_runner.h"
 #include "base/time/default_tick_clock.h"
 #include "build/build_config.h"
@@ -55,16 +56,39 @@
       pending_read_(false),
       received_end_of_stream_(false),
       rendered_end_of_stream_(false),
+      is_suspending_(false),
       weak_factory_(this) {
   audio_buffer_stream_->set_splice_observer(base::Bind(
       &AudioRendererImpl::OnNewSpliceBuffer, weak_factory_.GetWeakPtr()));
   audio_buffer_stream_->set_config_change_observer(base::Bind(
       &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr()));
+
+  // Tests may not have a power monitor.
+  base::PowerMonitor* monitor = base::PowerMonitor::Get();
+  if (!monitor)
+    return;
+
+  // PowerObserver's must be added and removed from the same thread, but we
+  // won't remove the observer until we're destructed on |task_runner_| so we
+  // must post it here if we're on the wrong thread.
+  if (task_runner_->BelongsToCurrentThread()) {
+    monitor->AddObserver(this);
+  } else {
+    // Safe to post this without a WeakPtr because this class must be destructed
+    // on the same thread and construction has not completed yet.
+    task_runner_->PostTask(FROM_HERE,
+                           base::Bind(&base::PowerMonitor::AddObserver,
+                                      base::Unretained(monitor), this));
+  }
+  // Do not add anything below this line since the above actions are only safe
+  // as the last lines of the constructor.
 }
 
 AudioRendererImpl::~AudioRendererImpl() {
   DVLOG(1) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
+  if (base::PowerMonitor::Get())
+    base::PowerMonitor::Get()->RemoveObserver(this);
 
   // If Render() is in progress, this call will wait for Render() to finish.
   // After this call, the |sink_| will not call back into |this| anymore.
@@ -189,7 +213,7 @@
   const double playback_rate = playback_rate_ ? playback_rate_ : 1.0;
   const bool is_time_moving = sink_playing_ && playback_rate_ &&
                               !last_render_time_.is_null() &&
-                              stop_rendering_time_.is_null();
+                              stop_rendering_time_.is_null() && !is_suspending_;
 
   // Pre-compute the time until playback of the audio buffer extents, since
   // these values are frequently used below.
@@ -501,6 +525,16 @@
   sink_->SetVolume(volume);
 }
 
+void AudioRendererImpl::OnSuspend() {
+  base::AutoLock auto_lock(lock_);
+  is_suspending_ = true;
+}
+
+void AudioRendererImpl::OnResume() {
+  base::AutoLock auto_lock(lock_);
+  is_suspending_ = false;
+}
+
 void AudioRendererImpl::DecodedAudioReady(
     AudioBufferStream::Status status,
     const scoped_refptr<AudioBuffer>& buffer) {
@@ -751,7 +785,7 @@
       return 0;
     }
 
-    if (playback_rate_ == 0) {
+    if (playback_rate_ == 0 || is_suspending_) {
       audio_clock_->WroteAudio(0, frames_requested, frames_delayed,
                                playback_rate_);
       return 0;
diff --git a/media/renderers/audio_renderer_impl.h b/media/renderers/audio_renderer_impl.h
index 5f6f3b5..c036727 100644
--- a/media/renderers/audio_renderer_impl.h
+++ b/media/renderers/audio_renderer_impl.h
@@ -26,6 +26,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "base/power_monitor/power_observer.h"
 #include "base/synchronization/lock.h"
 #include "media/base/audio_decoder.h"
 #include "media/base/audio_renderer.h"
@@ -53,6 +54,7 @@
 class MEDIA_EXPORT AudioRendererImpl
     : public AudioRenderer,
       public TimeSource,
+      public base::PowerObserver,
       NON_EXPORTED_BASE(public AudioRendererSink::RenderCallback) {
  public:
   // |task_runner| is the thread on which AudioRendererImpl will execute.
@@ -87,6 +89,10 @@
   void StartPlaying() override;
   void SetVolume(float volume) override;
 
+  // base::PowerObserver implementation.
+  void OnSuspend() override;
+  void OnResume() override;
+
  private:
   friend class AudioRendererImplTest;
 
@@ -285,6 +291,10 @@
   // reported to JavaScript from going backwards in time.
   base::TimeDelta last_media_timestamp_;
 
+  // Set by OnSuspend() and OnResume() to indicate when the system is about to
+  // suspend/is suspended and when it resumes.
+  bool is_suspending_;
+
   // End variables which must be accessed under |lock_|. ----------------------
 
   // NOTE: Weak pointers must be invalidated before all other member variables.
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 04b728b..e14de77 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -748,6 +748,33 @@
     ASSERT_NE(0.0f, bus->channel(0)[i]);
 }
 
+TEST_F(AudioRendererImplTest, RenderingDelayedForSuspend) {
+  Initialize();
+  Preroll(base::TimeDelta(), base::TimeDelta(), PIPELINE_OK);
+  StartTicking();
+
+  // Verify the first buffer is real data.
+  int frames_read = 0;
+  std::unique_ptr<AudioBus> bus = AudioBus::Create(hardware_params_);
+  EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read));
+  EXPECT_NE(0, frames_read);
+  for (int i = 0; i < bus->frames(); ++i)
+    ASSERT_NE(0.0f, bus->channel(0)[i]);
+
+  // Verify after suspend we get silence.
+  renderer_->OnSuspend();
+  EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read));
+  EXPECT_EQ(0, frames_read);
+
+  // Verify after resume we get audio.
+  bus->Zero();
+  renderer_->OnResume();
+  EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read));
+  EXPECT_NE(0, frames_read);
+  for (int i = 0; i < bus->frames(); ++i)
+    ASSERT_NE(0.0f, bus->channel(0)[i]);
+}
+
 TEST_F(AudioRendererImplTest, RenderingDelayDoesNotOverflow) {
   Initialize();
 
@@ -859,6 +886,16 @@
             ConvertMediaTime(base::TimeDelta(), &is_time_moving));
   EXPECT_TRUE(is_time_moving);
 
+  // A system suspend should freeze the time state and resume restart it.
+  renderer_->OnSuspend();
+  EXPECT_EQ(tick_clock_->NowTicks(),
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_FALSE(is_time_moving);
+  renderer_->OnResume();
+  EXPECT_EQ(tick_clock_->NowTicks(),
+            ConvertMediaTime(base::TimeDelta(), &is_time_moving));
+  EXPECT_TRUE(is_time_moving);
+
   // Consume some more audio data.
   frames_to_consume = frames_buffered();
   tick_clock_->Advance(
diff --git a/mojo/edk/system/node_controller.cc b/mojo/edk/system/node_controller.cc
index 2368dab2..a1fe420 100644
--- a/mojo/edk/system/node_controller.cc
+++ b/mojo/edk/system/node_controller.cc
@@ -202,6 +202,14 @@
   platform_handle = broker_->GetParentPlatformHandle();
   UMA_HISTOGRAM_TIMES("Mojo.System.GetParentPlatformHandleSyncTime",
                       timer.Elapsed());
+
+  if (!platform_handle.is_valid()) {
+    // Most likely the browser side of the channel has already been closed and
+    // the broker was unable to negotiate a NodeChannel pipe. In this case we
+    // can cancel parent connection.
+    DVLOG(1) << "Cannot connect to invalid parent channel.";
+    return;
+  }
 #endif
 
   io_task_runner_->PostTask(
diff --git a/mojo/public/cpp/bindings/lib/serialization.h b/mojo/public/cpp/bindings/lib/serialization.h
index 1cda65235..b079c18d 100644
--- a/mojo/public/cpp/bindings/lib/serialization.h
+++ b/mojo/public/cpp/bindings/lib/serialization.h
@@ -5,14 +5,18 @@
 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_
 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_
 
+#include <string.h>
+
 #include "mojo/public/cpp/bindings/array_traits_carray.h"
 #include "mojo/public/cpp/bindings/array_traits_standard.h"
 #include "mojo/public/cpp/bindings/array_traits_stl.h"
 #include "mojo/public/cpp/bindings/lib/array_serialization.h"
+#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
 #include "mojo/public/cpp/bindings/lib/map_serialization.h"
 #include "mojo/public/cpp/bindings/lib/native_enum_serialization.h"
 #include "mojo/public/cpp/bindings/lib/native_struct_serialization.h"
 #include "mojo/public/cpp/bindings/lib/string_serialization.h"
+#include "mojo/public/cpp/bindings/lib/template_util.h"
 #include "mojo/public/cpp/bindings/map_traits_standard.h"
 #include "mojo/public/cpp/bindings/map_traits_stl.h"
 #include "mojo/public/cpp/bindings/string_traits_standard.h"
@@ -20,4 +24,89 @@
 #include "mojo/public/cpp/bindings/string_traits_string16.h"
 #include "mojo/public/cpp/bindings/string_traits_string_piece.h"
 
+namespace mojo {
+namespace internal {
+
+template <typename MojomType, typename DataArrayType, typename UserType>
+DataArrayType StructSerializeImpl(UserType* input) {
+  static_assert(IsSpecializationOf<StructPtr, MojomType>::value ||
+                    IsSpecializationOf<InlinedStructPtr, MojomType>::value,
+                "Unexpected type.");
+
+  SerializationContext context;
+  size_t size = PrepareToSerialize<MojomType>(*input, &context);
+  DCHECK_EQ(size, Align(size));
+
+  DataArrayType result(size);
+  if (size == 0)
+    return result;
+
+  void* result_buffer = &result.front();
+  // The serialization logic requires that the buffer is 8-byte aligned. If the
+  // result buffer is not properly aligned, we have to do an extra copy. In
+  // practice, this should never happen for mojo::Array (backed by std::vector).
+  bool need_copy = !IsAligned(result_buffer);
+
+  if (need_copy) {
+    // calloc sets the memory to all zero.
+    result_buffer = calloc(size, 1);
+    DCHECK(IsAligned(result_buffer));
+  }
+
+  FixedBuffer buffer;
+  buffer.Initialize(result_buffer, size);
+  typename MojomType::Struct::Data_* data = nullptr;
+  Serialize<MojomType>(*input, &buffer, &data, &context);
+
+  data->EncodePointers();
+
+  if (need_copy) {
+    memcpy(&result.front(), result_buffer, size);
+    free(result_buffer);
+  }
+
+  return result;
+}
+
+template <typename MojomType, typename DataArrayType, typename UserType>
+bool StructDeserializeImpl(DataArrayType input, UserType* output) {
+  static_assert(IsSpecializationOf<StructPtr, MojomType>::value ||
+                    IsSpecializationOf<InlinedStructPtr, MojomType>::value,
+                "Unexpected type.");
+  using DataType = typename MojomType::Struct::Data_;
+
+  if (input.is_null())
+    return false;
+
+  void* input_buffer = input.empty() ? nullptr : &input.front();
+
+  // Please see comments in StructSerializeImpl.
+  bool need_copy = !IsAligned(input_buffer);
+
+  if (need_copy) {
+    input_buffer = malloc(input.size());
+    DCHECK(IsAligned(input_buffer));
+    memcpy(input_buffer, &input.front(), input.size());
+  }
+
+  ValidationContext validation_context(input_buffer, input.size(), 0);
+  bool result = false;
+  if (DataType::Validate(input_buffer, &validation_context)) {
+    auto data = reinterpret_cast<DataType*>(input_buffer);
+    if (data)
+      data->DecodePointers();
+
+    SerializationContext context;
+    result = Deserialize<MojomType>(data, output, &context);
+  }
+
+  if (need_copy)
+    free(input_buffer);
+
+  return result;
+}
+
+}  // namespace internal
+}  // namespace mojo
+
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_SERIALIZATION_H_
diff --git a/mojo/public/cpp/bindings/struct_ptr.h b/mojo/public/cpp/bindings/struct_ptr.h
index ab5d570..92f2728a 100644
--- a/mojo/public/cpp/bindings/struct_ptr.h
+++ b/mojo/public/cpp/bindings/struct_ptr.h
@@ -26,9 +26,10 @@
 }  // namespace internal
 
 // Smart pointer wrapping a mojom structure with move-only semantics.
-template <typename Struct>
+template <typename S>
 class StructPtr {
  public:
+  using Struct = S;
 
   StructPtr() : ptr_(nullptr) {}
   StructPtr(decltype(nullptr)) : ptr_(nullptr) {}
@@ -116,9 +117,10 @@
 };
 
 // Designed to be used when Struct is small and copyable.
-template <typename Struct>
+template <typename S>
 class InlinedStructPtr {
  public:
+  using Struct = S;
 
   InlinedStructPtr() : is_null_(true) {}
   InlinedStructPtr(decltype(nullptr)) : is_null_(true) {}
diff --git a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
index 4a96136f..ace70d9 100644
--- a/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/struct_traits_unittest.cc
@@ -12,6 +12,7 @@
 #include "mojo/public/cpp/bindings/tests/rect_blink.h"
 #include "mojo/public/cpp/bindings/tests/rect_chromium.h"
 #include "mojo/public/cpp/bindings/tests/struct_with_traits_impl.h"
+#include "mojo/public/cpp/bindings/tests/struct_with_traits_impl_traits.h"
 #include "mojo/public/cpp/bindings/tests/variant_test_util.h"
 #include "mojo/public/interfaces/bindings/tests/struct_with_traits.mojom.h"
 #include "mojo/public/interfaces/bindings/tests/test_native_types.mojom-blink.h"
@@ -311,5 +312,35 @@
   loop.Run();
 }
 
+TEST_F(StructTraitsTest, SerializeStructWithTraits) {
+  StructWithTraitsImpl input;
+  input.set_enum(EnumWithTraitsImpl::CUSTOM_VALUE_1);
+  input.set_bool(true);
+  input.set_uint32(7);
+  input.set_uint64(42);
+  input.set_string("hello world!");
+  input.get_mutable_string_array().assign({"hello", "world!"});
+  input.get_mutable_struct().value = 42;
+  input.get_mutable_struct_array().resize(2);
+  input.get_mutable_struct_array()[0].value = 1;
+  input.get_mutable_struct_array()[1].value = 2;
+  input.get_mutable_struct_map()["hello"] = NestedStructWithTraitsImpl(1024);
+  input.get_mutable_struct_map()["world"] = NestedStructWithTraitsImpl(2048);
+
+  mojo::Array<uint8_t> data = StructWithTraits::Serialize(&input);
+  StructWithTraitsImpl output;
+  ASSERT_TRUE(StructWithTraits::Deserialize(std::move(data), &output));
+
+  EXPECT_EQ(input.get_enum(), output.get_enum());
+  EXPECT_EQ(input.get_bool(), output.get_bool());
+  EXPECT_EQ(input.get_uint32(), output.get_uint32());
+  EXPECT_EQ(input.get_uint64(), output.get_uint64());
+  EXPECT_EQ(input.get_string(), output.get_string());
+  EXPECT_EQ(input.get_string_array(), output.get_string_array());
+  EXPECT_EQ(input.get_struct(), output.get_struct());
+  EXPECT_EQ(input.get_struct_array(), output.get_struct_array());
+  EXPECT_EQ(input.get_struct_map(), output.get_struct_map());
+}
+
 }  // namespace test
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/struct_unittest.cc b/mojo/public/cpp/bindings/tests/struct_unittest.cc
index d5cc816..cfd9ca4 100644
--- a/mojo/public/cpp/bindings/tests/struct_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/struct_unittest.cc
@@ -490,5 +490,68 @@
   }
 }
 
+TEST_F(StructTest, Serialization_PublicAPI) {
+  {
+    // A null struct pointer.
+    RectPtr null_struct;
+    mojo::Array<uint8_t> data = Rect::Serialize(&null_struct);
+    EXPECT_TRUE(data.empty());
+
+    // Initialize it to non-null.
+    RectPtr output(Rect::New());
+    ASSERT_TRUE(Rect::Deserialize(std::move(data), &output));
+    EXPECT_TRUE(output.is_null());
+  }
+
+  {
+    // A struct with no fields.
+    EmptyStructPtr empty_struct(EmptyStruct::New());
+    mojo::Array<uint8_t> data = EmptyStruct::Serialize(&empty_struct);
+    EXPECT_FALSE(data.empty());
+
+    EmptyStructPtr output;
+    ASSERT_TRUE(EmptyStruct::Deserialize(std::move(data), &output));
+    EXPECT_FALSE(output.is_null());
+  }
+
+  {
+    // A simple struct.
+    RectPtr rect = MakeRect();
+    RectPtr cloned_rect = rect.Clone();
+    mojo::Array<uint8_t> data = Rect::Serialize(&rect);
+
+    RectPtr output;
+    ASSERT_TRUE(Rect::Deserialize(std::move(data), &output));
+    EXPECT_TRUE(output.Equals(cloned_rect));
+  }
+
+  {
+    // A struct containing other objects.
+    NamedRegionPtr region(NamedRegion::New());
+    region->name = "region";
+    region->rects = Array<RectPtr>::New(4);
+    for (size_t i = 0; i < region->rects.size(); ++i)
+      region->rects[i] = MakeRect(static_cast<int32_t>(i) + 1);
+
+    NamedRegionPtr cloned_region = region.Clone();
+    mojo::Array<uint8_t> data = NamedRegion::Serialize(&region);
+
+    // Make sure that the serialized result gets pointers encoded properly.
+    mojo::Array<uint8_t> cloned_data = data.Clone();
+    NamedRegionPtr output;
+    ASSERT_TRUE(NamedRegion::Deserialize(std::move(cloned_data), &output));
+    EXPECT_TRUE(output.Equals(cloned_region));
+  }
+
+  {
+    // Deserialization failure.
+    RectPtr rect = MakeRect();
+    mojo::Array<uint8_t> data = Rect::Serialize(&rect);
+
+    NamedRegionPtr output;
+    EXPECT_FALSE(NamedRegion::Deserialize(std::move(data), &output));
+  }
+}
+
 }  // namespace test
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
index f691085e..a17d876 100644
--- a/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/wtf_types_unittest.cc
@@ -205,6 +205,20 @@
   EXPECT_TRUE(kUTF8HelloWorld == str_map2["2"]);
 }
 
+TEST_F(WTFTypesTest, Serialization_PublicAPI) {
+  blink::TestWTFStructPtr input(blink::TestWTFStruct::New());
+  input->str = kHelloWorld;
+  input->integer = 42;
+
+  blink::TestWTFStructPtr cloned_input = input.Clone();
+
+  WTFArray<uint8_t> data = blink::TestWTFStruct::Serialize(&input);
+
+  blink::TestWTFStructPtr output;
+  ASSERT_TRUE(blink::TestWTFStruct::Deserialize(std::move(data), &output));
+  EXPECT_TRUE(cloned_input.Equals(output));
+}
+
 TEST_F(WTFTypesTest, SendString) {
   blink::TestWTFPtr ptr;
   TestWTFImpl impl(ConvertInterfaceRequest<TestWTF>(GetProxy(&ptr)));
diff --git a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
index e15e4568..2fdbea8 100644
--- a/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
+++ b/mojo/public/interfaces/bindings/tests/test_wtf_types.mojom
@@ -24,6 +24,11 @@
   map<string, string?> str_map;
 };
 
+struct TestWTFStruct {
+  string str;
+  int32 integer;
+};
+
 interface TestWTF {
   EchoString(string? str) => (string? str);
   EchoStringArray(array<string?>? arr) => (array<string?>? arr);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
index b4abd68..1c4d9f7 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/wrapper_class_declaration.tmpl
@@ -52,6 +52,23 @@
                 T, {{struct.name}}>::value>::type* = nullptr>
   bool Equals(const T& other) const;
 
+{%- set serialization_result_type = "mojo::WTFArray<uint8_t>"
+        if for_blink else "mojo::Array<uint8_t>" %}
+
+  template <typename UserType>
+  static {{serialization_result_type}} Serialize(UserType* input) {
+    return mojo::internal::StructSerializeImpl<
+        {{struct.name}}Ptr, {{serialization_result_type}}>(input);
+  }
+
+  template <typename UserType>
+  static bool Deserialize({{serialization_result_type}} input,
+                          UserType* output) {
+    return mojo::internal::StructDeserializeImpl<
+        {{struct.name}}Ptr, {{serialization_result_type}}>(
+            std::move(input), output);
+  }
+
 {#--- Struct members #}
 {%  for field in struct.fields %}
 {%-   set type = field.kind|cpp_wrapper_type %}
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 3d7124d..e295d39 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -309,53 +309,27 @@
   proxy->PostTask(FROM_HERE, base::Bind(callback, cookie, removed));
 }
 
-size_t CountProtectedSecureCookiesAtPriority(
-    CookiePriority priority,
-    CookieMonster::CookieItVector* cookies) {
-  size_t num_protected_secure_cookies = 0;
-  for (const auto& cookie : *cookies) {
-    if (!cookie->second->IsSecure())
-      continue;
-    // 1) At low-priority, only low-priority secure cookies are protected as
-    //    part of the quota.
-    // 2) At medium-priority, only medium-priority secure cookies are protected
-    //    as part of the quota (low-priority secure cookies may be deleted).
-    // 3) At high-priority, medium-priority and high-priority secure cookies are
-    //    protected as part of the quota (low-priority secure cookies may be
-    //    deleted).
-    CookiePriority cookie_priority = cookie->second->Priority();
-    switch (cookie_priority) {
-      case COOKIE_PRIORITY_LOW:
-        if (priority == COOKIE_PRIORITY_LOW)
-          num_protected_secure_cookies++;
-        break;
-      case COOKIE_PRIORITY_MEDIUM:
-      case COOKIE_PRIORITY_HIGH:
-        if (cookie_priority <= priority)
-          num_protected_secure_cookies++;
-        break;
-    }
-  }
-
-  return num_protected_secure_cookies;
-}
-
 bool IsCookieEligibleForEviction(CookiePriority current_priority_level,
                                  bool protect_secure_cookies,
                                  const CanonicalCookie* cookie) {
-  if (!cookie->IsSecure() || !protect_secure_cookies)
-    return cookie->Priority() <= current_priority_level;
+  if (cookie->Priority() == current_priority_level && protect_secure_cookies)
+    return !cookie->IsSecure();
 
-  // Special consideration has to be given for low-priority secure cookies since
-  // they are given lower prority than non-secure medium-priority and non-secure
-  // high-priority cookies. Thus, low-priority secure cookies may be evicted at
-  // a medium and high value of |current_priority_level|. Put another way,
-  // low-priority secure cookies are only protected when the current priority
-  // level is low.
-  if (current_priority_level == COOKIE_PRIORITY_LOW)
-    return false;
+  return cookie->Priority() == current_priority_level;
+}
 
-  return cookie->Priority() == COOKIE_PRIORITY_LOW;
+size_t CountCookiesForPossibleDeletion(
+    CookiePriority priority,
+    const CookieMonster::CookieItVector* cookies,
+    bool protect_secure_cookies) {
+  size_t cookies_count = 0U;
+  for (const auto& cookie : *cookies) {
+    if (cookie->second->Priority() == priority) {
+      if (!protect_secure_cookies || cookie->second->IsSecure())
+        cookies_count++;
+    }
+  }
+  return cookies_count;
 }
 
 }  // namespace
@@ -1928,10 +1902,6 @@
       // Sort the cookies by access date, from least-recent to most-recent.
       std::sort(cookie_its->begin(), cookie_its->end(), LRACookieSorter);
 
-      size_t additional_quota_low = kDomainCookiesQuotaLow;
-      size_t additional_quota_medium = kDomainCookiesQuotaMedium;
-      size_t additional_quota_high = kDomainCookiesQuotaHigh;
-
       // Remove all but the kDomainCookiesQuotaLow most-recently accessed
       // cookies with low-priority. Then, if cookies still need to be removed,
       // bump the quota and remove low- and medium-priority. Then, if cookies
@@ -1969,26 +1939,24 @@
         if (!enforce_strict_secure && purge_round.protect_secure_cookies)
           continue;
 
-        // Only adjust the quota if the round is executing, otherwise it is
-        // necesary to delay quota adjustments until a later round. This is
-        // because if the high priority, non-secure round is skipped, its quota
-        // should not count until the later high priority, full round later.
-        size_t* additional_quota = nullptr;
+        // Adjust quota according to the priority of cookies. Each round should
+        // protect certain number of cookies in order to avoid starvation.
+        // For example, when each round starts to remove cookies, the number of
+        // cookies of that priority are counted and a decision whether they
+        // should be deleted or not is made. If yes, some number of cookies of
+        // that priority are deleted considering the quota.
         switch (purge_round.priority) {
           case COOKIE_PRIORITY_LOW:
-            additional_quota = &additional_quota_low;
+            quota = kDomainCookiesQuotaLow;
             break;
           case COOKIE_PRIORITY_MEDIUM:
-            additional_quota = &additional_quota_medium;
+            quota = kDomainCookiesQuotaMedium;
             break;
           case COOKIE_PRIORITY_HIGH:
-            additional_quota = &additional_quota_high;
+            quota = kDomainCookiesQuotaHigh;
             break;
         }
-        quota += *additional_quota;
-        *additional_quota = 0u;
         size_t just_deleted = 0u;
-
         // Purge up to |purge_goal| for all cookies at the given priority. This
         // path will always execute if strict secure cookies is disabled since
         // |purge_goal| must be positive because of the for-loop guard. If
@@ -2058,45 +2026,44 @@
                                               bool protect_secure_cookies) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  // Find the first protected cookie by walking down from the end of the list
-  // cookie list (most-recently accessed) until |to_protect| cookies that match
-  // |priority| are found.
-  //
-  // If |protect_secure_cookies| is true, do a first pass that counts eligible
-  // secure cookies at the specified priority as protected.
+  // 1. Count number of the cookies at |priority|
+  size_t cookies_count_possibly_to_be_deleted = CountCookiesForPossibleDeletion(
+      priority, cookies, false /* count all cookies */);
+
+  // 2. If |cookies_count_possibly_to_be_deleted| at |priority| is less than or
+  // equal |to_protect|, skip round in order to preserve the quota. This
+  // involves secure and non-secure cookies at |priority|.
+  if (cookies_count_possibly_to_be_deleted <= to_protect)
+    return 0u;
+
+  // 3. Calculate number of secure cookies at |priority|
+  // and number of cookies at |priority| that can possibly be deleted.
+  // It is guaranteed we do not delete more than |purge_goal| even if
+  // |cookies_count_possibly_to_be_deleted| is higher.
+  size_t secure_cookies = 0u;
   if (protect_secure_cookies) {
-    to_protect -= std::min(
-        to_protect, CountProtectedSecureCookiesAtPriority(priority, cookies));
+    secure_cookies = CountCookiesForPossibleDeletion(
+        priority, cookies, protect_secure_cookies /* count secure cookies */);
+    cookies_count_possibly_to_be_deleted -=
+        std::max(secure_cookies, to_protect - secure_cookies);
+  } else {
+    cookies_count_possibly_to_be_deleted -= to_protect;
   }
 
-  size_t protection_boundary = cookies->size();
-  while (to_protect > 0 && protection_boundary > 0) {
-    protection_boundary--;
-    if (cookies->at(protection_boundary)->second->Priority() <= priority)
-      to_protect--;
-  }
-
-  // Now, walk up from the beginning of the list (least-recently accessed) until
-  // |purge_goal| cookies are removed, or the iterator hits
-  // |protection_boundary|.
-  size_t removed = 0;
-  size_t current = 0;
-  while (removed < purge_goal && current < protection_boundary) {
+  size_t removed = 0u;
+  size_t current = 0u;
+  while ((removed < purge_goal && current < cookies->size()) &&
+         cookies_count_possibly_to_be_deleted > 0) {
     const CanonicalCookie* current_cookie = cookies->at(current)->second;
-    // Only delete the current cookie if the priority is less than or equal to
-    // the current level. If it is equal to the current level, and secure
-    // cookies are protected, only delete it if it is not secure.
+    // Only delete the current cookie if the priority is equal to
+    // the current level.
     if (IsCookieEligibleForEviction(priority, protect_secure_cookies,
                                     current_cookie)) {
       InternalDeleteCookie(cookies->at(current), true,
                            DELETE_COOKIE_EVICTED_DOMAIN);
       cookies->erase(cookies->begin() + current);
       removed++;
-
-      // The call to 'erase' above shifts the contents of the vector, but
-      // doesn't shift |protection_boundary|. Decrement that here to ensure that
-      // the correct set of cookies is protected.
-      protection_boundary--;
+      cookies_count_possibly_to_be_deleted--;
     } else {
       current++;
     }
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 875267c9..cd7ab02 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -565,15 +565,15 @@
     TestPriorityCookieCase(cm.get(), "10HN 171MN", 0U, 140U, 10U, 150U, 0U);
     // Round 1 => 10L; round2 => 21M; round 3 => none.
     TestPriorityCookieCase(cm.get(), "141MN 40LN", 30U, 120U, 0U, 150U, 0U);
-    // Round 1 => none; round2 => none; round 3 => 31H.
-    TestPriorityCookieCase(cm.get(), "101HN 80MN", 0U, 80U, 70U, 150U, 0U);
+    // Round 1 => none; round2 => 30M; round 3 => 1H.
+    TestPriorityCookieCase(cm.get(), "101HN 80MN", 0U, 50U, 100U, 150U, 0U);
 
     // For {low, medium} priorities right on quota, different orders.
-    // Round 1 => 1L; round 2 => none, round3 => 30L.
-    TestPriorityCookieCase(cm.get(), "31LN 50MN 100HN", 0U, 50U, 100U, 150U,
+    // Round 1 => 1L; round 2 => none, round3 => 30H.
+    TestPriorityCookieCase(cm.get(), "31LN 50MN 100HN", 30U, 50U, 70U, 150U,
                            0U);
-    // Round 1 => none; round 2 => 1M, round3 => 30M.
-    TestPriorityCookieCase(cm.get(), "51MN 100HN 30LN", 30U, 20U, 100U, 150U,
+    // Round 1 => none; round 2 => 1M, round3 => 30H.
+    TestPriorityCookieCase(cm.get(), "51MN 100HN 30LN", 30U, 50U, 70U, 150U,
                            0U);
     // Round 1 => none; round 2 => none; round3 => 31H.
     TestPriorityCookieCase(cm.get(), "101HN 50MN 30LN", 30U, 50U, 70U, 150U,
@@ -586,45 +586,21 @@
     // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
     TestPriorityCookieCase(cm.get(), "21HN 60MN 40LN 60HN", 30U, 50U, 70U, 150U,
                            0U);
-    // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
-    TestPriorityCookieCase(cm.get(), "11HN 10MN 20LN 110MN 20LN 10HN", 20U,
-                           109U, 21U, 150U, 0U);
-    // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
-    TestPriorityCookieCase(cm.get(), "11LN 10MN 140HN 10MN 10LN", 10U, 10U,
-                           130U, 150U, 0U);
-    // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
-    TestPriorityCookieCase(cm.get(), "11MN 10HN 10LN 60MN 90HN", 0U, 60U, 90U,
+    // Round 1 => 10L; round 2 => 21M; round 3 => 0H.
+    TestPriorityCookieCase(cm.get(), "11HN 10MN 20LN 110MN 20LN 10HN", 30U, 99U,
+                           21U, 150U, 0U);
+    // Round 1 => none; round 2 => none; round 3 => 31H.
+    TestPriorityCookieCase(cm.get(), "11LN 10MN 140HN 10MN 10LN", 21U, 20U,
+                           109U, 150U, 0U);
+    // Round 1 => none; round 2 => 21M; round 3 => 10H.
+    TestPriorityCookieCase(cm.get(), "11MN 10HN 10LN 60MN 90HN", 10U, 50U, 90U,
                            150U, 0U);
-    // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
-    TestPriorityCookieCase(cm.get(), "11MN 10HN 10LN 90MN 60HN", 0U, 80U, 70U,
+    // Round 1 => none; round 2 => 31M; round 3 => none.
+    TestPriorityCookieCase(cm.get(), "11MN 10HN 10LN 90MN 60HN", 10U, 70U, 70U,
                            150U, 0U);
 
-    // TODO(jww): According to
-    // https://tools.ietf.org/html/draft-west-cookie-priority#section-3, it
-    // seems that quotas are a mechanism for preventing another application on
-    // the same doman from DoS'ing an application by constantly evicting *all*
-    // lower priority cookies.
-    //
-    // Unfortunately, this has never strictly worked in our implementation. Take
-    // the following test as an example:
-    // TestPriorityCookieCase(cm.get(), "50LN 131HN", 30U, 0U, 120U, 150U, 0U);
-    //
-    // According to this theory, we would expect eviction to proceed as:
     // Round 1 => 20L; round 2 => 0; round 3 => 11H
-    // thus resulting in 30L and 120H at the end.
-    //
-    // However, what happens in practice is that the cookies left are 19L and
-    // 131H. This is because the quotas are accumulated over the rounds and what
-    // priority they apply to is lost information. Since in the last round all
-    // that is known is a total quota, and the low-priority cookies are least
-    // recently accessed, they are evicted first to get down to 150 cookies.
-    //
-    // We should address this and uncomment the test below when it is fixed.
-    //
-    // See https://crbug.com/609550
-    //
-    // Round 1 => 20L; round 2 => 0; round 3 => 11H
-    // TestPriorityCookieCase(cm.get(), "50LN 131HN", 30U, 0U, 120U, 150U, 0U);
+    TestPriorityCookieCase(cm.get(), "50LN 131HN", 30U, 0U, 120U, 150U, 0U);
     // Round 1 => 20L; round 2 => 0; round 3 => 11H
     TestPriorityCookieCase(cm.get(), "131HN 50LN", 30U, 0U, 120U, 150U, 0U);
     // Round 1 => 20L; round 2 => none; round 3 => 11H.
@@ -643,8 +619,11 @@
 
     // Each test case adds 181 cookies, so 31 cookies are evicted.
     // Cookie same priority, repeated for each priority.
+    // Round 1 => 31L; round2 => none; round 3 => none.
     TestPriorityCookieCase(cm.get(), "181LS", 150U, 0U, 0U, 0U, 150U);
+    // Round 1 => none; round2 => 31M; round 3 => none.
     TestPriorityCookieCase(cm.get(), "181MS", 0U, 150U, 0U, 0U, 150U);
+    // Round 1 => none; round2 => none; round 3 => 31H.
     TestPriorityCookieCase(cm.get(), "181HS", 0U, 0U, 150U, 0U, 150U);
 
     // Pairwise scenarios.
@@ -652,15 +631,15 @@
     TestPriorityCookieCase(cm.get(), "10HS 171MS", 0U, 140U, 10U, 0U, 150U);
     // Round 1 => 10L; round2 => 21M; round 3 => none.
     TestPriorityCookieCase(cm.get(), "141MS 40LS", 30U, 120U, 0U, 0U, 150U);
-    // Round 1 => none; round2 => none; round 3 => 31H.
-    TestPriorityCookieCase(cm.get(), "101HS 80MS", 0U, 80U, 70U, 0U, 150U);
+    // Round 1 => none; round2 => 30M; round 3 => 1H.
+    TestPriorityCookieCase(cm.get(), "101HS 80MS", 0U, 50U, 100U, 0U, 150U);
 
     // For {low, medium} priorities right on quota, different orders.
-    // Round 1 => 1L; round 2 => none, round3 => 30L.
-    TestPriorityCookieCase(cm.get(), "31LS 50MS 100HS", 0U, 50U, 100U, 0U,
+    // Round 1 => 1L; round 2 => none, round3 => 30H.
+    TestPriorityCookieCase(cm.get(), "31LS 50MS 100HS", 30U, 50U, 70U, 0U,
                            150U);
-    // Round 1 => none; round 2 => 1M, round3 => 30M.
-    TestPriorityCookieCase(cm.get(), "51MS 100HS 30LS", 30U, 20U, 100U, 0U,
+    // Round 1 => none; round 2 => 1M, round3 => 30H.
+    TestPriorityCookieCase(cm.get(), "51MS 100HS 30LS", 30U, 50U, 70U, 0U,
                            150U);
     // Round 1 => none; round 2 => none; round3 => 31H.
     TestPriorityCookieCase(cm.get(), "101HS 50MS 30LS", 30U, 50U, 70U, 0U,
@@ -673,17 +652,17 @@
     // Round 1 => 10L; round 2 => 10M; round 3 => 11H.
     TestPriorityCookieCase(cm.get(), "21HS 60MS 40LS 60HS", 30U, 50U, 70U, 0U,
                            150U);
-    // Round 1 => 10L; round 2 => 11M, 10L; round 3 => none.
-    TestPriorityCookieCase(cm.get(), "11HS 10MS 20LS 110MS 20LS 10HS", 20U,
-                           109U, 21U, 0U, 150U);
-    // Round 1 => none; round 2 => none; round 3 => 11L, 10M, 10H.
-    TestPriorityCookieCase(cm.get(), "11LS 10MS 140HS 10MS 10LS", 10U, 10U,
-                           130U, 0U, 150U);
-    // Round 1 => none; round 2 => 1M; round 3 => 10L, 10M, 10H.
-    TestPriorityCookieCase(cm.get(), "11MS 10HS 10LS 60MS 90HS", 0U, 60U, 90U,
+    // Round 1 => 10L; round 2 => 21M; round 3 => none.
+    TestPriorityCookieCase(cm.get(), "11HS 10MS 20LS 110MS 20LS 10HS", 30U, 99U,
+                           21U, 0U, 150U);
+    // Round 1 => none; round 2 => none; round 3 => 31H.
+    TestPriorityCookieCase(cm.get(), "11LS 10MS 140HS 10MS 10LS", 21U, 20U,
+                           109U, 0U, 150U);
+    // Round 1 => none; round 2 => 21M; round 3 => 10H.
+    TestPriorityCookieCase(cm.get(), "11MS 10HS 10LS 60MS 90HS", 10U, 50U, 90U,
                            0U, 150U);
-    // Round 1 => none; round 2 => 10L, 21M; round 3 => none.
-    TestPriorityCookieCase(cm.get(), "11MS 10HS 10LS 90MS 60HS", 0U, 80U, 70U,
+    // Round 1 => none; round 2 => 31M; round 3 => none.
+    TestPriorityCookieCase(cm.get(), "11MS 10HS 10LS 90MS 60HS", 10U, 70U, 70U,
                            0U, 150U);
   }
 
@@ -699,44 +678,101 @@
     // secure cookies take priority, so the non-secure cookie is removed, along
     // with 30 secure cookies. Repeated for each priority, and with the
     // non-secure cookie as older and newer.
+    // Round 1 => 1LN; round 2 => 30LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "1LN 180LS", 150U, 0U, 0U, 0U, 150U);
+    // Round 1 => none; round 2 => none; round 3 => 1MN.
+    // Round 4 => none; round 5 => 30MS; round 6 => none.
     TestPriorityCookieCase(cm.get(), "1MN 180MS", 0U, 150U, 0U, 0U, 150U);
+    // Round 1 => none; round 2 => none; round 3 => none.
+    // Round 4 => 1HN; round 5 => none; round 6 => 30HS.
     TestPriorityCookieCase(cm.get(), "1HN 180HS", 0U, 0U, 150U, 0U, 150U);
+    // Round 1 => 1LN; round 2 => 30LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "180LS 1LN", 150U, 0U, 0U, 0U, 150U);
+    // Round 1 => none; round 2 => none; round 3 => 1MN.
+    // Round 4 => none; round 5 => 30MS; round 6 => none.
     TestPriorityCookieCase(cm.get(), "180MS 1MN", 0U, 150U, 0U, 0U, 150U);
+    // Round 1 => none; round 2 => none; round 3 => none.
+    // Round 4 => 1HN; round 5 => none; round 6 => 30HS.
     TestPriorityCookieCase(cm.get(), "180HS 1HN", 0U, 0U, 150U, 0U, 150U);
 
     // Low-priority secure cookies are removed before higher priority non-secure
     // cookies.
+    // Round 1 => none; round 2 => 31LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "180LS 1MN", 149U, 1U, 0U, 1U, 149U);
+    // Round 1 => none; round 2 => 31LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "180LS 1HN", 149U, 0U, 1U, 1U, 149U);
+    // Round 1 => none; round 2 => 31LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "1MN 180LS", 149U, 1U, 0U, 1U, 149U);
+    // Round 1 => none; round 2 => 31LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "1HN 180LS", 149U, 0U, 1U, 1U, 149U);
 
     // Higher-priority non-secure cookies are removed before any secure cookie
-    // with greater than low-priority.
-    TestPriorityCookieCase(cm.get(), "180MS 1HN", 0U, 150U, 0U, 0U, 150U);
-    TestPriorityCookieCase(cm.get(), "1HN 180MS", 0U, 150U, 0U, 0U, 150U);
+    // with greater than low-priority. Is it true? How about the quota?
+    // Round 1 => none; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => 31MS; round 6 => none.
+    TestPriorityCookieCase(cm.get(), "180MS 1HN", 0U, 149U, 1U, 1U, 149U);
+    // Round 1 => none; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => 31MS; round 6 => none.
+    TestPriorityCookieCase(cm.get(), "1HN 180MS", 0U, 149U, 1U, 1U, 149U);
 
     // Pairwise:
+    // Round 1 => 31LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "1LS 180LN", 150U, 0U, 0U, 149U, 1U);
+    // Round 1 => 31LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "100LS 81LN", 150U, 0U, 0U, 50U, 100U);
+    // Round 1 => 31LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "150LS 31LN", 150U, 0U, 0U, 0U, 150U);
-    TestPriorityCookieCase(cm.get(), "1LS 180HN", 0U, 0U, 150U, 150U, 0U);
+    // Round 1 => none; round 2 => none; round 3 => none.
+    // Round 4 => 31HN; round 5 => none; round 6 => none.
+    TestPriorityCookieCase(cm.get(), "1LS 180HN", 1U, 0U, 149U, 149U, 1U);
+    // Round 1 => none; round 2 => 31LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "100LS 81HN", 69U, 0U, 81U, 81U, 69U);
+    // Round 1 => none; round 2 => 31LS; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "150LS 31HN", 119U, 0U, 31U, 31U, 119U);
 
     // Quota calculations inside non-secure/secure blocks remain in place:
-    // Round 1 => 20LS; round 2 => none; round 3 => 11HN.
+    // Round 1 => none; round 2 => 20LS; round 3 => none.
+    // Round 4 => 11HN; round 5 => none; round 6 => none.
     TestPriorityCookieCase(cm.get(), "50HN 50LS 81HS", 30U, 0U, 120U, 39U,
                            111U);
-    // Round 1 => none; round 2 => 10LS, 21MN; round 3 => none.
-    TestPriorityCookieCase(cm.get(), "11MS 10HN 10LS 90MN 60HN", 0U, 80U, 70U,
-                           139U, 11U);
+    // Round 1 => none; round 2 => none; round 3 => 31MN.
+    // Round 4 => none; round 5 => none; round 6 => none.
+    TestPriorityCookieCase(cm.get(), "11MS 10HN 10LS 90MN 60HN", 10U, 70U, 70U,
+                           129U, 21U);
+    // Round 1 => 31LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
+    TestPriorityCookieCase(cm.get(), "40LS 40LN 101HS", 49U, 0U, 101U, 9U,
+                           141U);
 
     // Multiple GC rounds end up with consistent behavior:
-    TestPriorityCookieCase(cm.get(), "100HS 100LN 100MN", 0, 76U, 100U, 76U,
-                           100U);
+    // GC is started as soon as there are 181 cookies in the store.
+    // On each major round it tries to preserve the quota for each priority.
+    // It is not aware about more cookies going in.
+    // 1 GC notices there are 181 cookies - 100HS 81LN 0MN
+    // Round 1 => 31LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
+    // 2 GC notices there are 181 cookies - 100HS 69LN 12MN
+    // Round 1 => 31LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => none.
+    // 3 GC notices there are 181 cookies - 100HS 38LN 43MN
+    // Round 1 =>  8LN; round 2 => none; round 3 => none.
+    // Round 4 => none; round 5 => none; round 6 => 23HS.
+    // 4 GC notcies there are 181 cookies - 77HS 30LN 74MN
+    // Round 1 => none; round 2 => none; round 3 => 24MN.
+    // Round 4 => none; round 5 => none; round 6 =>  7HS.
+    TestPriorityCookieCase(cm.get(), "100HS 100LN 100MN", 30U, 76U, 70U, 106U,
+                           70U);
   }
 
   // Function for creating a CM with a number of cookies in it,
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
index 2ba53f8..bd3f2e3 100644
--- a/net/http/http_stream_factory_impl_job_controller.cc
+++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -103,11 +103,13 @@
 
 LoadState HttpStreamFactoryImpl::JobController::GetLoadState() const {
   DCHECK(request_);
+  DCHECK(main_job_ || alternative_job_);
   if (bound_job_)
     return bound_job_->GetLoadState();
 
   // Just pick the first one.
-  return main_job_->GetLoadState();
+  return main_job_ ? main_job_->GetLoadState()
+                   : alternative_job_->GetLoadState();
 }
 
 void HttpStreamFactoryImpl::JobController::OnRequestComplete() {
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc
index 8f1f75d3..bd94d7d 100644
--- a/net/http/http_stream_factory_impl_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc
@@ -255,4 +255,45 @@
                                  ProxyInfo());
 }
 
+// Regression test for crbug/621069.
+// Get load state after main job fails and before alternative job succeeds.
+TEST_P(HttpStreamFactoryImplJobControllerTest, GetLoadStateAfterMainJobFailed) {
+  HttpRequestInfo request_info;
+  request_info.method = "GET";
+  request_info.url = GURL("https://www.google.com");
+
+  url::SchemeHostPort server(request_info.url);
+  AlternativeService alternative_service(QUIC, server.host(), 443);
+  SetAlternativeService(request_info, alternative_service);
+
+  request_.reset(
+      job_controller_->Start(request_info, &request_delegate_, nullptr,
+                             BoundNetLog(), HttpStreamRequest::HTTP_STREAM,
+                             DEFAULT_PRIORITY, SSLConfig(), SSLConfig()));
+  EXPECT_TRUE(job_controller_->main_job());
+  EXPECT_TRUE(job_controller_->alternative_job());
+
+  // |main_job| fails but should not report status to Request.
+  // The alternative job will mark the main job complete.
+  EXPECT_CALL(request_delegate_, OnStreamFailed(_, _, _)).Times(0);
+  EXPECT_CALL(*job_factory_.alternative_job(), MarkOtherJobComplete(_))
+      .Times(1);
+
+  job_controller_->OnStreamFailed(job_factory_.main_job(), ERR_FAILED,
+                                  SSLConfig(), SSL_FAILURE_NONE);
+
+  // Controller should use alternative job to get load state.
+  job_controller_->GetLoadState();
+
+  // |alternative_job| succeeds and should report status to Request.
+  HttpStream* http_stream =
+      new HttpBasicStream(new ClientSocketHandle(), false);
+  job_factory_.alternative_job()->SetStream(http_stream);
+
+  EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
+      .WillOnce(Invoke(DeleteHttpStreamPointer));
+  job_controller_->OnStreamReady(job_factory_.alternative_job(), SSLConfig(),
+                                 ProxyInfo());
+}
+
 }  // namespace net
diff --git a/net/quic/bidirectional_stream_quic_impl.cc b/net/quic/bidirectional_stream_quic_impl.cc
index 25154b4..1056d1c 100644
--- a/net/quic/bidirectional_stream_quic_impl.cc
+++ b/net/quic/bidirectional_stream_quic_impl.cc
@@ -33,6 +33,7 @@
       has_sent_headers_(false),
       has_received_headers_(false),
       send_request_headers_automatically_(true),
+      waiting_for_confirmation_(false),
       weak_factory_(this) {
   DCHECK(session_);
   session_->AddObserver(this);
@@ -281,6 +282,8 @@
 
 void BidirectionalStreamQuicImpl::OnCryptoHandshakeConfirmed() {
   was_handshake_confirmed_ = true;
+  if (waiting_for_confirmation_)
+    NotifyStreamReady();
 }
 
 void BidirectionalStreamQuicImpl::OnSessionClosed(
@@ -296,11 +299,11 @@
   DCHECK(rv == OK || !stream_);
   if (rv == OK) {
     stream_->SetDelegate(this);
-    if (send_request_headers_automatically_) {
-      SendRequestHeaders();
+    if (!was_handshake_confirmed_ && request_info_->method == "POST") {
+      waiting_for_confirmation_ = true;
+      return;
     }
-    if (delegate_)
-      delegate_->OnStreamReady(has_sent_headers_);
+    NotifyStreamReady();
   } else {
     NotifyError(rv);
   }
@@ -332,6 +335,14 @@
   }
 }
 
+void BidirectionalStreamQuicImpl::NotifyStreamReady() {
+  if (send_request_headers_automatically_) {
+    SendRequestHeaders();
+  }
+  if (delegate_)
+    delegate_->OnStreamReady(has_sent_headers_);
+}
+
 void BidirectionalStreamQuicImpl::ResetStream() {
   if (!stream_)
     return;
diff --git a/net/quic/bidirectional_stream_quic_impl.h b/net/quic/bidirectional_stream_quic_impl.h
index 7a3e665..bd22cdd7 100644
--- a/net/quic/bidirectional_stream_quic_impl.h
+++ b/net/quic/bidirectional_stream_quic_impl.h
@@ -75,6 +75,8 @@
 
   // Notifies the delegate of an error.
   void NotifyError(int error);
+  // Notifies the delegate that the stream is ready.
+  void NotifyStreamReady();
   // Resets the stream and ensures that |delegate_| won't be called back.
   void ResetStream();
 
@@ -117,6 +119,10 @@
   // frame with data frame in the same packet if possible.
   bool send_request_headers_automatically_;
 
+  // True of this stream is waiting for the QUIC handshake to be confirmed
+  // before sending headers.
+  bool waiting_for_confirmation_;
+
   base::WeakPtrFactory<BidirectionalStreamQuicImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(BidirectionalStreamQuicImpl);
diff --git a/net/quic/bidirectional_stream_quic_impl_unittest.cc b/net/quic/bidirectional_stream_quic_impl_unittest.cc
index 22dba77f..9d8658c 100644
--- a/net/quic/bidirectional_stream_quic_impl_unittest.cc
+++ b/net/quic/bidirectional_stream_quic_impl_unittest.cc
@@ -68,16 +68,19 @@
         on_data_sent_count_(0),
         not_expect_callback_(false),
         on_failed_called_(false),
-        send_request_headers_automatically_(true) {
+        send_request_headers_automatically_(true),
+        is_ready_(false) {
     loop_.reset(new base::RunLoop);
   }
 
   ~TestDelegateBase() override {}
 
   void OnStreamReady(bool request_headers_sent) override {
+    CHECK(!is_ready_);
     CHECK(!on_failed_called_);
     EXPECT_EQ(send_request_headers_automatically_, request_headers_sent);
     CHECK(!not_expect_callback_);
+    is_ready_ = true;
     loop_->Quit();
   }
 
@@ -194,6 +197,7 @@
   int on_data_read_count() const { return on_data_read_count_; }
   int on_data_sent_count() const { return on_data_sent_count_; }
   bool on_failed_called() const { return on_failed_called_; }
+  bool is_ready() const { return is_ready_; }
 
  protected:
   // Quits |loop_|.
@@ -220,6 +224,7 @@
   bool on_failed_called_;
   CompletionCallback callback_;
   bool send_request_headers_automatically_;
+  bool is_ready_;
 
   DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
 };
@@ -342,6 +347,8 @@
 
   // Configures the test fixture to use the list of expected writes.
   void Initialize() {
+    crypto_client_stream_factory_.set_handshake_mode(
+        MockCryptoClientStream::ZERO_RTT);
     mock_writes_.reset(new MockWrite[writes_.size()]);
     for (size_t i = 0; i < writes_.size(); i++) {
       if (writes_[i].packet == nullptr) {
@@ -382,7 +389,12 @@
         /*socket_performance_watcher=*/nullptr, net_log().bound().net_log()));
     session_->Initialize();
     session_->GetCryptoStream()->CryptoConnect();
-    EXPECT_TRUE(session_->IsCryptoHandshakeConfirmed());
+    EXPECT_TRUE(session_->IsEncryptionEstablished());
+  }
+
+  void ConfirmHandshake() {
+    crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+        QuicSession::HANDSHAKE_CONFIRMED);
   }
 
   void SetRequest(const std::string& method,
@@ -716,6 +728,8 @@
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->DoNotSendRequestHeadersAutomatically();
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  EXPECT_FALSE(delegate->is_ready());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Sends request headers separately, which causes them to be sent in a
@@ -819,6 +833,7 @@
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->DoNotSendRequestHeadersAutomatically();
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Send a Data packet.
@@ -916,6 +931,7 @@
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->DoNotSendRequestHeadersAutomatically();
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Send a Data packet.
@@ -1006,6 +1022,84 @@
   std::unique_ptr<TestDelegateBase> delegate(
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
+  delegate->WaitUntilNextCallback();  // OnStreamReady
+
+  // Send a DATA frame.
+  scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(kUploadData));
+
+  delegate->SendData(buf, buf->size(), true);
+  delegate->WaitUntilNextCallback();  // OnDataSent
+
+  // Server acks the request.
+  ProcessPacket(ConstructServerAckPacket(1, 0, 0));
+
+  // Server sends the response headers.
+  SpdyHeaderBlock response_headers = ConstructResponseHeaders("200");
+  size_t spdy_response_headers_frame_length;
+  QuicStreamOffset offset = 0;
+  ProcessPacket(ConstructResponseHeadersPacket(
+      2, !kFin, response_headers, &spdy_response_headers_frame_length,
+      &offset));
+
+  delegate->WaitUntilNextCallback();  // OnHeadersReceived
+  TestCompletionCallback cb;
+  int rv = delegate->ReadData(cb.callback());
+  EXPECT_EQ(ERR_IO_PENDING, rv);
+  EXPECT_EQ("200", delegate->response_headers().find(":status")->second);
+  const char kResponseBody[] = "Hello world!";
+  // Server sends data.
+  ProcessPacket(
+      ConstructServerDataPacket(3, !kIncludeVersion, !kFin, 0, kResponseBody));
+
+  EXPECT_EQ(static_cast<int>(strlen(kResponseBody)), cb.WaitForResult());
+
+  size_t spdy_trailers_frame_length;
+  SpdyHeaderBlock trailers;
+  trailers["foo"] = "bar";
+  trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody));
+  // Server sends trailers.
+  ProcessPacket(ConstructResponseTrailersPacket(
+      4, kFin, trailers, &spdy_trailers_frame_length, &offset));
+
+  delegate->WaitUntilNextCallback();  // OnTrailersReceived
+  trailers.erase(kFinalOffsetHeaderKey);
+  EXPECT_EQ(trailers, delegate->trailers());
+  EXPECT_EQ(OK, delegate->ReadData(cb.callback()));
+
+  EXPECT_EQ(1, delegate->on_data_read_count());
+  EXPECT_EQ(1, delegate->on_data_sent_count());
+  EXPECT_EQ(kProtoQUIC1SPDY3, delegate->GetProtocol());
+  EXPECT_EQ(static_cast<int64_t>(spdy_request_headers_frame_length +
+                                 strlen(kUploadData)),
+            delegate->GetTotalSentBytes());
+  EXPECT_EQ(
+      static_cast<int64_t>(spdy_response_headers_frame_length +
+                           strlen(kResponseBody) + spdy_trailers_frame_length),
+      delegate->GetTotalReceivedBytes());
+}
+
+TEST_P(BidirectionalStreamQuicImplTest, PutRequest) {
+  SetRequest("PUT", "/", DEFAULT_PRIORITY);
+  size_t spdy_request_headers_frame_length;
+  AddWrite(ConstructRequestHeadersPacket(1, !kFin, DEFAULT_PRIORITY,
+                                         &spdy_request_headers_frame_length));
+  AddWrite(ConstructDataPacket(2, kIncludeVersion, kFin, 0, kUploadData,
+                               &client_maker_));
+  AddWrite(ConstructClientAckPacket(3, 3, 1));
+
+  Initialize();
+
+  BidirectionalStreamRequestInfo request;
+  request.method = "PUT";
+  request.url = GURL("http://www.google.com/");
+  request.end_stream_on_headers = false;
+  request.priority = DEFAULT_PRIORITY;
+
+  scoped_refptr<IOBuffer> read_buffer(new IOBuffer(kReadBufferSize));
+  std::unique_ptr<TestDelegateBase> delegate(
+      new TestDelegateBase(read_buffer.get(), kReadBufferSize));
+  delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Send a DATA frame.
@@ -1084,6 +1178,7 @@
   std::unique_ptr<TestDelegateBase> delegate(
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Server acks the request.
@@ -1163,6 +1258,7 @@
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
   delegate->WaitUntilNextCallback();  // OnStreamReady
+  ConfirmHandshake();
 
   // Server sends a Rst.
   ProcessPacket(ConstructServerRstStreamPacket(1));
@@ -1202,6 +1298,7 @@
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
   delegate->WaitUntilNextCallback();  // OnStreamReady
+  ConfirmHandshake();
 
   // Server acks the request.
   ProcessPacket(ConstructServerAckPacket(1, 0, 0));
@@ -1259,6 +1356,7 @@
   std::unique_ptr<TestDelegateBase> delegate(
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Server acks the request.
@@ -1314,6 +1412,7 @@
   std::unique_ptr<TestDelegateBase> delegate(
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Server acks the request.
@@ -1372,6 +1471,7 @@
   std::unique_ptr<TestDelegateBase> delegate(
       new TestDelegateBase(read_buffer.get(), kReadBufferSize));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Server acks the request.
@@ -1422,6 +1522,7 @@
       new DeleteStreamDelegate(read_buffer.get(), kReadBufferSize,
                                DeleteStreamDelegate::ON_HEADERS_RECEIVED));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Server acks the request.
@@ -1464,6 +1565,7 @@
   std::unique_ptr<DeleteStreamDelegate> delegate(new DeleteStreamDelegate(
       read_buffer.get(), kReadBufferSize, DeleteStreamDelegate::ON_DATA_READ));
   delegate->Start(&request, net_log().bound(), session()->GetWeakPtr());
+  ConfirmHandshake();
   delegate->WaitUntilNextCallback();  // OnStreamReady
 
   // Server acks the request.
diff --git a/net/quic/quic_chromium_client_stream.cc b/net/quic/quic_chromium_client_stream.cc
index 2b72c95..539c9909 100644
--- a/net/quic/quic_chromium_client_stream.cc
+++ b/net/quic/quic_chromium_client_stream.cc
@@ -139,6 +139,11 @@
     const SpdyHeaderBlock& header_block,
     bool fin,
     QuicAckListenerInterface* ack_notifier_delegate) {
+  if (!session()->IsCryptoHandshakeConfirmed()) {
+    auto entry = header_block.find(":method");
+    DCHECK(entry != header_block.end());
+    DCHECK_NE("POST", entry->second);
+  }
   net_log_.AddEvent(
       NetLog::TYPE_QUIC_CHROMIUM_CLIENT_STREAM_SEND_REQUEST_HEADERS,
       base::Bind(&QuicRequestNetLogCallback, id(), &header_block,
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 96913a84..3643fa4 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -83,7 +83,7 @@
 bool FLAGS_quic_crypto_server_config_default_has_chacha20 = true;
 
 // Resend 0RTT requests in response to an REJ that re-establishes encryption.
-bool FLAGS_quic_reply_to_rej = false;
+bool FLAGS_quic_reply_to_rej = true;
 
 // If true, QUIC connections can do bandwidth resumption with an initial window
 // of < 10 packets.
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc
index 8d54207..7598a1f 100644
--- a/net/quic/quic_http_stream.cc
+++ b/net/quic/quic_http_stream.cc
@@ -525,6 +525,13 @@
 
 void QuicHttpStream::OnCryptoHandshakeConfirmed() {
   was_handshake_confirmed_ = true;
+  if (next_state_ == STATE_WAIT_FOR_CONFIRMATION_COMPLETE) {
+    int rv = DoLoop(OK);
+
+    if (rv != ERR_IO_PENDING && !callback_.is_null()) {
+      DoCallback(rv);
+    }
+  }
 }
 
 void QuicHttpStream::OnSessionClosed(int error, bool port_migration_detected) {
@@ -562,6 +569,13 @@
       case STATE_SET_REQUEST_PRIORITY:
         rv = DoSetRequestPriority();
         break;
+      case STATE_WAIT_FOR_CONFIRMATION:
+        CHECK_EQ(OK, rv);
+        rv = DoWaitForConfirmation();
+        break;
+      case STATE_WAIT_FOR_CONFIRMATION_COMPLETE:
+        rv = DoWaitForConfirmationComplete(rv);
+        break;
       case STATE_SEND_HEADERS:
         CHECK_EQ(OK, rv);
         rv = DoSendHeaders();
@@ -621,12 +635,28 @@
 }
 
 int QuicHttpStream::DoSetRequestPriority() {
-  // Set priority according to request and, and advance to
-  // STATE_SEND_HEADERS.
+  // Set priority according to request
   DCHECK(stream_);
   DCHECK(response_info_);
   SpdyPriority priority = ConvertRequestPriorityToQuicPriority(priority_);
   stream_->SetPriority(priority);
+  next_state_ = STATE_WAIT_FOR_CONFIRMATION;
+  return OK;
+}
+
+int QuicHttpStream::DoWaitForConfirmation() {
+  next_state_ = STATE_WAIT_FOR_CONFIRMATION_COMPLETE;
+  if (!session_->IsCryptoHandshakeConfirmed() &&
+      request_info_->method == "POST") {
+    return ERR_IO_PENDING;
+  }
+  return OK;
+}
+
+int QuicHttpStream::DoWaitForConfirmationComplete(int rv) {
+  if (rv < 0)
+    return rv;
+
   next_state_ = STATE_SEND_HEADERS;
   return OK;
 }
diff --git a/net/quic/quic_http_stream.h b/net/quic/quic_http_stream.h
index eb21387..7a1302e 100644
--- a/net/quic/quic_http_stream.h
+++ b/net/quic/quic_http_stream.h
@@ -96,6 +96,8 @@
     STATE_NONE,
     STATE_REQUEST_STREAM,
     STATE_SET_REQUEST_PRIORITY,
+    STATE_WAIT_FOR_CONFIRMATION,
+    STATE_WAIT_FOR_CONFIRMATION_COMPLETE,
     STATE_SEND_HEADERS,
     STATE_SEND_HEADERS_COMPLETE,
     STATE_READ_REQUEST_BODY,
@@ -112,6 +114,8 @@
   int DoLoop(int rv);
   int DoStreamRequest();
   int DoSetRequestPriority();
+  int DoWaitForConfirmation();
+  int DoWaitForConfirmationComplete(int rv);
   int DoSendHeaders();
   int DoSendHeadersComplete(int rv);
   int DoReadRequestBody();
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 9e830c2..ce63012 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -176,7 +176,6 @@
       const QuicSessionKey& key,
       bool was_alternative_service_recently_broken,
       int cert_verify_flags,
-      bool is_post,
       QuicServerInfo* server_info,
       const BoundNetLog& net_log);
 
@@ -229,7 +228,6 @@
   SingleRequestHostResolver host_resolver_;
   QuicSessionKey key_;
   int cert_verify_flags_;
-  bool is_post_;
   bool was_alternative_service_recently_broken_;
   std::unique_ptr<QuicServerInfo> server_info_;
   bool started_another_job_;
@@ -249,7 +247,6 @@
                             const QuicSessionKey& key,
                             bool was_alternative_service_recently_broken,
                             int cert_verify_flags,
-                            bool is_post,
                             QuicServerInfo* server_info,
                             const BoundNetLog& net_log)
     : io_state_(STATE_RESOLVE_HOST),
@@ -257,7 +254,6 @@
       host_resolver_(host_resolver),
       key_(key),
       cert_verify_flags_(cert_verify_flags),
-      is_post_(is_post),
       was_alternative_service_recently_broken_(
           was_alternative_service_recently_broken),
       server_info_(server_info),
@@ -276,7 +272,6 @@
       host_resolver_(host_resolver),  // unused
       key_(key),
       cert_verify_flags_(0),                            // unused
-      is_post_(false),                                  // unused
       was_alternative_service_recently_broken_(false),  // unused
       started_another_job_(false),                      // unused
       net_log_(session->net_log()),                     // unused
@@ -436,7 +431,7 @@
     // If we are waiting to load server config from the disk cache, then start
     // another job.
     started_another_job_ = true;
-    factory_->CreateAuxilaryJob(key_, cert_verify_flags_, is_post_, net_log_);
+    factory_->CreateAuxilaryJob(key_, cert_verify_flags_, net_log_);
   }
   return rv;
 }
@@ -482,7 +477,7 @@
   if (!session_->connection()->connected()) {
     return ERR_QUIC_PROTOCOL_ERROR;
   }
-  bool require_confirmation = factory_->require_confirmation() || is_post_ ||
+  bool require_confirmation = factory_->require_confirmation() ||
                               was_alternative_service_recently_broken_;
 
   rv = session_->CryptoConnect(
@@ -890,8 +885,7 @@
   QuicSessionKey key(destination, server_id);
   std::unique_ptr<Job> job(
       new Job(this, host_resolver_, key, WasQuicRecentlyBroken(server_id),
-              cert_verify_flags, method == "POST" /* is_post */,
-              quic_server_info, net_log));
+              cert_verify_flags, quic_server_info, net_log));
   int rv = job->Run(base::Bind(&QuicStreamFactory::OnJobComplete,
                                base::Unretained(this), job.get()));
   if (rv == ERR_IO_PENDING) {
@@ -934,11 +928,10 @@
 
 void QuicStreamFactory::CreateAuxilaryJob(const QuicSessionKey& key,
                                           int cert_verify_flags,
-                                          bool is_post,
                                           const BoundNetLog& net_log) {
   Job* aux_job =
       new Job(this, host_resolver_, key, WasQuicRecentlyBroken(key.server_id()),
-              cert_verify_flags, is_post, nullptr, net_log);
+              cert_verify_flags, nullptr, net_log);
   active_jobs_[key.server_id()].insert(aux_job);
   task_runner_->PostTask(FROM_HERE,
                          base::Bind(&QuicStreamFactory::Job::RunAuxilaryJob,
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index 60d512d..f56281f 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -379,7 +379,6 @@
   // disk cache. This job is started via a PostTask.
   void CreateAuxilaryJob(const QuicSessionKey& key,
                          int cert_verify_flags,
-                         bool is_post,
                          const BoundNetLog& net_log);
 
   // Returns a newly created QuicHttpStream owned by the caller.
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 030e5df..29b9e0e 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -611,17 +611,10 @@
                                            "192.168.0.1", "");
 
   QuicStreamRequest request(factory_.get());
-  // Posts require handshake confirmation, so this will return asynchronously.
-  EXPECT_EQ(ERR_IO_PENDING,
-            request.Request(host_port_pair_, privacy_mode_,
-                            /*cert_verify_flags=*/0, url_, "POST", net_log_,
-                            callback_.callback()));
+  EXPECT_EQ(OK, request.Request(host_port_pair_, privacy_mode_,
+                                /*cert_verify_flags=*/0, url_, "POST", net_log_,
+                                callback_.callback()));
 
-  // Confirm the handshake and verify that the stream is created.
-  crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
-      QuicSession::HANDSHAKE_CONFIRMED);
-
-  EXPECT_EQ(OK, callback_.WaitForResult());
   std::unique_ptr<QuicHttpStream> stream = request.CreateStream();
   EXPECT_TRUE(stream.get());
   EXPECT_TRUE(socket_data.AllReadDataConsumed());
@@ -3663,7 +3656,7 @@
   http_server_properties_.SetServerNetworkStats(server, stats1);
 
   crypto_client_stream_factory_.set_handshake_mode(
-      MockCryptoClientStream::ZERO_RTT);
+      MockCryptoClientStream::COLD_START);
   host_resolver_.set_synchronous_mode(true);
   host_resolver_.rules()->AddIPLiteralRule(host_port_pair_.host(),
                                            "192.168.0.1", "");
diff --git a/net/socket/ssl_server_socket.h b/net/socket/ssl_server_socket.h
index dfda6c1..9053ea0 100644
--- a/net/socket/ssl_server_socket.h
+++ b/net/socket/ssl_server_socket.h
@@ -1,6 +1,17 @@
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+//
+// NOTE: This class is provided to support existing Chromium consumers; it is
+// NOT intended for use in NEW code. Configuring a TLS server correctly is a
+// security-sensitive activity with many subtle nuances, and thus care should be
+// taken to discuss with //net/OWNERS before any new usages.
+//
+// As such, this header should be treated as an internal implementation detail
+// of //net (where it's used for some unit test infrastructure), not as
+// appropriate for general use.
+//
+// See https://crbug.com/621176 for more details.
 
 #ifndef NET_SOCKET_SSL_SERVER_SOCKET_H_
 #define NET_SOCKET_SSL_SERVER_SOCKET_H_
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc
index a3d3565..8d90f5f 100644
--- a/net/url_request/sdch_dictionary_fetcher.cc
+++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -225,7 +225,7 @@
   current_request_.reset();
   buffer_ = nullptr;
   current_callback_.Reset();
-  dictionary_.clear();
+  dictionary_.reset();
   return;
 }
 
@@ -286,6 +286,7 @@
   current_request_->SetLoadFlags(load_flags);
 
   buffer_ = new IOBuffer(kBufferSize);
+  dictionary_.reset(new std::string());
   current_callback_ = info.callback;
 
   current_request_->Start();
@@ -350,7 +351,7 @@
 
   // Data; append to the dictionary and look for more data.
   if (rv > 0) {
-    dictionary_.append(buffer_->data(), rv);
+    dictionary_->append(buffer_->data(), rv);
     next_state_ = STATE_READ_BODY;
     return OK;
   }
@@ -365,7 +366,7 @@
 
   // If the dictionary was successfully fetched, add it to the manager.
   if (rv == OK) {
-    current_callback_.Run(dictionary_, current_request_->url(),
+    current_callback_.Run(*dictionary_, current_request_->url(),
                           current_request_->net_log(),
                           current_request_->was_cached());
   }
diff --git a/net/url_request/sdch_dictionary_fetcher.h b/net/url_request/sdch_dictionary_fetcher.h
index e4b7c4f..ea59582 100644
--- a/net/url_request/sdch_dictionary_fetcher.h
+++ b/net/url_request/sdch_dictionary_fetcher.h
@@ -112,8 +112,10 @@
   scoped_refptr<IOBuffer> buffer_;
   OnDictionaryFetchedCallback current_callback_;
 
-  // The currently accumulating dictionary.
-  std::string dictionary_;
+  // The currently accumulating dictionary. Stored as a unique_ptr so all memory
+  // it consumes can be easily freed, as it gets quite big, and
+  // std::string::clear() may not free memory.
+  std::unique_ptr<std::string> dictionary_;
 
   // Store the URLRequestContext associated with the owning SdchManager for
   // use while fetching.
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 8f5b7ce4..56acc45f 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -522,6 +522,8 @@
 
 // Creates a channel to talk to a renderer. The plugin will respond with
 // PpapiHostMsg_ChannelCreated.
+// If |renderer_pid| is base::kNullProcessId, this is a channel used by the
+// browser itself.
 IPC_MESSAGE_CONTROL3(PpapiMsg_CreateChannel,
                      base::ProcessId /* renderer_pid */,
                      int /* renderer_child_id */,
diff --git a/remoting/host/chromeos/aura_desktop_capturer.cc b/remoting/host/chromeos/aura_desktop_capturer.cc
index ee80cd2..f12a8ce 100644
--- a/remoting/host/chromeos/aura_desktop_capturer.cc
+++ b/remoting/host/chromeos/aura_desktop_capturer.cc
@@ -55,7 +55,8 @@
 void AuraDesktopCapturer::OnFrameCaptured(
     std::unique_ptr<cc::CopyOutputResult> result) {
   if (result->IsEmpty()) {
-    callback_->OnCaptureCompleted(nullptr);
+    callback_->OnCaptureResult(DesktopCapturer::Result::ERROR_TEMPORARY,
+                               nullptr);
     return;
   }
 
@@ -74,7 +75,8 @@
   // See cc::Layer::contents_scale_(x|y)() and frame->set_depi().
   frame->mutable_updated_region()->SetRect(rect);
 
-  callback_->OnCaptureCompleted(frame.release());
+  callback_->OnCaptureResult(DesktopCapturer::Result::SUCCESS,
+                             std::move(frame));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/chromeos/aura_desktop_capturer_unittest.cc b/remoting/host/chromeos/aura_desktop_capturer_unittest.cc
index 754bb45..82af9189 100644
--- a/remoting/host/chromeos/aura_desktop_capturer_unittest.cc
+++ b/remoting/host/chromeos/aura_desktop_capturer_unittest.cc
@@ -16,7 +16,6 @@
 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
 
 using testing::_;
-using testing::SaveArg;
 
 namespace remoting {
 
@@ -37,6 +36,11 @@
     0x20, 0x3c, 0x00, 0xc6, 0xe1, 0x73, 0x34, 0xe2, 0x23, 0x99, 0xc4, 0xfa,
     0x91, 0xc2, 0xd5, 0x97, 0xc1, 0x8b, 0xd0, 0x3c, 0x13, 0xba, 0xf0, 0xd7
   };
+
+ACTION_P(SaveUniquePtrArg, dest) {
+  *dest = std::move(*arg1);
+}
+
 }  // namespace
 
 class AuraDesktopCapturerTest : public testing::Test,
@@ -46,7 +50,13 @@
 
   void SetUp() override;
 
-  MOCK_METHOD1(OnCaptureCompleted, void(webrtc::DesktopFrame* frame));
+  MOCK_METHOD2(OnCaptureResultPtr,
+               void(webrtc::DesktopCapturer::Result result,
+                    std::unique_ptr<webrtc::DesktopFrame>* frame));
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override {
+    OnCaptureResultPtr(result, &frame);
+  }
 
  protected:
   void SimulateFrameCapture() {
@@ -67,22 +77,18 @@
 }
 
 TEST_F(AuraDesktopCapturerTest, ConvertSkBitmapToDesktopFrame) {
-  webrtc::DesktopFrame* captured_frame = nullptr;
+  std::unique_ptr<webrtc::DesktopFrame> captured_frame;
 
-  EXPECT_CALL(*this, OnCaptureCompleted(_)).Times(1).WillOnce(
-      SaveArg<0>(&captured_frame));
+  EXPECT_CALL(*this,
+              OnCaptureResultPtr(webrtc::DesktopCapturer::Result::SUCCESS, _))
+      .Times(1)
+      .WillOnce(SaveUniquePtrArg(&captured_frame));
   capturer_->Start(this);
 
   SimulateFrameCapture();
 
-  ASSERT_TRUE(captured_frame != nullptr);
-  uint8_t* captured_data = captured_frame->data();
-  EXPECT_EQ(
-      0,
-      memcmp(
-          frame_data, captured_data, sizeof(frame_data)));
-
-  delete captured_frame;
+  ASSERT_TRUE(captured_frame);
+  EXPECT_EQ(0, memcmp(frame_data, captured_frame->data(), sizeof(frame_data)));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h
index 1d2a574..8a60aa1 100644
--- a/remoting/host/chromoting_messages.h
+++ b/remoting/host/chromoting_messages.h
@@ -14,6 +14,7 @@
 #include "remoting/host/screen_resolution.h"
 #include "remoting/protocol/errors.h"
 #include "remoting/protocol/transport.h"
+#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h"
 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
 
 #endif  // REMOTING_HOST_CHROMOTING_MESSAGES_H_
@@ -172,9 +173,13 @@
   IPC_STRUCT_MEMBER(webrtc::DesktopVector, dpi)
 IPC_STRUCT_END()
 
+IPC_ENUM_TRAITS_MAX_VALUE(webrtc::DesktopCapturer::Result,
+                          webrtc::DesktopCapturer::Result::MAX_VALUE)
+
 // Notifies the network process that a shared buffer has been created.
-IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_CaptureCompleted,
-                     SerializedDesktopFrame /* frame */ )
+IPC_MESSAGE_CONTROL2(ChromotingDesktopNetworkMsg_CaptureResult,
+                     webrtc::DesktopCapturer::Result /* result */,
+                     SerializedDesktopFrame /* frame */)
 
 // Carries a cursor share update from the desktop session agent to the client.
 IPC_MESSAGE_CONTROL1(ChromotingDesktopNetworkMsg_MouseCursor,
diff --git a/remoting/host/desktop_capturer_proxy.cc b/remoting/host/desktop_capturer_proxy.cc
index 0a7307b4..af9f162 100644
--- a/remoting/host/desktop_capturer_proxy.cc
+++ b/remoting/host/desktop_capturer_proxy.cc
@@ -40,7 +40,8 @@
 
  private:
   // webrtc::DesktopCapturer::Callback implementation.
-  void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override;
 
   base::ThreadChecker thread_checker_;
 
@@ -93,17 +94,18 @@
   if (capturer_) {
     capturer_->Capture(rect);
   } else {
-    OnCaptureCompleted(nullptr);
+    OnCaptureResult(webrtc::DesktopCapturer::Result::ERROR_PERMANENT, nullptr);
   }
 }
 
-void DesktopCapturerProxy::Core::OnCaptureCompleted(
-    webrtc::DesktopFrame* frame) {
+void DesktopCapturerProxy::Core::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   caller_task_runner_->PostTask(
       FROM_HERE, base::Bind(&DesktopCapturerProxy::OnFrameCaptured, proxy_,
-                            base::Passed(base::WrapUnique(frame))));
+                            result, base::Passed(&frame)));
 }
 
 DesktopCapturerProxy::DesktopCapturerProxy(
@@ -152,10 +154,11 @@
 }
 
 void DesktopCapturerProxy::OnFrameCaptured(
+    webrtc::DesktopCapturer::Result result,
     std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  callback_->OnCaptureCompleted(frame.release());
+  callback_->OnCaptureResult(result, std::move(frame));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/desktop_capturer_proxy.h b/remoting/host/desktop_capturer_proxy.h
index 0f6c8a02..d92c31c8 100644
--- a/remoting/host/desktop_capturer_proxy.h
+++ b/remoting/host/desktop_capturer_proxy.h
@@ -45,7 +45,8 @@
  private:
   class Core;
 
-  void OnFrameCaptured(std::unique_ptr<webrtc::DesktopFrame> frame);
+  void OnFrameCaptured(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame);
 
   base::ThreadChecker thread_checker_;
 
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc
index 628d1c9..200c334 100644
--- a/remoting/host/desktop_session_agent.cc
+++ b/remoting/host/desktop_session_agent.cc
@@ -321,11 +321,11 @@
   mouse_cursor_monitor_->Init(this, webrtc::MouseCursorMonitor::SHAPE_ONLY);
 }
 
-void DesktopSessionAgent::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
+void DesktopSessionAgent::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
 
-  last_frame_.reset(frame);
-
   // Serialize webrtc::DesktopFrame.
   SerializedDesktopFrame serialized_frame;
   if (frame) {
@@ -340,8 +340,10 @@
     }
   }
 
+  last_frame_ = std::move(frame);
+
   SendToNetwork(base::WrapUnique(
-      new ChromotingDesktopNetworkMsg_CaptureCompleted(serialized_frame)));
+      new ChromotingDesktopNetworkMsg_CaptureResult(result, serialized_frame)));
 }
 
 void DesktopSessionAgent::OnMouseCursor(webrtc::MouseCursor* cursor) {
diff --git a/remoting/host/desktop_session_agent.h b/remoting/host/desktop_session_agent.h
index 554d27f..5f6da59 100644
--- a/remoting/host/desktop_session_agent.h
+++ b/remoting/host/desktop_session_agent.h
@@ -78,7 +78,8 @@
   void OnChannelError() override;
 
   // webrtc::DesktopCapturer::Callback implementation.
-  void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override;
 
   // webrtc::MouseCursorMonitor::Callback implementation.
   void OnMouseCursor(webrtc::MouseCursor* cursor) override;
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc
index 2cd68c3d..636c177 100644
--- a/remoting/host/desktop_session_proxy.cc
+++ b/remoting/host/desktop_session_proxy.cc
@@ -178,8 +178,8 @@
   IPC_BEGIN_MESSAGE_MAP(DesktopSessionProxy, message)
     IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_AudioPacket,
                         OnAudioPacket)
-    IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CaptureCompleted,
-                        OnCaptureCompleted)
+    IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CaptureResult,
+                        OnCaptureResult)
     IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_MouseCursor,
                         OnMouseCursor)
     IPC_MESSAGE_HANDLER(ChromotingDesktopNetworkMsg_CreateSharedBuffer,
@@ -262,7 +262,8 @@
   // Generate fake responses to keep the video capturer in sync.
   while (pending_capture_frame_requests_) {
     --pending_capture_frame_requests_;
-    video_capturer_->OnCaptureCompleted(nullptr);
+    video_capturer_->OnCaptureResult(
+        webrtc::DesktopCapturer::Result::ERROR_PERMANENT, nullptr);
   }
 }
 
@@ -280,7 +281,8 @@
     ++pending_capture_frame_requests_;
     SendToDesktop(new ChromotingNetworkDesktopMsg_CaptureFrame());
   } else {
-    video_capturer_->OnCaptureCompleted(nullptr);
+    video_capturer_->OnCaptureResult(
+        webrtc::DesktopCapturer::Result::ERROR_PERMANENT, nullptr);
   }
 }
 
@@ -467,16 +469,15 @@
   shared_buffers_.erase(id);
 }
 
-void DesktopSessionProxy::OnCaptureCompleted(
+void DesktopSessionProxy::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
     const SerializedDesktopFrame& serialized_frame) {
   DCHECK(caller_task_runner_->BelongsToCurrentThread());
 
   --pending_capture_frame_requests_;
 
-  // If the input serialized_frame does not have a screen size, it means the
-  // capturer returns a nullptr for OnCaptureCompleted call.
-  if (serialized_frame.dimensions.is_empty()) {
-    video_capturer_->OnCaptureCompleted(nullptr);
+  if (result != webrtc::DesktopCapturer::Result::SUCCESS) {
+    video_capturer_->OnCaptureResult(result, nullptr);
     return;
   }
 
@@ -493,11 +494,12 @@
   frame->set_capture_time_ms(serialized_frame.capture_time_ms);
   frame->set_dpi(serialized_frame.dpi);
 
-  for (size_t i = 0; i < serialized_frame.dirty_region.size(); ++i) {
-    frame->mutable_updated_region()->AddRect(serialized_frame.dirty_region[i]);
+  for (const auto& rect : serialized_frame.dirty_region) {
+    frame->mutable_updated_region()->AddRect(rect);
   }
 
-  video_capturer_->OnCaptureCompleted(std::move(frame));
+  video_capturer_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
+                                   std::move(frame));
 }
 
 void DesktopSessionProxy::OnMouseCursor(
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h
index 133df7c..5559146 100644
--- a/remoting/host/desktop_session_proxy.h
+++ b/remoting/host/desktop_session_proxy.h
@@ -160,8 +160,9 @@
   // Drops a cached reference to the shared buffer.
   void OnReleaseSharedBuffer(int id);
 
-  // Handles CaptureCompleted notification from the desktop session agent.
-  void OnCaptureCompleted(const SerializedDesktopFrame& serialized_frame);
+  // Handles CaptureResult notification from the desktop session agent.
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       const SerializedDesktopFrame& serialized_frame);
 
   // Handles MouseCursor notification from the desktop session agent.
   void OnMouseCursor(const webrtc::MouseCursor& mouse_cursor);
diff --git a/remoting/host/ipc_desktop_environment_unittest.cc b/remoting/host/ipc_desktop_environment_unittest.cc
index a7491c0..c7965f2 100644
--- a/remoting/host/ipc_desktop_environment_unittest.cc
+++ b/remoting/host/ipc_desktop_environment_unittest.cc
@@ -66,7 +66,13 @@
   MockScreenCapturerCallback() {}
   virtual ~MockScreenCapturerCallback() {}
 
-  MOCK_METHOD1(OnCaptureCompleted, void(webrtc::DesktopFrame*));
+  MOCK_METHOD2(OnCaptureResultPtr,
+               void(webrtc::DesktopCapturer::Result result,
+                    std::unique_ptr<webrtc::DesktopFrame>* frame));
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override {
+    OnCaptureResultPtr(result, &frame);
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockScreenCapturerCallback);
@@ -543,11 +549,9 @@
   setup_run_loop_->Run();
 
   // Stop the test when the first frame is captured.
-  EXPECT_CALL(desktop_capturer_callback_, OnCaptureCompleted(_))
-      .WillOnce(DoAll(
-          DeleteArg<0>(),
-          InvokeWithoutArgs(
-              this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment)));
+  EXPECT_CALL(desktop_capturer_callback_, OnCaptureResultPtr(_, _))
+      .WillOnce(InvokeWithoutArgs(
+          this, &IpcDesktopEnvironmentTest::DeleteDesktopEnvironment));
 
   // Capture a single frame.
   video_capturer_->Capture(webrtc::DesktopRegion());
diff --git a/remoting/host/ipc_video_frame_capturer.cc b/remoting/host/ipc_video_frame_capturer.cc
index 23cc5e0..396d83ce 100644
--- a/remoting/host/ipc_video_frame_capturer.cc
+++ b/remoting/host/ipc_video_frame_capturer.cc
@@ -33,11 +33,12 @@
   desktop_session_proxy_->CaptureFrame();
 }
 
-void IpcVideoFrameCapturer::OnCaptureCompleted(
+void IpcVideoFrameCapturer::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
     std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(capture_pending_);
   capture_pending_ = false;
-  callback_->OnCaptureCompleted(frame.release());
+  callback_->OnCaptureResult(result, std::move(frame));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/ipc_video_frame_capturer.h b/remoting/host/ipc_video_frame_capturer.h
index c93e2ba..c96970c 100644
--- a/remoting/host/ipc_video_frame_capturer.h
+++ b/remoting/host/ipc_video_frame_capturer.h
@@ -29,7 +29,8 @@
   void Capture(const webrtc::DesktopRegion& region) override;
 
   // Called when a video |frame| has been captured.
-  void OnCaptureCompleted(std::unique_ptr<webrtc::DesktopFrame> frame);
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame);
 
  private:
   // Points to the callback passed to webrtc::DesktopCapturer::Start().
diff --git a/remoting/protocol/connection_unittest.cc b/remoting/protocol/connection_unittest.cc
index 7e639cc..be04b6c7 100644
--- a/remoting/protocol/connection_unittest.cc
+++ b/remoting/protocol/connection_unittest.cc
@@ -84,7 +84,8 @@
           webrtc::DesktopRect::MakeSize(frame->size()));
     }
 
-    callback_->OnCaptureCompleted(frame.release());
+    callback_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
+                               std::move(frame));
   }
 
  private:
diff --git a/remoting/protocol/fake_desktop_capturer.cc b/remoting/protocol/fake_desktop_capturer.cc
index 9b15e9a..f6042fd 100644
--- a/remoting/protocol/fake_desktop_capturer.cc
+++ b/remoting/protocol/fake_desktop_capturer.cc
@@ -153,7 +153,10 @@
     frame->set_capture_time_ms(
         (base::Time::Now() - capture_start_time).InMillisecondsRoundedUp());
   }
-  callback_->OnCaptureCompleted(frame.release());
+  callback_->OnCaptureResult(
+      frame ? webrtc::DesktopCapturer::Result::SUCCESS
+            : webrtc::DesktopCapturer::Result::ERROR_TEMPORARY,
+      std::move(frame));
 }
 
 }  // namespace protocol
diff --git a/remoting/protocol/video_frame_pump.cc b/remoting/protocol/video_frame_pump.cc
index ab98abc..e2882ad7 100644
--- a/remoting/protocol/video_frame_pump.cc
+++ b/remoting/protocol/video_frame_pump.cc
@@ -112,7 +112,9 @@
   size_callback_ = size_callback;
 }
 
-void VideoFramePump::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
+void VideoFramePump::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   capture_scheduler_.OnCaptureCompleted();
@@ -137,7 +139,7 @@
   base::PostTaskAndReplyWithResult(
       encode_task_runner_.get(), FROM_HERE,
       base::Bind(&VideoFramePump::EncodeFrame, encoder_.get(),
-                 base::Passed(base::WrapUnique(frame)),
+                 base::Passed(&frame),
                  base::Passed(&captured_frame_timestamps_)),
       base::Bind(&VideoFramePump::OnFrameEncoded, weak_factory_.GetWeakPtr()));
 }
diff --git a/remoting/protocol/video_frame_pump.h b/remoting/protocol/video_frame_pump.h
index 3ca5a21..3b774ce0 100644
--- a/remoting/protocol/video_frame_pump.h
+++ b/remoting/protocol/video_frame_pump.h
@@ -122,7 +122,8 @@
   };
 
   // webrtc::DesktopCapturer::Callback interface.
-  void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override;
 
   // Callback for CaptureScheduler.
   void CaptureNextFrame();
diff --git a/remoting/protocol/video_frame_pump_unittest.cc b/remoting/protocol/video_frame_pump_unittest.cc
index 18c041f..34d8f31 100644
--- a/remoting/protocol/video_frame_pump_unittest.cc
+++ b/remoting/protocol/video_frame_pump_unittest.cc
@@ -118,7 +118,8 @@
         new webrtc::BasicDesktopFrame(webrtc::DesktopSize(kWidth, kHeight)));
     frame->mutable_updated_region()->SetRect(
         webrtc::DesktopRect::MakeXYWH(0, 0, 10, 10));
-    callback_->OnCaptureCompleted(frame.release());
+    callback_->OnCaptureResult(webrtc::DesktopCapturer::Result::SUCCESS,
+                               std::move(frame));
   }
 
  private:
diff --git a/remoting/protocol/webrtc_frame_scheduler.cc b/remoting/protocol/webrtc_frame_scheduler.cc
index 9dbd21f..0cab3d2 100644
--- a/remoting/protocol/webrtc_frame_scheduler.cc
+++ b/remoting/protocol/webrtc_frame_scheduler.cc
@@ -118,7 +118,9 @@
   return key_frame_request;
 }
 
-void WebrtcFrameScheduler::OnCaptureCompleted(webrtc::DesktopFrame* frame) {
+void WebrtcFrameScheduler::OnCaptureResult(
+    webrtc::DesktopCapturer::Result result,
+    std::unique_ptr<webrtc::DesktopFrame> frame) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   base::TimeTicks captured_ticks = base::TimeTicks::Now();
@@ -126,7 +128,7 @@
       (captured_ticks - base::TimeTicks()).InMilliseconds();
   capture_pending_ = false;
 
-  std::unique_ptr<webrtc::DesktopFrame> owned_frame(frame);
+  // TODO(sergeyu): Handle ERROR_PERMANENT result here.
 
   if (encode_pending_) {
     // TODO(isheriff): consider queuing here
@@ -150,7 +152,7 @@
   task_tracker_.PostTaskAndReplyWithResult(
       encode_task_runner_.get(), FROM_HERE,
       base::Bind(&WebrtcFrameScheduler::EncodeFrame, encoder_.get(),
-                 base::Passed(std::move(owned_frame)), target_bitrate_kbps_,
+                 base::Passed(&frame), target_bitrate_kbps_,
                  ClearAndGetKeyFrameRequest(), capture_timestamp_ms),
       base::Bind(&WebrtcFrameScheduler::OnFrameEncoded,
                  weak_factory_.GetWeakPtr()));
diff --git a/remoting/protocol/webrtc_frame_scheduler.h b/remoting/protocol/webrtc_frame_scheduler.h
index e575a5d..363eac15 100644
--- a/remoting/protocol/webrtc_frame_scheduler.h
+++ b/remoting/protocol/webrtc_frame_scheduler.h
@@ -45,7 +45,8 @@
 
  private:
   // webrtc::DesktopCapturer::Callback interface.
-  void OnCaptureCompleted(webrtc::DesktopFrame* frame) override;
+  void OnCaptureResult(webrtc::DesktopCapturer::Result result,
+                       std::unique_ptr<webrtc::DesktopFrame> frame) override;
 
   // Starts |capture_timer_|.
   void StartCaptureTimer();
diff --git a/services/shell/public/cpp/BUILD.gn b/services/shell/public/cpp/BUILD.gn
index 9bef5f5..f179341 100644
--- a/services/shell/public/cpp/BUILD.gn
+++ b/services/shell/public/cpp/BUILD.gn
@@ -33,10 +33,12 @@
     "lib/interface_factory_binder.h",
     "lib/interface_registry.cc",
     "lib/names.cc",
+    "lib/remote_interface_registry.cc",
     "lib/shell_client.cc",
     "lib/shell_connection.cc",
     "lib/shell_connection_ref.cc",
     "names.h",
+    "remote_interface_registry.h",
     "shell_client.h",
     "shell_connection.h",
     "shell_connection_ref.h",
diff --git a/services/shell/public/cpp/connection.h b/services/shell/public/cpp/connection.h
index 56834d8..74760ae75 100644
--- a/services/shell/public/cpp/connection.h
+++ b/services/shell/public/cpp/connection.h
@@ -14,12 +14,14 @@
 #include "services/shell/public/cpp/connect.h"
 #include "services/shell/public/cpp/identity.h"
 #include "services/shell/public/cpp/interface_registry.h"
+#include "services/shell/public/cpp/remote_interface_registry.h"
 #include "services/shell/public/interfaces/connector.mojom.h"
 #include "services/shell/public/interfaces/interface_provider.mojom.h"
 
 namespace shell {
 
 class InterfaceBinder;
+class RemoteInterfaceRegistry;
 
 // Represents a connection to another application. An instance of this class is
 // returned from Shell's ConnectToApplication(), and passed to ShellClient's
@@ -86,7 +88,7 @@
   // interface.
   template <typename Interface>
   void GetInterface(mojo::InterfacePtr<Interface>* ptr) {
-    GetInterfaceRegistry()->GetInterface(ptr);
+    GetRemoteInterfaceRegistry()->GetInterface(ptr);
   }
 
   // Returns true if the remote application has the specified capability class
@@ -138,11 +140,17 @@
   // remote application.
   virtual bool AllowsInterface(const std::string& interface_name) const = 0;
 
-  // Returns the InterfaceRegistry that encapsulates the pair of
-  // InterfaceProviders between this application and the remote.
-  virtual InterfaceRegistry* GetInterfaceRegistry() = 0;
+  // Returns a raw pointer to the InterfaceProvider at the remote end.
+  virtual mojom::InterfaceProvider* GetRemoteInterfaceProvider() = 0;
 
  protected:
+  // Returns the InterfaceRegistry that implements the mojom::InterfaceProvider
+  // exposed to the remote application.
+  virtual InterfaceRegistry* GetInterfaceRegistry() = 0;
+
+  // Returns an object encapsulating a remote InterfaceProvider.
+  virtual RemoteInterfaceRegistry* GetRemoteInterfaceRegistry() = 0;
+
   virtual base::WeakPtr<Connection> GetWeakPtr() = 0;
 };
 
diff --git a/services/shell/public/cpp/interface_registry.h b/services/shell/public/cpp/interface_registry.h
index e2c26332..81bd3654 100644
--- a/services/shell/public/cpp/interface_registry.h
+++ b/services/shell/public/cpp/interface_registry.h
@@ -51,10 +51,6 @@
           base::WrapUnique(binder), interface_name);
     }
 
-    void RemoveInterfaceBinderForName(const std::string& interface_name) {
-      registry_->RemoveInterfaceBinderForName(interface_name);
-    }
-
    private:
     InterfaceRegistry* registry_;
     DISALLOW_COPY_AND_ASSIGN(TestApi);
@@ -66,23 +62,9 @@
   // rules filtering which interfaces are allowed to be exposed to clients are
   // imposed on this registry. If null, they are not.
   explicit InterfaceRegistry(Connection* connection);
-  // Construct with an InterfaceProviderRequest and a Connection (which may be
-  // null, see note above about filtering).
-  InterfaceRegistry(mojom::InterfaceProviderPtr remote_interfaces,
-                    mojom::InterfaceProviderRequest local_interfaces_request,
-                    Connection* connection);
   ~InterfaceRegistry() override;
 
-  // Takes the client end of the InterfaceProvider pipe created in the
-  // constructor.
-  mojom::InterfaceProviderPtr TakeClientHandle();
-
-  // Returns a raw pointer to the remote InterfaceProvider.
-  mojom::InterfaceProvider* GetRemoteInterfaces();
-
-  // Sets a closure to be run when the remote InterfaceProvider pipe is closed.
-  void SetRemoteInterfacesConnectionLostClosure(
-      const base::Closure& connection_lost_closure);
+  void Bind(mojom::InterfaceProviderRequest local_interfaces_request);
 
   // Allows |Interface| to be exposed via this registry. Requests to bind will
   // be handled by |factory|. Returns true if the interface was exposed, false
@@ -109,23 +91,11 @@
         Interface::Name_);
   }
 
-  // Binds |ptr| to an implementation of Interface in the remote application.
-  // |ptr| can immediately be used to start sending requests to the remote
-  // interface.
   template <typename Interface>
-  void GetInterface(mojo::InterfacePtr<Interface>* ptr) {
-    mojo::MessagePipe pipe;
-    ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
-
-    // Local binders can be registered via TestApi.
-    auto it = name_to_binder_.find(Interface::Name_);
-    if (it != name_to_binder_.end()) {
-      it->second->BindInterface(connection_, Interface::Name_,
-                                std::move(pipe.handle1));
-      return;
-    }
-    remote_interfaces_->GetInterface(Interface::Name_, std::move(pipe.handle1));
+  void RemoveInterface() {
+    RemoveInterface(Interface::Name_);
   }
+  void RemoveInterface(const std::string& name);
 
  private:
   using NameToInterfaceBinderMap =
@@ -140,16 +110,11 @@
   bool SetInterfaceBinderForName(std::unique_ptr<InterfaceBinder> binder,
                                  const std::string& name);
 
-  void RemoveInterfaceBinderForName(const std::string& interface_name);
-
-  mojom::InterfaceProviderPtr client_handle_;
   mojo::Binding<mojom::InterfaceProvider> binding_;
   Connection* connection_;
 
   NameToInterfaceBinderMap name_to_binder_;
 
-  mojom::InterfaceProviderPtr remote_interfaces_;
-
   DISALLOW_COPY_AND_ASSIGN(InterfaceRegistry);
 };
 
diff --git a/services/shell/public/cpp/lib/connection_impl.cc b/services/shell/public/cpp/lib/connection_impl.cc
index acafa89e..d6ebd70f 100644
--- a/services/shell/public/cpp/lib/connection_impl.cc
+++ b/services/shell/public/cpp/lib/connection_impl.cc
@@ -31,18 +31,18 @@
       remote_(remote),
       remote_id_(remote_id),
       state_(initial_state),
-      interfaces_(std::move(remote_interfaces),
-                  std::move(local_interfaces),
-                  this),
+      interfaces_(this),
+      remote_interfaces_(std::move(remote_interfaces)),
       capability_request_(capability_request),
       allow_all_interfaces_(capability_request.interfaces.size() == 1 &&
                             capability_request.interfaces.count("*") == 1),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+  interfaces_.Bind(std::move(local_interfaces));
+}
 
 ConnectionImpl::ConnectionImpl()
-    : interfaces_(shell::mojom::InterfaceProviderPtr(),
-                  shell::mojom::InterfaceProviderRequest(),
-                  this),
+    : interfaces_(this),
+      remote_interfaces_(nullptr),
       allow_all_interfaces_(true),
       weak_factory_(this) {}
 
@@ -69,7 +69,7 @@
 }
 
 void ConnectionImpl::SetConnectionLostClosure(const base::Closure& handler) {
-  interfaces_.SetRemoteInterfacesConnectionLostClosure(handler);
+  remote_interfaces_.SetConnectionLostClosure(handler);
 }
 
 shell::mojom::ConnectResult ConnectionImpl::GetResult() const {
@@ -97,10 +97,18 @@
          capability_request_.interfaces.count(interface_name);
 }
 
+mojom::InterfaceProvider* ConnectionImpl::GetRemoteInterfaceProvider() {
+  return remote_interfaces_.GetInterfaceProvider();
+}
+
 InterfaceRegistry* ConnectionImpl::GetInterfaceRegistry() {
   return &interfaces_;
 }
 
+RemoteInterfaceRegistry* ConnectionImpl::GetRemoteInterfaceRegistry() {
+  return &remote_interfaces_;
+}
+
 base::WeakPtr<Connection> ConnectionImpl::GetWeakPtr() {
   return weak_factory_.GetWeakPtr();
 }
diff --git a/services/shell/public/cpp/lib/connection_impl.h b/services/shell/public/cpp/lib/connection_impl.h
index b0ec989d..9710960 100644
--- a/services/shell/public/cpp/lib/connection_impl.h
+++ b/services/shell/public/cpp/lib/connection_impl.h
@@ -51,7 +51,9 @@
   uint32_t GetRemoteInstanceID() const override;
   void AddConnectionCompletedClosure(const mojo::Closure& callback) override;
   bool AllowsInterface(const std::string& interface_name) const override;
+  mojom::InterfaceProvider* GetRemoteInterfaceProvider() override;
   InterfaceRegistry* GetInterfaceRegistry() override;
+  RemoteInterfaceRegistry* GetRemoteInterfaceRegistry() override;
   base::WeakPtr<Connection> GetWeakPtr() override;
 
   void OnConnectionCompleted(shell::mojom::ConnectResult result,
@@ -67,6 +69,7 @@
   std::vector<mojo::Closure> connection_completed_callbacks_;
 
   InterfaceRegistry interfaces_;
+  RemoteInterfaceRegistry remote_interfaces_;
 
   const CapabilityRequest capability_request_;
   const bool allow_all_interfaces_;
diff --git a/services/shell/public/cpp/lib/interface_registry.cc b/services/shell/public/cpp/lib/interface_registry.cc
index d248dae..a4657b2 100644
--- a/services/shell/public/cpp/lib/interface_registry.cc
+++ b/services/shell/public/cpp/lib/interface_registry.cc
@@ -9,33 +9,19 @@
 namespace shell {
 
 InterfaceRegistry::InterfaceRegistry(Connection* connection)
-    : InterfaceRegistry(nullptr, nullptr, connection) {}
+    : binding_(this), connection_(connection) {}
+InterfaceRegistry::~InterfaceRegistry() {}
 
-InterfaceRegistry::InterfaceRegistry(
-    mojom::InterfaceProviderPtr remote_interfaces,
-    mojom::InterfaceProviderRequest local_interfaces_request,
-    Connection* connection)
-    : binding_(this),
-      connection_(connection),
-      remote_interfaces_(std::move(remote_interfaces)) {
-  if (!local_interfaces_request.is_pending())
-    local_interfaces_request = GetProxy(&client_handle_);
+void InterfaceRegistry::Bind(
+    mojom::InterfaceProviderRequest local_interfaces_request) {
+  DCHECK(!binding_.is_bound());
   binding_.Bind(std::move(local_interfaces_request));
 }
 
-InterfaceRegistry::~InterfaceRegistry() {}
-
-mojom::InterfaceProviderPtr InterfaceRegistry::TakeClientHandle() {
-  return std::move(client_handle_);
-}
-
-mojom::InterfaceProvider* InterfaceRegistry::GetRemoteInterfaces() {
-  return remote_interfaces_.get();
-}
-
-void InterfaceRegistry::SetRemoteInterfacesConnectionLostClosure(
-    const base::Closure& connection_lost_closure) {
-  remote_interfaces_.set_connection_error_handler(connection_lost_closure);
+void InterfaceRegistry::RemoveInterface(const std::string& name) {
+  auto it = name_to_binder_.find(name);
+  if (it != name_to_binder_.end())
+    name_to_binder_.erase(it);
 }
 
 // mojom::InterfaceProvider:
@@ -57,19 +43,11 @@
     const std::string& interface_name) {
   if (!connection_ ||
       (connection_ && connection_->AllowsInterface(interface_name))) {
-    RemoveInterfaceBinderForName(interface_name);
+    RemoveInterface(interface_name);
     name_to_binder_[interface_name] = std::move(binder);
     return true;
   }
   return false;
 }
 
-void InterfaceRegistry::RemoveInterfaceBinderForName(
-    const std::string& interface_name) {
-  NameToInterfaceBinderMap::iterator it = name_to_binder_.find(interface_name);
-  if (it == name_to_binder_.end())
-    return;
-  name_to_binder_.erase(it);
-}
-
 }  // namespace shell
diff --git a/services/shell/public/cpp/lib/remote_interface_registry.cc b/services/shell/public/cpp/lib/remote_interface_registry.cc
new file mode 100644
index 0000000..5915e182
--- /dev/null
+++ b/services/shell/public/cpp/lib/remote_interface_registry.cc
@@ -0,0 +1,33 @@
+// 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 "services/shell/public/cpp/remote_interface_registry.h"
+
+namespace shell {
+
+RemoteInterfaceRegistry::RemoteInterfaceRegistry(
+    mojom::InterfaceProviderPtr remote_interfaces)
+    : remote_interfaces_(std::move(remote_interfaces)) {}
+RemoteInterfaceRegistry::~RemoteInterfaceRegistry() {}
+
+mojom::InterfaceProvider* RemoteInterfaceRegistry::GetInterfaceProvider() {
+  return remote_interfaces_.get();
+}
+
+void RemoteInterfaceRegistry::SetConnectionLostClosure(
+    const base::Closure& connection_lost_closure) {
+  remote_interfaces_.set_connection_error_handler(connection_lost_closure);
+}
+
+void RemoteInterfaceRegistry::GetInterface(
+    const std::string& name,
+    mojo::ScopedMessagePipeHandle request_handle) {
+  remote_interfaces_->GetInterface(name, std::move(request_handle));
+}
+
+void RemoteInterfaceRegistry::ClearBinders() {
+  binders_.clear();
+}
+
+}  // namespace shell
diff --git a/services/shell/public/cpp/remote_interface_registry.h b/services/shell/public/cpp/remote_interface_registry.h
new file mode 100644
index 0000000..7840cdf
--- /dev/null
+++ b/services/shell/public/cpp/remote_interface_registry.h
@@ -0,0 +1,95 @@
+// 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 SERVICES_SHELL_PUBLIC_CPP_REMOTE_INTERFACE_REGISTRY_H_
+#define SERVICES_SHELL_PUBLIC_CPP_REMOTE_INTERFACE_REGISTRY_H_
+
+#include "services/shell/public/interfaces/interface_provider.mojom.h"
+
+namespace shell {
+
+// Encapsulates a mojom::InterfaceProviderPtr implemented in a remote
+// application. Provides two main features:
+// - a typesafe GetInterface() method for binding InterfacePtrs.
+// - a testing API that allows local callbacks to be registered that bind
+//   requests for remote interfaces.
+// An instance of this class is used by the GetInterface() methods on
+// Connection.
+class RemoteInterfaceRegistry {
+ public:
+  class TestApi {
+   public:
+    explicit TestApi(RemoteInterfaceRegistry* registry) : registry_(registry) {}
+    ~TestApi() {}
+
+    template <typename Interface>
+    void SetBinderForName(
+        const std::string& name,
+        const base::Callback<void(mojo::InterfaceRequest<Interface>)>& binder) {
+      registry_->SetBinderForName(name, binder);
+    }
+
+    void ClearBinders() {
+      registry_->ClearBinders();
+    }
+
+   private:
+    RemoteInterfaceRegistry* registry_;
+    DISALLOW_COPY_AND_ASSIGN(TestApi);
+  };
+
+  explicit RemoteInterfaceRegistry(
+      mojom::InterfaceProviderPtr remote_interfaces);
+  ~RemoteInterfaceRegistry();
+
+  // Returns a raw pointer to the remote InterfaceProvider.
+  mojom::InterfaceProvider* GetInterfaceProvider();
+
+  // Sets a closure to be run when the remote InterfaceProvider pipe is closed.
+  void SetConnectionLostClosure(const base::Closure& connection_lost_closure);
+
+  // Binds |ptr| to an implementation of Interface in the remote application.
+  // |ptr| can immediately be used to start sending requests to the remote
+  // interface.
+  template <typename Interface>
+  void GetInterface(mojo::InterfacePtr<Interface>* ptr) {
+    mojo::MessagePipe pipe;
+    ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
+
+    // Local binders can be registered via TestApi.
+    auto it = binders_.find(Interface::Name_);
+    if (it != binders_.end()) {
+      it->second.Run(std::move(pipe.handle1));
+      return;
+    }
+    remote_interfaces_->GetInterface(Interface::Name_, std::move(pipe.handle1));
+  }
+  template <typename Interface>
+  void GetInterface(mojo::InterfaceRequest<Interface> request) {
+    GetInterface(Interface::Name_, std::move(request.PassMessagePipe()));
+  }
+  void GetInterface(const std::string& name,
+                    mojo::ScopedMessagePipeHandle request_handle);
+
+ private:
+  template <typename Interface>
+  void SetBinderForName(
+      const std::string& name,
+      const base::Callback<void(mojo::InterfaceRequest<Interface>)>& binder) {
+    binders_[name] = binder;
+  }
+  void ClearBinders();
+
+  using BinderMap = std::map<
+      std::string, base::Callback<void(mojo::ScopedMessagePipeHandle)>>;
+  BinderMap binders_;
+
+  mojom::InterfaceProviderPtr remote_interfaces_;
+
+  DISALLOW_COPY_AND_ASSIGN(RemoteInterfaceRegistry);
+};
+
+}  // namespace shell
+
+#endif  // SERVICES_SHELL_PUBLIC_CPP_REMOTE_INTERFACE_REGISTRY_H_
diff --git a/services/shell/public/cpp/tests/interface_registry_unittest.cc b/services/shell/public/cpp/tests/interface_registry_unittest.cc
index 614248f..fbe6804 100644
--- a/services/shell/public/cpp/tests/interface_registry_unittest.cc
+++ b/services/shell/public/cpp/tests/interface_registry_unittest.cc
@@ -42,7 +42,7 @@
     InterfaceBinder* b = new TestBinder(&delete_count);
     InterfaceRegistry::TestApi test_api(registry.get());
     test_api.SetInterfaceBinderForName(b, "TC1");
-    test_api.RemoveInterfaceBinderForName("TC1");
+    registry->RemoveInterface("TC1");
     registry.reset();
     EXPECT_EQ(2, delete_count);
   }
diff --git a/services/shell/shell_public.gyp b/services/shell/shell_public.gyp
index c8b2487..0b8f078 100644
--- a/services/shell/shell_public.gyp
+++ b/services/shell/shell_public.gyp
@@ -55,10 +55,12 @@
       'public/cpp/lib/interface_factory_binder.h',
       'public/cpp/lib/interface_registry.cc',
       'public/cpp/lib/names.cc',
+      'public/cpp/lib/remote_interface_registry.cc',
       'public/cpp/lib/shell_client.cc',
       'public/cpp/lib/shell_connection.cc',
       'public/cpp/lib/shell_connection_ref.cc',
       'public/cpp/names.h',
+      'public/cpp/remote_interface_registry.h',
       'public/cpp/shell_client.h',
       'public/cpp/shell_connection.h',
       'public/cpp/shell_connection_ref.h',
diff --git a/testing/buildbot/trybot_analyze_config.json b/testing/buildbot/trybot_analyze_config.json
index e36229d..3557e81 100644
--- a/testing/buildbot/trybot_analyze_config.json
+++ b/testing/buildbot/trybot_analyze_config.json
@@ -17,6 +17,7 @@
       "build/gyp_chromium",
       "build/linux/sysroot_ld_path.sh",
       "build/toolchain/get_concurrent_links.py",
+      "build/toolchain/mac/*.py",
       "build/util/lib/common/unittest_util.py",
       "infra/.*",
       "DEPS",
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index 4644f8d..d3671df 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -288,3 +288,13 @@
   libfuzzer_options = [ "max_len=1024" ]
   seed_corpus = "//testing/libfuzzer/fuzzers/flatbuffers_corpus"
 }
+
+fuzzer_test("skia_path_fuzzer") {
+  sources = [
+    "skia_path_fuzzer.cc",
+  ]
+  deps = [
+    "//skia",
+  ]
+  libfuzzer_options = [ "max_len=256" ]
+}
diff --git a/testing/libfuzzer/fuzzers/skia_path_fuzzer.cc b/testing/libfuzzer/fuzzers/skia_path_fuzzer.cc
new file mode 100644
index 0000000..110ea46b
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/skia_path_fuzzer.cc
@@ -0,0 +1,135 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+// We specifically don't want to include kDone_Verb.
+const int kLastVerb = SkPath::Verb::kClose_Verb;
+
+template <typename T>
+static bool read(const uint8_t** data, size_t* size, T* value) {
+  if (*size < sizeof(T))
+    return false;
+
+  *value = *reinterpret_cast<const T*>(*data);
+  *data += sizeof(T);
+  *size -= sizeof(T);
+  return true;
+}
+
+void BuildPath(const uint8_t* data, size_t size, SkPath* path) {
+  uint8_t operation;
+  SkScalar a, b, c, d, e, f;
+  while (read<uint8_t>(&data, &size, &operation)) {
+    switch (operation % (kLastVerb + 1)) {
+      case SkPath::Verb::kMove_Verb:
+        if (!read<SkScalar>(&data, &size, &a) ||
+            !read<SkScalar>(&data, &size, &b))
+          return;
+        path->moveTo(a, b);
+        break;
+
+      case SkPath::Verb::kLine_Verb:
+        if (!read<SkScalar>(&data, &size, &a) ||
+            !read<SkScalar>(&data, &size, &b))
+          return;
+        path->lineTo(a, b);
+        break;
+
+      case SkPath::Verb::kQuad_Verb:
+        if (!read<SkScalar>(&data, &size, &a) ||
+            !read<SkScalar>(&data, &size, &b) ||
+            !read<SkScalar>(&data, &size, &c) ||
+            !read<SkScalar>(&data, &size, &d))
+          return;
+        path->quadTo(a, b, c, d);
+        break;
+
+      case SkPath::Verb::kConic_Verb:
+        if (!read<SkScalar>(&data, &size, &a) ||
+            !read<SkScalar>(&data, &size, &b) ||
+            !read<SkScalar>(&data, &size, &c) ||
+            !read<SkScalar>(&data, &size, &d) ||
+            !read<SkScalar>(&data, &size, &e))
+          return;
+        path->conicTo(a, b, c, d, e);
+        break;
+
+      case SkPath::Verb::kCubic_Verb:
+        if (!read<SkScalar>(&data, &size, &a) ||
+            !read<SkScalar>(&data, &size, &b) ||
+            !read<SkScalar>(&data, &size, &c) ||
+            !read<SkScalar>(&data, &size, &d) ||
+            !read<SkScalar>(&data, &size, &e) ||
+            !read<SkScalar>(&data, &size, &f))
+          return;
+        path->cubicTo(a, b, c, d, e, f);
+        break;
+
+      case SkPath::Verb::kClose_Verb:
+        path->close();
+        break;
+    }
+  }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  uint8_t w, h, anti_alias;
+  if (!read<uint8_t>(&data, &size, &w))
+    return 0;
+  if (!read<uint8_t>(&data, &size, &h))
+    return 0;
+  if (!read<uint8_t>(&data, &size, &anti_alias))
+    return 0;
+
+  SkScalar a, b, c, d;
+  if (!read<SkScalar>(&data, &size, &a))
+    return 0;
+  if (!read<SkScalar>(&data, &size, &b))
+    return 0;
+  if (!read<SkScalar>(&data, &size, &c))
+    return 0;
+  if (!read<SkScalar>(&data, &size, &d))
+    return 0;
+
+  // SkPath::readFromMemory does not seem to be able to handle arbitrary input.
+  SkPath path;
+  BuildPath(data, size, &path);
+
+  // Try a few potentially interesting things with our path.
+  path.contains(a, b);
+  path.conservativelyContainsRect(SkRect::MakeLTRB(a, b, c, d));
+
+  SkPaint paint_fill;
+  paint_fill.setStyle(SkPaint::Style::kFill_Style);
+  paint_fill.setAntiAlias(anti_alias & 1);
+
+  SkPaint paint_stroke;
+  paint_stroke.setStyle(SkPaint::Style::kStroke_Style);
+  paint_stroke.setStrokeWidth(1);
+  paint_stroke.setAntiAlias(anti_alias & 1);
+
+  SkPaint paint_stroke_and_fill;
+  paint_stroke_and_fill.setStyle(SkPaint::Style::kStrokeAndFill_Style);
+  paint_stroke_and_fill.setStrokeWidth(1);
+  paint_stroke_and_fill.setAntiAlias(anti_alias & 1);
+
+  SkPath dst_path;
+  paint_stroke.getFillPath(path, &dst_path, nullptr);
+
+  // Width and height should never be 0.
+  auto surface(SkSurface::MakeRasterN32Premul(w ? w : 1, h ? h : 1));
+
+  surface->getCanvas()->drawPath(path, paint_fill);
+  surface->getCanvas()->drawPath(path, paint_stroke);
+  surface->getCanvas()->drawPath(path, paint_stroke_and_fill);
+
+  return 0;
+}
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json
index e7140d2..22668382 100644
--- a/testing/variations/fieldtrial_testing_config_android.json
+++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -291,6 +291,14 @@
             "group_name": "Enabled"
         }
     ],
+    "ReadItLater": [
+        {
+            "enable_features": [
+                "ReadItLaterInMenu"
+            ],
+            "group_name": "Enabled"
+        }
+    ],
     "ReaderModeUI": [
         {
             "group_name": "AdaBoost"
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index ed3605d..bac56e3 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -270,9 +270,9 @@
 crbug.com/389648 crbug.com/517123 crbug.com/410145 fast/text-autosizing/table-inflation-crash.html [ Pass Crash Timeout ]
 crbug.com/419696 [ Mac Debug ] fast/text/font-linux-normalize.html [ Crash Pass ]
 
-crbug.com/569139 fast/js/string-replace-2.html [ NeedsManualRebaseline ]
-crbug.com/569139 fast/js/regexp-caching.html [ NeedsManualRebaseline ]
-crbug.com/597221 fast/dom/Window/window-postmessage-clone-deep-array.html [ NeedsManualRebaseline ]
+crbug.com/569139 fast/js/string-replace-2.html [ Failure ]
+crbug.com/569139 fast/js/regexp-caching.html [ Failure ]
+crbug.com/597221 fast/dom/Window/window-postmessage-clone-deep-array.html [ Failure ]
 
 crbug.com/498539 http/tests/inspector/elements/styles/selector-line.html [ Pass Timeout ]
 crbug.com/498539 http/tests/inspector/network/network-datareceived.html [ Pass Timeout ]
@@ -563,8 +563,8 @@
 
 crbug.com/517840 imported/wpt/webrtc/rtcpeerconnection/rtcpeerconnection-idl.html [ Failure Timeout ]
 
-crbug.com/603997 compositing/overflow/clear-scroll-parent.html [ NeedsManualRebaseline ]
-crbug.com/603997 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent.html [ NeedsManualRebaseline ]
+crbug.com/603997 compositing/overflow/clear-scroll-parent.html [ Failure ]
+crbug.com/603997 virtual/prefer_compositing_to_lcd_text/compositing/overflow/clear-scroll-parent.html [ Failure ]
 
 crbug.com/552494 scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
 crbug.com/552494 virtual/prefer_compositing_to_lcd_text/scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
@@ -1319,11 +1319,6 @@
 
 crbug.com/320139 fast/repaint/block-layout-inline-children-replaced.html [ Pass Failure ]
 
-crbug.com/620786 webaudio/audioparam-setTargetAtTime-continuous.html [ NeedsManualRebaseline ]
-crbug.com/620786 webaudio/audioparam-setTargetAtTime-limit.html [ NeedsManualRebaseline ]
-crbug.com/620786 webaudio/audioparam-setTargetAtTime-sampling.html [ NeedsManualRebaseline ]
-crbug.com/620786 webaudio/stereopannernode-no-glitch.html [ NeedsManualRebaseline ]
-
 crbug.com/575766 http/tests/inspector/resource-tree/resource-tree-frame-add.html [ Timeout Pass ]
 crbug.com/581468 http/tests/inspector/resource-tree/resource-tree-non-unique-url.html [ Pass Failure ]
 
@@ -1381,7 +1376,7 @@
 
 crbug.com/592185 fast/repaint/fixed-right-in-page-scale.html [ Failure Pass ]
 
-crbug.com/592409 inspector-protocol/debugger/stepping-with-blackboxed-ranges.html [ NeedsManualRebaseline ]
+crbug.com/592409 inspector-protocol/debugger/stepping-with-blackboxed-ranges.html [ Failure ]
 
 crbug.com/594595 [ Linux ] http/tests/security/mixedContent/websocket/insecure-websocket-in-secure-page-worker-allowed.html [ Timeout Pass ]
 
@@ -1427,16 +1422,16 @@
 crbug.com/610464 [ Win7 Debug ] inspector/components/throttler.html [ Failure Pass ]
 crbug.com/606649 fast/dom/gc-dom-tree-lifetime.html [ Pass Timeout ]
 
-crbug.com/620126 svg/repaint/inner-svg-change-viewBox-contract.svg [ NeedsManualRebaseline ]
-crbug.com/620126 svg/repaint/mask-clip-target-transform.svg [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/relative-sized-shadow-tree-content.xhtml [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/relative-sized-deep-shadow-tree-content.xhtml [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/relative-sized-content.xhtml [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/resource-invalidate-on-target-update.svg [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/marker-viewBox-changes.svg [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/relative-sized-image.xhtml [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/js-late-clipPath-and-object-creation.svg [ NeedsManualRebaseline ]
-crbug.com/620126 svg/custom/js-late-clipPath-creation.svg [ NeedsManualRebaseline ]
+crbug.com/620126 svg/repaint/inner-svg-change-viewBox-contract.svg [ Pass Failure ]
+crbug.com/620126 svg/repaint/mask-clip-target-transform.svg [ Pass Failure ]
+crbug.com/620126 svg/custom/relative-sized-shadow-tree-content.xhtml [ Pass Failure ]
+crbug.com/620126 svg/custom/relative-sized-deep-shadow-tree-content.xhtml [ Pass Failure ]
+crbug.com/620126 svg/custom/relative-sized-content.xhtml [ Pass Failure ]
+crbug.com/620126 svg/custom/resource-invalidate-on-target-update.svg [ Pass Failure ]
+crbug.com/620126 svg/custom/marker-viewBox-changes.svg [ Pass Failure ]
+crbug.com/620126 svg/custom/relative-sized-image.xhtml [ Pass Failure ]
+crbug.com/620126 svg/custom/js-late-clipPath-and-object-creation.svg [ Pass Failure ]
+crbug.com/620126 svg/custom/js-late-clipPath-creation.svg [ Pass Failure ]
 
 # Failure on Linux Trusty, temporarily disabled.
 crbug.com/621025 [ Linux ] svg/custom/text-match-highlight.html [ Failure ]
@@ -1506,27 +1501,27 @@
 crbug.com/609067 [ Mac ] bluetooth/writeValue/write-succeeds.html [ Skip ]
 crbug.com/609067 [ Mac ] bluetooth/writeValue/write-updates-value.html [ Skip ]
 
-crbug.com/487344 compositing/video/video-controls-layer-creation.html [ NeedsManualRebaseline ]
-crbug.com/487344 fast/hidpi/video-controls-in-hidpi.html [ NeedsManualRebaseline ]
-crbug.com/487344 fast/layers/video-layer.html [ NeedsManualRebaseline ]
-crbug.com/487344 http/tests/media/video-buffered-range-contains-currentTime.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/audio-controls-rendering.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/audio-repaint.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-after-reload.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-focus-ring.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-layout-direction.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-strict.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-styling.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-styling-strict.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/controls-without-preload.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/media-controls-clone.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/media-document-audio-repaint.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/video-controls-rendering.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/video-controls-with-cast-rendering.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/video-display-toggle.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/video-empty-source.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/video-no-audio.html [ NeedsManualRebaseline ]
-crbug.com/487344 media/video-paint-invalidation.html [ NeedsManualRebaseline ]
+crbug.com/487344 compositing/video/video-controls-layer-creation.html [ Failure ]
+crbug.com/487344 fast/hidpi/video-controls-in-hidpi.html [ Failure ]
+crbug.com/487344 fast/layers/video-layer.html [ Failure ]
+crbug.com/487344 http/tests/media/video-buffered-range-contains-currentTime.html [ Failure ]
+crbug.com/487344 media/audio-controls-rendering.html [ Failure ]
+crbug.com/487344 media/audio-repaint.html [ Failure ]
+crbug.com/487344 media/controls-after-reload.html [ Failure ]
+crbug.com/487344 media/controls-focus-ring.html [ Failure ]
+crbug.com/487344 media/controls-layout-direction.html [ Failure ]
+crbug.com/487344 media/controls-strict.html [ Failure ]
+crbug.com/487344 media/controls-styling.html [ Failure ]
+crbug.com/487344 media/controls-styling-strict.html [ Failure ]
+crbug.com/487344 media/controls-without-preload.html [ Failure ]
+crbug.com/487344 media/media-controls-clone.html [ Failure ]
+crbug.com/487344 media/media-document-audio-repaint.html [ Failure ]
+crbug.com/487344 media/video-controls-rendering.html [ Failure ]
+crbug.com/487344 media/video-controls-with-cast-rendering.html [ Failure ]
+crbug.com/487344 media/video-display-toggle.html [ Failure ]
+crbug.com/487344 media/video-empty-source.html [ Failure ]
+crbug.com/487344 media/video-no-audio.html [ Failure ]
+crbug.com/487344 media/video-paint-invalidation.html [ Failure ]
 
 # Failed expectation after auto-rebaseline.
 crbug.com/617033 [ Mac10.11 Retina ] tables/mozilla/bugs/bug30692.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-1st-stop.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-1st-stop.html
index 659331e0..ab48e3b 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-1st-stop.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-1st-stop.html
@@ -22,7 +22,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-aligned-not-aligned.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-aligned-not-aligned.html
index 33dfc09..51f2be6 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-aligned-not-aligned.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-aligned-not-aligned.html
@@ -61,7 +61,7 @@
 
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 
 function runTest()
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-clipped-overflowed-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-clipped-overflowed-content.html
index cfe48ce..3aa8ee80 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-clipped-overflowed-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-clipped-overflowed-content.html
@@ -49,7 +49,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-only-white-space.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-only-white-space.html
index aceccfe..67a7c0a 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-only-white-space.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-only-white-space.html
@@ -33,7 +33,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-white-space.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-white-space.html
index da13b2a..e1d4bd7 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-white-space.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-container-white-space.html
@@ -41,7 +41,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-date.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-date.html
index e8d37ce..8d15dc6 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-date.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-date.html
@@ -7,7 +7,7 @@
 
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 </script>
 </head>
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-in-anchor.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-in-anchor.html
index dbefb71..170e1ed 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-in-anchor.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-in-anchor.html
@@ -12,7 +12,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-overflow-scrol-hidden.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-overflow-scrol-hidden.html
index e4e177b2..d009d02c 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-overflow-scrol-hidden.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-overflow-scrol-hidden.html
@@ -21,7 +21,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html
index 6bac78c..f33b6860 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-div-scrollable-but-without-focusable-content.html
@@ -48,7 +48,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-horizontally.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-horizontally.html
index d40935d..4af4c022 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-horizontally.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-horizontally.html
@@ -54,7 +54,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-vertically.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-vertically.html
index abca83a3..1f549e7b 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-vertically.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-fully-aligned-vertically.html
@@ -32,7 +32,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-focusable-element.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-focusable-element.html
index baf820dcf..62972a7f 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-focusable-element.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-focusable-element.html
@@ -12,7 +12,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe-zero-size.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe-zero-size.html
index 0f76818..371c78d 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe-zero-size.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe-zero-size.html
@@ -12,7 +12,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe.html
index ecbd271..8f00c5b 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-hidden-iframe.html
@@ -12,7 +12,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-nested.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-nested.html
index 202faf5e..33ef0a7a 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-nested.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-nested.html
@@ -41,7 +41,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-focusable-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-focusable-content.html
index 037cd4a..b90e78c 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-focusable-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-focusable-content.html
@@ -37,7 +37,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-scrollable-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-scrollable-content.html
index d8c67b4..0e9178ab 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-scrollable-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-no-scrollable-content.html
@@ -38,7 +38,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-recursive-offset-parent.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-recursive-offset-parent.html
index 5801835..995cf3bc 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-recursive-offset-parent.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-recursive-offset-parent.html
@@ -31,7 +31,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
index f5dc295f..7ed48ed 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html
@@ -43,7 +43,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-not-focusable.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-not-focusable.html
index 187e7aa..52527b3 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-not-focusable.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-not-focusable.html
@@ -16,7 +16,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-without-image.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-without-image.html
index 13e9b737..60e25ad 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-without-image.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-area-without-image.html
@@ -14,7 +14,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-overlapped-areas.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-overlapped-areas.html
index 0641d6e..2fd4433 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-overlapped-areas.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-overlapped-areas.html
@@ -24,7 +24,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-simple.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-simple.html
index b9ce67d..c2a251c 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-simple.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-imagemap-simple.html
@@ -22,7 +22,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-input.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-input.html
index 148bc31..d6eb46a 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-input.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-input.html
@@ -52,7 +52,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-media-elements.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-media-elements.html
index 84019d64..3dc7d1b2 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-media-elements.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-media-elements.html
@@ -24,7 +24,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
     }
 
     function runTest()
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select-focusring.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select-focusring.html
index e2df1a42..96d8680 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select-focusring.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select-focusring.html
@@ -9,7 +9,7 @@
 <script>
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 
 var multiselect = document.getElementById('multiselect');
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select.html
index 32f059d..c149038c 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-multiple-select.html
@@ -34,7 +34,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-below.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-below.html
index f760860c..fa8066d 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-below.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-below.html
@@ -51,7 +51,7 @@
 
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 
 function runTest()
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-rightof.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-rightof.html
index 97b79385..8d9cf9ff 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-rightof.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-not-rightof.html
@@ -51,7 +51,7 @@
 
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 
 function runTest()
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-offscreen-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-offscreen-content.html
index 89d064b..4189c98 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-offscreen-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-offscreen-content.html
@@ -36,7 +36,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-only-clipped-overflow-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-only-clipped-overflow-content.html
index de2a7dc..44d5cfc1 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-only-clipped-overflow-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-only-clipped-overflow-content.html
@@ -39,7 +39,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-overlapping-elements.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-overlapping-elements.html
index b2100b4..f5679a8 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-overlapping-elements.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-overlapping-elements.html
@@ -72,7 +72,7 @@
 
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 
 function runTest()
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio-group.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio-group.html
index 81fa0421..140da26 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio-group.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio-group.html
@@ -37,7 +37,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio.html
index 5aa9991..cb1341a 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-radio.html
@@ -29,7 +29,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-simple-content-overflow.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-simple-content-overflow.html
index cd977b6..7d179b4 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-simple-content-overflow.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-simple-content-overflow.html
@@ -37,7 +37,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select-list.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select-list.html
index 7673b17..b80c52d5 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select-list.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select-list.html
@@ -34,7 +34,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select.html
index ce02e81e..ddca34b 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-single-select.html
@@ -34,7 +34,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-symmetrically-positioned.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-symmetrically-positioned.html
index 48cb8ac..85986fa2 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-symmetrically-positioned.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-symmetrically-positioned.html
@@ -60,7 +60,7 @@
 
 if (window.testRunner) {
     testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-    testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+    window.internals.settings.setSpatialNavigationEnabled(true);
 }
 
 function runTest()
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-table-traversal.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-table-traversal.html
index 6a24531..9487578bd 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-table-traversal.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-table-traversal.html
@@ -35,7 +35,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-textarea.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-textarea.html
index 756d2d1..836b7db 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-textarea.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-textarea.html
@@ -62,7 +62,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-tiny-table-traversal.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-tiny-table-traversal.html
index a5c12d0..146cf41 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-tiny-table-traversal.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-tiny-table-traversal.html
@@ -38,7 +38,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-two-elements-one-line.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-two-elements-one-line.html
index 78f8c03..18facb7 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-two-elements-one-line.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-two-elements-one-line.html
@@ -17,7 +17,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html
index 59e0f21..8cee8ca 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-unit-overflow-and-scroll-in-direction.html
@@ -42,7 +42,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-z-index.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-z-index.html
index a76de85..b04e72b 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-z-index.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-z-index.html
@@ -29,7 +29,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-zero-margin-content.html b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-zero-margin-content.html
index c784a1d..1d4779e 100644
--- a/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-zero-margin-content.html
+++ b/third_party/WebKit/LayoutTests/fast/spatial-navigation/snav-zero-margin-content.html
@@ -33,7 +33,7 @@
     if (window.testRunner) {
       testRunner.dumpAsText();
       testRunner.overridePreference("WebKitTabToLinksPreferenceKey", 1);
-      testRunner.overridePreference("WebKitSpatialNavigationEnabled", 1);
+      window.internals.settings.setSpatialNavigationEnabled(true);
       testRunner.waitUntilDone();
     }
 
diff --git a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses.html b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses.html
index a0189af..3654f8c2 100644
--- a/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses.html
+++ b/third_party/WebKit/LayoutTests/media/encrypted-media/encrypted-media-keystatuses.html
@@ -47,8 +47,8 @@
 
                     // Check |keyStatuses| for 2 entries.
                     var result = [];
-                    for (var entry of mediaKeySession.keyStatuses) {
-                        result.push({ key: arrayBufferAsString(entry[0]), value: entry[1] });
+                    for (let [keyId, status] of mediaKeySession.keyStatuses) {
+                        result.push({ key: arrayBufferAsString(keyId), value: status });
                     }
                     assert_object_equals(result,
                                          [{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}],
@@ -90,12 +90,40 @@
                                          [{ key: key1String, value: 'usable'}, { key: key2String, value: 'usable'}],
                                          'keyStatuses.forEach() fails');
 
+                    // has() and get() should return the expected values.
                     assert_true(mediaKeySession.keyStatuses.has(key1));
                     assert_true(mediaKeySession.keyStatuses.has(key2));
-                    assert_false(mediaKeySession.keyStatuses.has(stringToUint8Array('123456')));
                     assert_equals(mediaKeySession.keyStatuses.get(key1), 'usable');
                     assert_equals(mediaKeySession.keyStatuses.get(key2), 'usable');
-                    assert_equals(mediaKeySession.keyStatuses.get(stringToUint8Array('123456')), undefined);
+
+                    // Try some invalid keyIds.
+                    var invalid1 = key1.subarray(0, key1.length - 1);
+                    assert_false(mediaKeySession.keyStatuses.has(invalid1));
+                    assert_equals(mediaKeySession.keyStatuses.get(invalid1), undefined);
+
+                    var invalid2 = key1.subarray(1);
+                    assert_false(mediaKeySession.keyStatuses.has(invalid2));
+                    assert_equals(mediaKeySession.keyStatuses.get(invalid2), undefined);
+
+                    var invalid3 = new Uint8Array(key1);
+                    invalid3[0] += 1;
+                    assert_false(mediaKeySession.keyStatuses.has(invalid3));
+                    assert_equals(mediaKeySession.keyStatuses.get(invalid3), undefined);
+
+                    var invalid4 = new Uint8Array(key1);
+                    invalid4[invalid4.length - 1] -= 1;
+                    assert_false(mediaKeySession.keyStatuses.has(invalid4));
+                    assert_equals(mediaKeySession.keyStatuses.get(invalid4), undefined);
+
+                    var invalid5 = new Uint8Array(key1.length + 1);
+                    invalid5.set(key1, 1);  // First element will be 0.
+                    assert_false(mediaKeySession.keyStatuses.has(invalid5));
+                    assert_equals(mediaKeySession.keyStatuses.get(invalid5), undefined);
+
+                    var invalid6 = new Uint8Array(key1.length + 1);
+                    invalid6.set(key1, 0);  // Last element will be 0.
+                    assert_false(mediaKeySession.keyStatuses.has(invalid6));
+                    assert_equals(mediaKeySession.keyStatuses.get(invalid6), undefined);
 
                     test.done();
                 }
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt
index df6bcfb..3ceba5d 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-continuous-expected.txt
@@ -10,8 +10,8 @@
 PASS Linear ramp preceded by SetTarget is continuous.
 
 PASS Delayed linear ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...] with an element-wise tolerance of 0.
-PASS Delayed linear ramp: SetTarget part equals [1,0.9979188352992993,0.9958420018451098,0.9937694906233947,0.9917012926388759,0.9896373989149966,0.9875778004938814,0.985522488436298,0.9834714538216174,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671756,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 2.19417e-7.
-PASS Delayed linear ramp equals [0.4493289641172215,0.4501502941150408,0.45097162411286007,0.4517929541106793,0.4526142841084986,0.4534356141063179,0.45425694410413714,0.4550782741019564,0.4558996040997757,0.45672093409759495,0.45754226409541415,0.45836359409323346,0.4591849240910527,0.46000625408887197,0.4608275840866913,0.46164891408451053,...] with an element-wise tolerance of 0.00000107972.
+PASS Delayed linear ramp: SetTarget part equals [1,0.9979188352992993,0.99584200184511,0.9937694906233947,0.991701292638876,0.9896373989149966,0.9875778004938814,0.9855224884362979,0.9834714538216175,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671757,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 2.19417e-7.
+PASS Delayed linear ramp equals [0.44932896411722156,0.45015029411504087,0.4509716241128601,0.4517929541106794,0.45261428410849863,0.45343561410631794,0.4542569441041372,0.45507827410195645,0.45589960409977576,0.45672093409759495,0.4575422640954142,0.4583635940932335,0.45918492409105277,0.460006254088872,0.46082758408669133,0.4616489140845106,...] with an element-wise tolerance of 0.00000107972.
 PASS Delayed linear ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] with an element-wise tolerance of 0.
 PASS Delayed linear ramp preceded by SetTarget is continuous.
 
@@ -22,7 +22,7 @@
 PASS Exponential ramp preceded by SetTarget is continuous.
 
 PASS Delayed exponential ramp: Initial part equals [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...] with an element-wise tolerance of 0.
-PASS Delayed exponential ramp: SetTarget part equals [1,0.9979188352992993,0.9958420018451098,0.9937694906233947,0.9917012926388759,0.9896373989149966,0.9875778004938814,0.985522488436298,0.9834714538216174,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671756,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 2.19417e-7.
+PASS Delayed exponential ramp: SetTarget part equals [1,0.9979188352992993,0.99584200184511,0.9937694906233947,0.991701292638876,0.9896373989149966,0.9875778004938814,0.9855224884362979,0.9834714538216175,0.981424687747777,0.9793821813312401,0.9773439257069583,0.9753099120283326,0.9732801314671757,0.9712545752136729,0.969233234476344,...] with an element-wise tolerance of 2.19417e-7.
 PASS Delayed exponential ramp equals [0.4493289589881897,0.4496844708919525,0.45004022121429443,0.4503962993621826,0.4507526457309723,0.45110926032066345,0.4514661729335785,0.451823353767395,0.4521808326244354,0.4525385797023773,0.4528966248035431,0.45325493812561035,0.4536135494709015,0.4539724290370941,0.4543316066265106,0.4546910524368286,...] with an element-wise tolerance of 0.00000417233.
 PASS Delayed exponential ramp: Tail part equals [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,...] with an element-wise tolerance of 0.
 PASS Delayed exponential ramp preceded by SetTarget is continuous.
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit-expected.txt
index 52eb0aa5..2d9fb77 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-limit-expected.txt
@@ -3,11 +3,11 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS Initial output of 774 samples for setTargetAtTime(1, 0, 0.001) equals [0,0.02061781866875989,0.04081054289086172,0.0605869371865243,0.07995558537067682,0.09892489427870932,0.11750309741540466,0.13569825852863593,...] with an element-wise tolerance of 0.000024.
+PASS Initial output of 774 samples for setTargetAtTime(1, 0, 0.001) equals [0,0.02061781866875978,0.040810542890861834,0.06058693718652419,0.07995558537067671,0.09892489427870943,0.11750309741540454,0.13569825852863604,...] with an element-wise tolerance of 0.000024.
 PASS Tail output for setTargetAtTime(1, 0, 0.001) contains all the expected values in the correct order: [1].
 PASS setTargetAtTime(1, 0, 0.001) had the expected values.
 
-PASS Initial output of 2322 samples for setTargetAtTime(0, 0, 0.001) equals [1,0.9793821813312401,0.9591894571091383,0.9394130628134757,0.9200444146293232,0.9010751057212907,0.8824969025845953,0.8643017414713641,...] with an element-wise tolerance of 1.3e-7.
+PASS Initial output of 2322 samples for setTargetAtTime(0, 0, 0.001) equals [1,0.9793821813312402,0.9591894571091382,0.9394130628134758,0.9200444146293233,0.9010751057212906,0.8824969025845955,0.864301741471364,...] with an element-wise tolerance of 1.3e-7.
 PASS Tail output for setTargetAtTime(0, 0, 0.001) contains all the expected values in the correct order: [0].
 PASS setTargetAtTime(0, 0, 0.001) had the expected values.
 
diff --git a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling-expected.txt
index 57afccc..fe41e41 100644
--- a/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/audioparam-setTargetAtTime-sampling-expected.txt
@@ -3,10 +3,10 @@
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-PASS Initialize by setValueAtTime: Target value at frame 129 is 9139.31185271227 within a relative error of 3.6029e-8.
+PASS Initialize by setValueAtTime: Target value at frame 129 is 9139.311852712272 within a relative error of 3.6029e-8.
 PASS Initialize by setValueAtTime: Target value at frame 1 is 9139.311852712282 within a relative error of 3.6029e-8.
 PASS Initialize by setValueAtTime: Target value at frame 0 is 10000 within a relative error of 3.6029e-8.
-PASS Initialize by setter: Target value at frame 129 is 9139.31185271227 within a relative error of 3.6029e-8.
+PASS Initialize by setter: Target value at frame 129 is 9139.311852712272 within a relative error of 3.6029e-8.
 PASS Initialize by setter: Target value at frame 1 is 9139.311852712282 within a relative error of 3.6029e-8.
 PASS Initialize by setter: Target value at frame 0 is 10000 within a relative error of 0.
 PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
index a6c7e47..a8c4d8eb 100644
--- a/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
+++ b/third_party/WebKit/LayoutTests/webaudio/stereopannernode-no-glitch-expected.txt
@@ -6,7 +6,7 @@
 PASS Transition found between sample #2175 and #17854.
 PASS Channel #0 has no glitch above the threshold of 0.0005.
 PASS Channel #1 has no glitch above the threshold of 0.0005.
-PASS Channel #0 equals [1.156434465040231,1.1562937736154577,...] with an element-wise tolerance of 1e-7.
+PASS Channel #0 equals [1.156434465040231,1.1562937736154582,...] with an element-wise tolerance of 1e-7.
 PASS Channel #1 equals [0.9876883405951378,0.987710613656166,...] with an element-wise tolerance of 1e-7.
 PASS Transition found between sample #2175 and #17854.
 PASS Channel #0 has no glitch above the threshold of 0.0005.
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 0ca6466..c44be33b 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4220,6 +4220,7 @@
     getter payerEmail
     getter payerPhone
     getter shippingAddress
+    getter shippingOption
     getter totalAmount
     method complete
     method constructor
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
index 9804316..4f8c4d0a 100644
--- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -725,6 +725,7 @@
     if (!loader)
         return;
 
+    FrameNavigationDisabler navigationDisabler(*m_frame);
     loader->detachFromFrame();
     loader = nullptr;
 }
@@ -1113,7 +1114,6 @@
     // At this point, the provisional document loader should not detach, because
     // then the FrameLoader would not have any attached DocumentLoaders.
     if (m_documentLoader) {
-        FrameNavigationDisabler navigationDisabler(*m_frame);
         TemporaryChange<bool> inDetachDocumentLoader(m_protectProvisionalLoader, true);
         detachDocumentLoader(m_documentLoader);
     }
@@ -1420,10 +1420,7 @@
         return;
 
     m_frame->document()->cancelParsing();
-    if (m_provisionalDocumentLoader) {
-        FrameNavigationDisabler navigationDisabler(*m_frame);
-        detachDocumentLoader(m_provisionalDocumentLoader);
-    }
+    detachDocumentLoader(m_provisionalDocumentLoader);
 
     // beforeunload fired above, and detaching a DocumentLoader can fire
     // events, which can detach this frame.
diff --git a/third_party/WebKit/Source/core/page/FrameTree.cpp b/third_party/WebKit/Source/core/page/FrameTree.cpp
index 4b6e9d1..5742191 100644
--- a/third_party/WebKit/Source/core/page/FrameTree.cpp
+++ b/third_party/WebKit/Source/core/page/FrameTree.cpp
@@ -54,19 +54,22 @@
 
 void FrameTree::setName(const AtomicString& name)
 {
+    // This method should only be called for local frames
+    // (remote frames should be updated via setPrecalculatedName).
+    DCHECK(m_thisFrame->isLocalFrame());
+
+    // When this method is called, m_uniqueName should be already initialized.
+    // This assert helps ensure that early return (a few lines below) won't
+    // result in an uninitialized m_uniqueName.
+    DCHECK(!m_uniqueName.isNull()
+        || (m_uniqueName.isNull() && m_name.isNull() && !parent()));
+
     // Do not recalculate m_uniqueName if there is no real change of m_name.
     // This is not just a performance optimization - other code relies on the
     // assumption that unique name shouldn't change if the assigned name didn't
     // change (i.e. code in content::FrameTreeNode::SetFrameName).
-    if (m_name == name) {
-        // Assert that returning early below won't leave m_uniqueName in an
-        // uninitialized state - it should only be null if m_name is also
-        // null and only if it is for the main frame.
-        // m_uniqueName.isNull() should imply m_name.isNull() && !parent().
-        // this FrameTree is for a main frame.
-        DCHECK(!m_uniqueName.isNull() || (m_name.isNull() && !parent()));
+    if (m_name == name)
         return;
-    }
 
     m_name = name;
 
diff --git a/third_party/WebKit/Source/modules/mediasource/MediaSourceRegistry.cpp b/third_party/WebKit/Source/modules/mediasource/MediaSourceRegistry.cpp
index 9f7a295..4fb81b2 100644
--- a/third_party/WebKit/Source/modules/mediasource/MediaSourceRegistry.cpp
+++ b/third_party/WebKit/Source/modules/mediasource/MediaSourceRegistry.cpp
@@ -67,7 +67,7 @@
 URLRegistrable* MediaSourceRegistry::lookup(const String& url)
 {
     DCHECK(isMainThread());
-    return m_mediaSources.get(url);
+    return url.isNull() ? nullptr : m_mediaSources.get(url);
 }
 
 MediaSourceRegistry::MediaSourceRegistry()
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index bdcbce7..2b21e08 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -508,13 +508,13 @@
       'notifications/NotificationAction.idl',
       'notifications/NotificationEventInit.idl',
       'notifications/NotificationOptions.idl',
-      'payments/CurrencyAmount.idl',
+      'payments/PaymentCurrencyAmount.idl',
       'payments/PaymentDetails.idl',
       'payments/PaymentItem.idl',
       'payments/PaymentMethodData.idl',
       'payments/PaymentOptions.idl',
       'payments/PaymentRequestUpdateEventInit.idl',
-      'payments/ShippingOption.idl',
+      'payments/PaymentShippingOption.idl',
       'permissions/MidiPermissionDescriptor.idl',
       'permissions/PermissionDescriptor.idl',
       'permissions/PushPermissionDescriptor.idl',
@@ -680,8 +680,8 @@
       '<(blink_modules_output_dir)/notifications/NotificationEventInit.h',
       '<(blink_modules_output_dir)/notifications/NotificationOptions.cpp',
       '<(blink_modules_output_dir)/notifications/NotificationOptions.h',
-      '<(blink_modules_output_dir)/payments/CurrencyAmount.cpp',
-      '<(blink_modules_output_dir)/payments/CurrencyAmount.h',
+      '<(blink_modules_output_dir)/payments/PaymentCurrencyAmount.cpp',
+      '<(blink_modules_output_dir)/payments/PaymentCurrencyAmount.h',
       '<(blink_modules_output_dir)/payments/PaymentDetails.cpp',
       '<(blink_modules_output_dir)/payments/PaymentDetails.h',
       '<(blink_modules_output_dir)/payments/PaymentItem.cpp',
@@ -692,8 +692,8 @@
       '<(blink_modules_output_dir)/payments/PaymentOptions.h',
       '<(blink_modules_output_dir)/payments/PaymentRequestUpdateEventInit.cpp',
       '<(blink_modules_output_dir)/payments/PaymentRequestUpdateEventInit.h',
-      '<(blink_modules_output_dir)/payments/ShippingOption.cpp',
-      '<(blink_modules_output_dir)/payments/ShippingOption.h',
+      '<(blink_modules_output_dir)/payments/PaymentShippingOption.cpp',
+      '<(blink_modules_output_dir)/payments/PaymentShippingOption.h',
       '<(blink_modules_output_dir)/permissions/MidiPermissionDescriptor.cpp',
       '<(blink_modules_output_dir)/permissions/MidiPermissionDescriptor.h',
       '<(blink_modules_output_dir)/permissions/PermissionDescriptor.cpp',
@@ -2021,6 +2021,7 @@
       'notifications/NotificationDataTest.cpp',
       'notifications/NotificationResourcesLoaderTest.cpp',
       'payments/AbortTest.cpp',
+      'payments/OnPaymentResponseTest.cpp',
       'payments/PaymentAddressTest.cpp',
       'payments/PaymentRequestDetailsTest.cpp',
       'payments/PaymentRequestTest.cpp',
diff --git a/third_party/WebKit/Source/modules/payments/OnPaymentResponseTest.cpp b/third_party/WebKit/Source/modules/payments/OnPaymentResponseTest.cpp
new file mode 100644
index 0000000..6f004f12
--- /dev/null
+++ b/third_party/WebKit/Source/modules/payments/OnPaymentResponseTest.cpp
@@ -0,0 +1,458 @@
+// 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.
+
+// Tests for PaymentRequest::OnPaymentResponse().
+
+#include "bindings/core/v8/ScriptFunction.h"
+#include "bindings/core/v8/V8BindingForTesting.h"
+#include "bindings/modules/v8/V8PaymentResponse.h"
+#include "modules/payments/PaymentAddress.h"
+#include "modules/payments/PaymentRequest.h"
+#include "modules/payments/PaymentTestHelper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include <utility>
+
+namespace blink {
+namespace {
+
+// If the merchant requests shipping information, but the browser does not
+// provide the shipping option, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectMissingShippingOption)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
+    response->shipping_address = mojom::blink::PaymentAddress::New();
+    response->shipping_address->country = "US";
+    response->shipping_address->language_code = "en";
+    response->shipping_address->script_code = "Latn";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests shipping information, but the browser does not
+// provide a shipping address, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectMissingAddress)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
+    response->shipping_option = "standardShipping";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests an email address, but the browser does not provide
+// it, reject the show() promise.
+TEST(PaymentRequestTest, RejectMissingEmail)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerEmail(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests a phone number, but the browser does not provide it,
+// reject the show() promise.
+TEST(PaymentRequestTest, RejectMissingPhone)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerPhone(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests shipping information, but the browser provides an
+// empty string for shipping option, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectEmptyShippingOption)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
+    response->shipping_option = "";
+    response->shipping_address = mojom::blink::PaymentAddress::New();
+    response->shipping_address->country = "US";
+    response->shipping_address->language_code = "en";
+    response->shipping_address->script_code = "Latn";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests shipping information, but the browser provides an
+// empty shipping address, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectEmptyAddress)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
+    response->shipping_option = "standardShipping";
+    response->shipping_address = mojom::blink::PaymentAddress::New();
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests an email, but the browser provides an empty string
+// for email, reject the show() promise.
+TEST(PaymentRequestTest, RejectEmptyEmail)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerEmail(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_email = "";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests a phone number, but the browser provides an empty
+// string for the phone number, reject the show() promise.
+TEST(PaymentRequestTest, RejectEmptyPhone)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerPhone(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_phone = "";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant does not request shipping information, but the browser
+// provides a shipping address, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectNotRequestedAddress)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->shipping_address = mojom::blink::PaymentAddress::New();
+    response->shipping_address->country = "US";
+    response->shipping_address->language_code = "en";
+    response->shipping_address->script_code = "Latn";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant does not request shipping information, but the browser
+// provides a shipping option, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectNotRequestedShippingOption)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->shipping_option = "";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant does not request an email, but the browser provides it,
+// reject the show() promise.
+TEST(PaymentRequestTest, RejectNotRequestedEmail)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerEmail(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_email = "";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant does not request a phone number, but the browser provides it,
+// reject the show() promise.
+TEST(PaymentRequestTest, RejectNotRequestedPhone)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerPhone(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_phone = "";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+// If the merchant requests shipping information, but the browser provides an
+// invalid shipping address, reject the show() promise.
+TEST(OnPaymentResponseTest, RejectInvalidAddress)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
+    response->shipping_option = "standardShipping";
+    response->shipping_address = mojom::blink::PaymentAddress::New();
+    response->shipping_address->country = "Atlantis";
+
+    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+}
+
+class PaymentResponseFunction : public ScriptFunction {
+public:
+    static v8::Local<v8::Function> create(ScriptState* scriptState, ScriptValue* outValue)
+    {
+        PaymentResponseFunction* self = new PaymentResponseFunction(scriptState, outValue);
+        return self->bindToV8Function();
+    }
+
+private:
+    PaymentResponseFunction(ScriptState* scriptState, ScriptValue* outValue)
+        : ScriptFunction(scriptState)
+        , m_value(outValue)
+    {
+        DCHECK(m_value);
+    }
+
+    ScriptValue call(ScriptValue value) override
+    {
+        DCHECK(!value.isEmpty());
+        *m_value = value;
+        return value;
+    }
+
+    ScriptValue* const m_value;
+};
+
+// If the merchant requests shipping information, the resolved show() promise
+// should contain a shipping option and an address.
+TEST(OnPaymentResponseTest, CanRequestShippingInformation)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
+    response->shipping_option = "standardShipping";
+    response->shipping_address = mojom::blink::PaymentAddress::New();
+    response->shipping_address->country = "US";
+    response->shipping_address->language_code = "en";
+    response->shipping_address->script_code = "Latn";
+    ScriptValue outValue;
+    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+
+    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
+    PaymentResponse* resp = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
+    EXPECT_EQ("standardShipping", resp->shippingOption());
+    EXPECT_EQ("US", resp->shippingAddress()->country());
+    EXPECT_EQ("en-Latn", resp->shippingAddress()->languageCode());
+}
+
+// If the merchant requests an email address, the resolved show() promise should
+// contain an email address.
+TEST(PaymentRequestTest, CanRequestEmail)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerEmail(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_email = "abc@gmail.com";
+    ScriptValue outValue;
+    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+
+    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
+    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
+    EXPECT_EQ("abc@gmail.com", pr->payerEmail());
+}
+
+// If the merchant requests a phone number, the resolved show() promise should
+// contain a phone number.
+TEST(PaymentRequestTest, CanRequestPhone)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerPhone(true);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_phone = "0123";
+
+    ScriptValue outValue;
+    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
+    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
+
+    EXPECT_EQ("0123", pr->payerPhone());
+}
+
+// If the merchant does not request shipping information, the resolved show()
+// promise should contain null shipping option and address.
+TEST(OnPaymentResponseTest, ShippingInformationNotRequired)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestShipping(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    ASSERT_FALSE(scope.getExceptionState().hadException());
+    ScriptValue outValue;
+    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(buildPaymentResponseForTest());
+
+    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
+    PaymentResponse* resp = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
+    EXPECT_TRUE(resp->shippingOption().isNull());
+    EXPECT_EQ(nullptr, resp->shippingAddress());
+}
+
+// If the merchant does not request a phone number, the resolved show() promise
+// should contain null phone number.
+TEST(PaymentRequestTest, PhoneNotRequred)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerPhone(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_phone = String();
+    ScriptValue outValue;
+    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+
+    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
+    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
+    EXPECT_TRUE(pr->payerPhone().isNull());
+}
+
+// If the merchant does not request an email address, the resolved show()
+// promise should contain null email address.
+TEST(PaymentRequestTest, EmailNotRequired)
+{
+    V8TestingScope scope;
+    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
+    makePaymentRequestOriginSecure(scope.document());
+    PaymentOptions options;
+    options.setRequestPayerEmail(false);
+    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
+    EXPECT_FALSE(scope.getExceptionState().hadException());
+    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
+    response->total_amount = mojom::blink::PaymentCurrencyAmount::New();
+    response->payer_email = String();
+    ScriptValue outValue;
+    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
+
+    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
+
+    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
+    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
+    EXPECT_TRUE(pr->payerEmail().isNull());
+}
+
+} // namespace
+} // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/CurrencyAmount.idl b/third_party/WebKit/Source/modules/payments/PaymentCurrencyAmount.idl
similarity index 70%
rename from third_party/WebKit/Source/modules/payments/CurrencyAmount.idl
rename to third_party/WebKit/Source/modules/payments/PaymentCurrencyAmount.idl
index a92763b..b022c715 100644
--- a/third_party/WebKit/Source/modules/payments/CurrencyAmount.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentCurrencyAmount.idl
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/browser-payment-api/specs/paymentrequest.html#currencyamount
+// https://w3c.github.io/browser-payment-api/#paymentcurrencyamount
 
 [
     RuntimeEnabled=PaymentRequest
-] dictionary CurrencyAmount {
+] dictionary PaymentCurrencyAmount {
     required DOMString currency;
     required DOMString value;
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentDetails.idl b/third_party/WebKit/Source/modules/payments/PaymentDetails.idl
index 5592c7c..15626f3 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentDetails.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentDetails.idl
@@ -9,5 +9,5 @@
 ] dictionary PaymentDetails {
     PaymentItem total;
     sequence<PaymentItem> displayItems;
-    sequence<ShippingOption> shippingOptions;
+    sequence<PaymentShippingOption> shippingOptions;
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentItem.idl b/third_party/WebKit/Source/modules/payments/PaymentItem.idl
index 7a7ab7dc..1c433010 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentItem.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentItem.idl
@@ -8,5 +8,5 @@
     RuntimeEnabled=PaymentRequest
 ] dictionary PaymentItem {
     required DOMString label;
-    required CurrencyAmount amount;
+    required PaymentCurrencyAmount amount;
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
index e1a1812..ce4cc78 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequest.cpp
@@ -19,8 +19,8 @@
 #include "modules/payments/PaymentItem.h"
 #include "modules/payments/PaymentRequestUpdateEvent.h"
 #include "modules/payments/PaymentResponse.h"
+#include "modules/payments/PaymentShippingOption.h"
 #include "modules/payments/PaymentsValidators.h"
-#include "modules/payments/ShippingOption.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/wtf_array.h"
 #include "platform/mojo/MojoHelper.h"
@@ -29,8 +29,8 @@
 
 namespace mojo {
 
-using blink::mojom::blink::CurrencyAmount;
-using blink::mojom::blink::CurrencyAmountPtr;
+using blink::mojom::blink::PaymentCurrencyAmount;
+using blink::mojom::blink::PaymentCurrencyAmountPtr;
 using blink::mojom::blink::PaymentDetails;
 using blink::mojom::blink::PaymentDetailsPtr;
 using blink::mojom::blink::PaymentItem;
@@ -39,14 +39,14 @@
 using blink::mojom::blink::PaymentMethodDataPtr;
 using blink::mojom::blink::PaymentOptions;
 using blink::mojom::blink::PaymentOptionsPtr;
-using blink::mojom::blink::ShippingOption;
-using blink::mojom::blink::ShippingOptionPtr;
+using blink::mojom::blink::PaymentShippingOption;
+using blink::mojom::blink::PaymentShippingOptionPtr;
 
 template <>
-struct TypeConverter<CurrencyAmountPtr, blink::CurrencyAmount> {
-    static CurrencyAmountPtr Convert(const blink::CurrencyAmount& input)
+struct TypeConverter<PaymentCurrencyAmountPtr, blink::PaymentCurrencyAmount> {
+    static PaymentCurrencyAmountPtr Convert(const blink::PaymentCurrencyAmount& input)
     {
-        CurrencyAmountPtr output = CurrencyAmount::New();
+        PaymentCurrencyAmountPtr output = PaymentCurrencyAmount::New();
         output->currency = input.currency();
         output->value = input.value();
         return output;
@@ -59,19 +59,19 @@
     {
         PaymentItemPtr output = PaymentItem::New();
         output->label = input.label();
-        output->amount = CurrencyAmount::From(input.amount());
+        output->amount = PaymentCurrencyAmount::From(input.amount());
         return output;
     }
 };
 
 template <>
-struct TypeConverter<ShippingOptionPtr, blink::ShippingOption> {
-    static ShippingOptionPtr Convert(const blink::ShippingOption& input)
+struct TypeConverter<PaymentShippingOptionPtr, blink::PaymentShippingOption> {
+    static PaymentShippingOptionPtr Convert(const blink::PaymentShippingOption& input)
     {
-        ShippingOptionPtr output = ShippingOption::New();
+        PaymentShippingOptionPtr output = PaymentShippingOption::New();
         output->id = input.id();
         output->label = input.label();
-        output->amount = CurrencyAmount::From(input.amount());
+        output->amount = PaymentCurrencyAmount::From(input.amount());
         output->selected = input.hasSelected() && input.selected();
         return output;
     }
@@ -90,9 +90,9 @@
             output->display_items = mojo::WTFArray<PaymentItemPtr>::New(0);
 
         if (input.hasShippingOptions())
-            output->shipping_options = mojo::WTFArray<ShippingOptionPtr>::From(input.shippingOptions());
+            output->shipping_options = mojo::WTFArray<PaymentShippingOptionPtr>::From(input.shippingOptions());
         else
-            output->shipping_options = mojo::WTFArray<ShippingOptionPtr>::New(0);
+            output->shipping_options = mojo::WTFArray<PaymentShippingOptionPtr>::New(0);
 
         return output;
     }
@@ -173,7 +173,7 @@
     }
 }
 
-void validateShippingOptions(const HeapVector<ShippingOption>& options, ExceptionState& exceptionState)
+void validateShippingOptions(const HeapVector<PaymentShippingOption>& options, ExceptionState& exceptionState)
 {
     for (const auto& option : options) {
         if (!option.hasId() || option.id().isEmpty()) {
@@ -457,7 +457,7 @@
     DCHECK(!m_completeResolver);
 
     if (m_options.requestShipping()) {
-        if (!response->shipping_address) {
+        if (!response->shipping_address || response->shipping_option.isEmpty()) {
             m_showResolver->reject(DOMException::create(SyntaxError));
             clearResolversAndCloseMojoConnection();
             return;
@@ -471,9 +471,9 @@
         }
 
         m_shippingAddress = new PaymentAddress(response->shipping_address.Clone());
-        m_shippingOption = response->shipping_option_id;
+        m_shippingOption = response->shipping_option;
     } else {
-        if (response->shipping_address) {
+        if (response->shipping_address || !response->shipping_option.isNull()) {
             m_showResolver->reject(DOMException::create(SyntaxError));
             clearResolversAndCloseMojoConnection();
             return;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
index be38125..dbc425cb 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentRequestTest.cpp
@@ -5,17 +5,13 @@
 #include "modules/payments/PaymentRequest.h"
 
 #include "bindings/core/v8/JSONValuesForV8.h"
-#include "bindings/core/v8/ScriptFunction.h"
 #include "bindings/core/v8/V8BindingForTesting.h"
-#include "bindings/modules/v8/V8PaymentResponse.h"
 #include "core/dom/Document.h"
 #include "core/dom/ExceptionCode.h"
 #include "modules/payments/PaymentAddress.h"
-#include "modules/payments/PaymentResponse.h"
 #include "modules/payments/PaymentTestHelper.h"
 #include "platform/heap/HeapAllocator.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include <utility>
 
 namespace blink {
 namespace {
@@ -81,7 +77,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    details.setShippingOptions(HeapVector<ShippingOption>(2, buildShippingOptionForTest()));
+    details.setShippingOptions(HeapVector<PaymentShippingOption>(2, buildShippingOptionForTest()));
     PaymentOptions options;
     options.setRequestShipping(true);
 
@@ -96,7 +92,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    details.setShippingOptions(HeapVector<ShippingOption>(1, buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "standard")));
+    details.setShippingOptions(HeapVector<PaymentShippingOption>(1, buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "standard")));
 
     PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), details, scope.getExceptionState());
 
@@ -109,7 +105,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    details.setShippingOptions(HeapVector<ShippingOption>(1, buildShippingOptionForTest()));
+    details.setShippingOptions(HeapVector<PaymentShippingOption>(1, buildShippingOptionForTest()));
     PaymentOptions options;
     options.setRequestShipping(false);
 
@@ -124,7 +120,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    details.setShippingOptions(HeapVector<ShippingOption>(1, buildShippingOptionForTest()));
+    details.setShippingOptions(HeapVector<PaymentShippingOption>(1, buildShippingOptionForTest()));
     PaymentOptions options;
     options.setRequestShipping(true);
 
@@ -139,7 +135,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    HeapVector<ShippingOption> shippingOptions(1, buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "standard"));
+    HeapVector<PaymentShippingOption> shippingOptions(1, buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "standard"));
     shippingOptions[0].setSelected(true);
     details.setShippingOptions(shippingOptions);
     PaymentOptions options;
@@ -156,7 +152,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    HeapVector<ShippingOption> shippingOptions(2);
+    HeapVector<PaymentShippingOption> shippingOptions(2);
     shippingOptions[0] = buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "standard");
     shippingOptions[0].setSelected(true);
     shippingOptions[1] = buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "express");
@@ -175,7 +171,7 @@
     makePaymentRequestOriginSecure(scope.document());
     PaymentDetails details;
     details.setTotal(buildPaymentItemForTest());
-    HeapVector<ShippingOption> shippingOptions(2);
+    HeapVector<PaymentShippingOption> shippingOptions(2);
     shippingOptions[0] = buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "standard");
     shippingOptions[0].setSelected(true);
     shippingOptions[1] = buildShippingOptionForTest(PaymentTestDataId, PaymentTestOverwriteValue, "express");
@@ -202,131 +198,6 @@
     static_cast<mojom::blink::PaymentRequestClient*>(request)->OnShippingAddressChange(mojom::blink::PaymentAddress::New());
 }
 
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestShippingTrueAndEmptyShippingAddressInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestShipping(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestShippingTrueAndInvalidShippingAddressInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestShipping(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
-    response->shipping_address = mojom::blink::PaymentAddress::New();
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestShippingFalseAndShippingAddressExistsInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestShipping(false);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->shipping_address = mojom::blink::PaymentAddress::New();
-    response->shipping_address->country = "US";
-    response->shipping_address->language_code = "en";
-    response->shipping_address->script_code = "Latn";
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-class PaymentResponseFunction : public ScriptFunction {
-public:
-    static v8::Local<v8::Function> create(ScriptState* scriptState, ScriptValue* outValue)
-    {
-        PaymentResponseFunction* self = new PaymentResponseFunction(scriptState, outValue);
-        return self->bindToV8Function();
-    }
-
-    ScriptValue call(ScriptValue value) override
-    {
-        DCHECK(!value.isEmpty());
-        *m_value = value;
-        return value;
-    }
-
-private:
-    PaymentResponseFunction(ScriptState* scriptState, ScriptValue* outValue)
-        : ScriptFunction(scriptState)
-        , m_value(outValue)
-    {
-        DCHECK(m_value);
-    }
-
-    ScriptValue* m_value;
-};
-
-TEST(PaymentRequestTest, ResolveShowPromiseWithRequestShippingTrueAndValidShippingAddressInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestShipping(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = buildPaymentResponseForTest();
-    response->shipping_address = mojom::blink::PaymentAddress::New();
-    response->shipping_address->country = "US";
-    response->shipping_address->language_code = "en";
-    response->shipping_address->script_code = "Latn";
-
-    ScriptValue outValue;
-    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
-    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
-
-    EXPECT_EQ("US", pr->shippingAddress()->country());
-    EXPECT_EQ("en-Latn", pr->shippingAddress()->languageCode());
-}
-
-TEST(PaymentRequestTest, ResolveShowPromiseWithRequestShippingFalseAndEmptyShippingAddressInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestShipping(false);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-
-    ScriptValue outValue;
-    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(buildPaymentResponseForTest());
-    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
-    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
-
-    EXPECT_EQ(nullptr, pr->shippingAddress());
-}
-
 TEST(PaymentRequestTest, OnShippingOptionChange)
 {
     V8TestingScope scope;
@@ -543,205 +414,5 @@
     EXPECT_EQ("fast", request->shippingOption());
 }
 
-TEST(PaymentRequestTest, ResolveShowPromiseWithRequestPayerEmailTrueAndValidPayerEmailInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerEmail(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_email = "abc@gmail.com";
-
-    ScriptValue outValue;
-    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
-    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
-
-    EXPECT_EQ("abc@gmail.com", pr->payerEmail());
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestPayerEmailTrueAndEmptyPayerEmailInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerEmail(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_email = "";
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestPayerEmailTrueAndNullPayerEmailInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerEmail(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_email = String();
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestPayerEmailFalseAndNonNullPayerEmailInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerEmail(false);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_email = "";
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, ResolveShowPromiseWithRequestPayerEmailFalseAndNullPayerEmailInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerEmail(false);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_email = String();
-
-    ScriptValue outValue;
-    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
-    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
-
-    EXPECT_TRUE(pr->payerEmail().isNull());
-}
-
-TEST(PaymentRequestTest, ResolveShowPromiseWithRequestPayerPhoneTrueAndValidPayerPhoneInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerPhone(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_phone = "0123";
-
-    ScriptValue outValue;
-    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
-    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
-
-    EXPECT_EQ("0123", pr->payerPhone());
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestPayerPhoneTrueAndEmptyPayerPhoneInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerPhone(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_phone = "";
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestPayerPhoneTrueAndNullPayerPhoneInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerPhone(true);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_phone = String();
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, RejectShowPromiseWithRequestPayerPhoneFalseAndNonNulPayerPhoneInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerPhone(false);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_phone = "";
-
-    request->show(scope.getScriptState()).then(funcs.expectNoCall(), funcs.expectCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-}
-
-TEST(PaymentRequestTest, ResolveShowPromiseWithRequestPayerPhoneFalseAndNullPayerPhoneInResponse)
-{
-    V8TestingScope scope;
-    PaymentRequestMockFunctionScope funcs(scope.getScriptState());
-    makePaymentRequestOriginSecure(scope.document());
-    PaymentOptions options;
-    options.setRequestPayerPhone(false);
-    PaymentRequest* request = PaymentRequest::create(scope.getScriptState(), buildPaymentMethodDataForTest(), buildPaymentDetailsForTest(), options, scope.getExceptionState());
-    EXPECT_FALSE(scope.getExceptionState().hadException());
-    mojom::blink::PaymentResponsePtr response = mojom::blink::PaymentResponse::New();
-    response->total_amount = mojom::blink::CurrencyAmount::New();
-    response->payer_phone = String();
-
-    ScriptValue outValue;
-    request->show(scope.getScriptState()).then(PaymentResponseFunction::create(scope.getScriptState(), &outValue), funcs.expectNoCall());
-
-    static_cast<mojom::blink::PaymentRequestClient*>(request)->OnPaymentResponse(std::move(response));
-    v8::MicrotasksScope::PerformCheckpoint(scope.isolate());
-    PaymentResponse* pr = V8PaymentResponse::toImplWithTypeCheck(scope.isolate(), outValue.v8Value());
-
-    EXPECT_TRUE(pr->payerPhone().isNull());
-}
-
 } // namespace
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
index a2e498f..139e9cf 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.cpp
@@ -12,10 +12,10 @@
 namespace mojo {
 
 template <>
-struct TypeConverter<blink::CurrencyAmount, blink::mojom::blink::CurrencyAmount> {
-    static blink::CurrencyAmount Convert(const blink::mojom::blink::CurrencyAmount& input)
+struct TypeConverter<blink::PaymentCurrencyAmount, blink::mojom::blink::PaymentCurrencyAmount> {
+    static blink::PaymentCurrencyAmount Convert(const blink::mojom::blink::PaymentCurrencyAmount& input)
     {
-        blink::CurrencyAmount output;
+        blink::PaymentCurrencyAmount output;
         output.setCurrency(input.currency);
         output.setValue(input.value);
         return output;
@@ -28,9 +28,10 @@
 
 PaymentResponse::PaymentResponse(mojom::blink::PaymentResponsePtr response, PaymentCompleter* paymentCompleter)
     : m_methodName(response->method_name)
-    , m_totalAmount(response->total_amount->To<CurrencyAmount>())
+    , m_totalAmount(response->total_amount->To<PaymentCurrencyAmount>())
     , m_stringifiedDetails(response->stringified_details)
     , m_shippingAddress(response->shipping_address ? new PaymentAddress(std::move(response->shipping_address)) : nullptr)
+    , m_shippingOption(response->shipping_option)
     , m_payerEmail(response->payer_email)
     , m_payerPhone(response->payer_phone)
     , m_paymentCompleter(paymentCompleter)
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.h b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
index 8548b617..f41d5fa 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.h
@@ -9,7 +9,7 @@
 #include "bindings/core/v8/ScriptValue.h"
 #include "bindings/core/v8/ScriptWrappable.h"
 #include "modules/ModulesExport.h"
-#include "modules/payments/CurrencyAmount.h"
+#include "modules/payments/PaymentCurrencyAmount.h"
 #include "platform/heap/Handle.h"
 #include "public/platform/modules/payments/payment_request.mojom-blink.h"
 #include "wtf/Noncopyable.h"
@@ -31,9 +31,10 @@
     virtual ~PaymentResponse();
 
     const String& methodName() const { return m_methodName; }
-    void totalAmount(CurrencyAmount& result) const { result = m_totalAmount; }
+    void totalAmount(PaymentCurrencyAmount& result) const { result = m_totalAmount; }
     ScriptValue details(ScriptState*, ExceptionState&) const;
     PaymentAddress* shippingAddress() const { return m_shippingAddress.get(); }
+    const String& shippingOption() const { return m_shippingOption; }
     const String& payerEmail() const { return m_payerEmail; }
     const String& payerPhone() const { return m_payerPhone; }
 
@@ -43,9 +44,10 @@
 
 private:
     String m_methodName;
-    CurrencyAmount m_totalAmount;
+    PaymentCurrencyAmount m_totalAmount;
     String m_stringifiedDetails;
     Member<PaymentAddress> m_shippingAddress;
+    String m_shippingOption;
     String m_payerEmail;
     String m_payerPhone;
     Member<PaymentCompleter> m_paymentCompleter;
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
index a24427e..bd12606c 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponse.idl
@@ -10,17 +10,18 @@
     ""
 };
 
-// https://w3c.github.io/browser-payment-api/specs/paymentrequest.html#paymentresponse-interface
+// https://w3c.github.io/browser-payment-api/#paymentresponse-interface
 
 [
     RuntimeEnabled=PaymentRequest,
 ] interface PaymentResponse {
     readonly attribute DOMString methodName;
-    readonly attribute CurrencyAmount totalAmount;
+    readonly attribute PaymentCurrencyAmount totalAmount;
     readonly attribute DOMString? payerEmail;
     readonly attribute DOMString? payerPhone;
     [CallWith=ScriptState, RaisesException] readonly attribute object details;
     readonly attribute PaymentAddress? shippingAddress;
+    readonly attribute DOMString? shippingOption;
 
     [CallWith=ScriptState] Promise<void> complete(optional PaymentComplete paymentResult = "");
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
index ae633dca..12812b4 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentResponseTest.cpp
@@ -48,6 +48,7 @@
     input->total_amount->currency = "USD";
     input->total_amount->value = "5.00";
     input->stringified_details = "{\"transactionId\": 123}";
+    input->shipping_option = "standardShippingOption";
     input->payer_email = "abc@gmail.com";
     input->payer_phone = "0123";
     MockPaymentCompleter* completeCallback = new MockPaymentCompleter;
@@ -55,10 +56,11 @@
     PaymentResponse output(std::move(input), completeCallback);
 
     EXPECT_EQ("foo", output.methodName());
+    EXPECT_EQ("standardShippingOption", output.shippingOption());
     EXPECT_EQ("abc@gmail.com", output.payerEmail());
     EXPECT_EQ("0123", output.payerPhone());
 
-    CurrencyAmount totalAmount;
+    PaymentCurrencyAmount totalAmount;
     output.totalAmount(totalAmount);
     EXPECT_EQ("USD", totalAmount.currency());
     EXPECT_EQ("5.00", totalAmount.value());
diff --git a/third_party/WebKit/Source/modules/payments/ShippingOption.idl b/third_party/WebKit/Source/modules/payments/PaymentShippingOption.idl
similarity index 64%
rename from third_party/WebKit/Source/modules/payments/ShippingOption.idl
rename to third_party/WebKit/Source/modules/payments/PaymentShippingOption.idl
index 6d48a3c..58678e55 100644
--- a/third_party/WebKit/Source/modules/payments/ShippingOption.idl
+++ b/third_party/WebKit/Source/modules/payments/PaymentShippingOption.idl
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/browser-payment-api/specs/paymentrequest.html#shippingoption-interface
+// https://w3c.github.io/browser-payment-api/#paymentshippingoption-dictionary
 
 [
     RuntimeEnabled=PaymentRequest
-] dictionary ShippingOption {
+] dictionary PaymentShippingOption {
     required DOMString id;
     required DOMString label;
-    required CurrencyAmount amount;
+    required PaymentCurrencyAmount amount;
     boolean selected = false;
 };
diff --git a/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp b/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp
index 918524a..ecbb264 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp
+++ b/third_party/WebKit/Source/modules/payments/PaymentTestHelper.cpp
@@ -6,19 +6,19 @@
 
 #include "bindings/core/v8/ScriptState.h"
 #include "core/dom/Document.h"
-#include "modules/payments/CurrencyAmount.h"
+#include "modules/payments/PaymentCurrencyAmount.h"
 #include "modules/payments/PaymentMethodData.h"
 #include "platform/heap/HeapAllocator.h"
 
 namespace blink {
 namespace {
 
-// PaymentItem and ShippingOption have identical structure
-// except for the "id" field, which is present only in ShippingOption.
-template <typename PaymentItemOrShippingOption>
-void setValues(PaymentItemOrShippingOption& original, PaymentTestDataToChange data, PaymentTestModificationType modificationType, const String& valueToUse)
+// PaymentItem and PaymentShippingOption have identical structure
+// except for the "id" field, which is present only in PaymentShippingOption.
+template <typename PaymentItemOrPaymentShippingOption>
+void setValues(PaymentItemOrPaymentShippingOption& original, PaymentTestDataToChange data, PaymentTestModificationType modificationType, const String& valueToUse)
 {
-    CurrencyAmount itemAmount;
+    PaymentCurrencyAmount itemAmount;
     if (data == PaymentTestDataCurrencyCode) {
         if (modificationType == PaymentTestOverwriteValue)
             itemAmount.setCurrency(valueToUse);
@@ -53,9 +53,9 @@
     return item;
 }
 
-ShippingOption buildShippingOptionForTest(PaymentTestDataToChange data, PaymentTestModificationType modificationType, const String& valueToUse)
+PaymentShippingOption buildShippingOptionForTest(PaymentTestDataToChange data, PaymentTestModificationType modificationType, const String& valueToUse)
 {
-    ShippingOption shippingOption;
+    PaymentShippingOption shippingOption;
     if (data == PaymentTestDataId) {
         if (modificationType == PaymentTestOverwriteValue)
             shippingOption.setId(valueToUse);
@@ -80,7 +80,7 @@
     else
         item = buildPaymentItemForTest();
 
-    ShippingOption shippingOption;
+    PaymentShippingOption shippingOption;
     if (detail == PaymentTestDetailShippingOption)
         shippingOption = buildShippingOptionForTest(data, modificationType, valueToUse);
     else
@@ -89,7 +89,7 @@
     PaymentDetails result;
     result.setTotal(total);
     result.setDisplayItems(HeapVector<PaymentItem>(1, item));
-    result.setShippingOptions(HeapVector<ShippingOption>(2, shippingOption));
+    result.setShippingOptions(HeapVector<PaymentShippingOption>(2, shippingOption));
 
     return result;
 }
@@ -104,7 +104,7 @@
 mojom::blink::PaymentResponsePtr buildPaymentResponseForTest()
 {
     mojom::blink::PaymentResponsePtr result = mojom::blink::PaymentResponse::New();
-    result->total_amount = mojom::blink::CurrencyAmount::New();
+    result->total_amount = mojom::blink::PaymentCurrencyAmount::New();
     return result;
 }
 
diff --git a/third_party/WebKit/Source/modules/payments/PaymentTestHelper.h b/third_party/WebKit/Source/modules/payments/PaymentTestHelper.h
index 903e4b0c..30249f54 100644
--- a/third_party/WebKit/Source/modules/payments/PaymentTestHelper.h
+++ b/third_party/WebKit/Source/modules/payments/PaymentTestHelper.h
@@ -8,7 +8,7 @@
 #include "bindings/core/v8/ScriptFunction.h"
 #include "modules/payments/PaymentDetails.h"
 #include "modules/payments/PaymentItem.h"
-#include "modules/payments/ShippingOption.h"
+#include "modules/payments/PaymentShippingOption.h"
 #include "platform/heap/HeapAllocator.h"
 #include "platform/heap/Persistent.h"
 #include "public/platform/modules/payments/payment_request.mojom-blink.h"
@@ -47,7 +47,7 @@
 
 PaymentItem buildPaymentItemForTest(PaymentTestDataToChange = PaymentTestDataNone, PaymentTestModificationType = PaymentTestOverwriteValue, const String& valueToUse = String());
 
-ShippingOption buildShippingOptionForTest(PaymentTestDataToChange = PaymentTestDataNone, PaymentTestModificationType = PaymentTestOverwriteValue, const String& valueToUse = String());
+PaymentShippingOption buildShippingOptionForTest(PaymentTestDataToChange = PaymentTestDataNone, PaymentTestModificationType = PaymentTestOverwriteValue, const String& valueToUse = String());
 
 PaymentDetails buildPaymentDetailsForTest(PaymentTestDetailToChange = PaymentTestDetailNone, PaymentTestDataToChange = PaymentTestDataNone, PaymentTestModificationType = PaymentTestOverwriteValue, const String& valueToUse = String());
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/__init__.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/__init__.py
index 94910da..ef65bee5 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/__init__.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/__init__.py
@@ -1,9 +1 @@
 # Required for Python to search this directory for module files
-
-from webkitpy.tool.commands.commit_announcer import CommitAnnouncerCommand
-from webkitpy.tool.commands.flaky_tests import FlakyTests
-from webkitpy.tool.commands.pretty_diff import PrettyDiff
-from webkitpy.tool.commands.queries import *
-from webkitpy.tool.commands.rebaseline import Rebaseline
-from webkitpy.tool.commands.rebaseline_server import RebaselineServer
-from webkitpy.tool.commands.layout_tests_server import LayoutTestsServer
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool.py
index ad10d1a73..4a55ac27 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool.py
@@ -35,7 +35,6 @@
 import logging
 import sys
 
-from webkitpy.tool.commands.command import Command
 from webkitpy.tool.commands.command import HelpPrintingOptionParser
 from webkitpy.tool.commands.help_command import HelpCommand
 
@@ -46,33 +45,20 @@
 
     global_options = None
 
-    def __init__(self, name=None, commands=None):
-        self._name = name or optparse.OptionParser(prog=name).get_prog_name()  # OptionParser has nice logic for fetching the name.
-        # Allow the unit tests to disable command auto-discovery.
-        self.commands = commands or [cls() for cls in self._find_all_commands() if cls.name]
+    def __init__(self, commands):
+        self.commands = commands
         self.help_command = self.command_by_name(HelpCommand.name)
-        # Require a help command, even if the manual test list doesn't include one.
+        # Require the help command, even if the manual test list doesn't include one.
         if not self.help_command:
             self.help_command = HelpCommand()
             self.commands.append(self.help_command)
+        # FIXME: Since tool is passed to Command.execute, it may not be necessary to set a tool attribute on the
+        # command objects here - maybe this should be done inside of Command.execute for commands that use self._tool.
         for command in self.commands:
             command.bind_to_tool(self)
 
-    @classmethod
-    def _add_all_subclasses(cls, class_to_crawl, seen_classes):
-        for subclass in class_to_crawl.__subclasses__():
-            if subclass not in seen_classes:
-                seen_classes.add(subclass)
-                cls._add_all_subclasses(subclass, seen_classes)
-
-    @classmethod
-    def _find_all_commands(cls):
-        commands = set()
-        cls._add_all_subclasses(Command, commands)
-        return sorted(commands)
-
     def name(self):
-        return self._name
+        return optparse.OptionParser().get_prog_name()
 
     def _create_option_parser(self):
         usage = "Usage: %prog [options] COMMAND [ARGS]"
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool_unittest.py
index 10d9ede0..266d72d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/multi_command_tool_unittest.py
@@ -32,7 +32,7 @@
 
 from webkitpy.common.system.outputcapture import OutputCapture
 from webkitpy.tool.multi_command_tool import MultiCommandTool
-from webkitpy.tool.commands import Command
+from webkitpy.tool.commands.command import Command
 
 
 class TrivialCommand(Command):
@@ -55,8 +55,11 @@
 
 class TrivialTool(MultiCommandTool):
 
-    def __init__(self, commands=None):
-        MultiCommandTool.__init__(self, name="trivial-tool", commands=commands)
+    def __init__(self, commands):
+        MultiCommandTool.__init__(self, commands)
+
+    def name(self):
+        return 'trivial-tool'
 
     def path(self):
         return __file__
@@ -85,8 +88,7 @@
         self._assert_split(full_args, full_args_expected)
 
     def test_command_by_name(self):
-        # This also tests Command auto-discovery.
-        tool = TrivialTool()
+        tool = TrivialTool(commands=[TrivialCommand(), UncommonCommand()])
         self.assertEqual(tool.command_by_name("trivial").name, "trivial")
         self.assertIsNone(tool.command_by_name("bar"))
 
@@ -130,7 +132,7 @@
         self._assert_tool_main_outputs(tool, ["tool", "--all-commands", "help"], expected_all_commands_help)
 
     def test_command_help(self):
-        command_with_options = TrivialCommand(options=[make_option("--my_option")], )
+        command_with_options = TrivialCommand(options=[make_option("--my_option")])
         tool = TrivialTool(commands=[command_with_options])
         expected_subcommand_help = """trivial [options]   help text
 
@@ -141,3 +143,8 @@
 
 """
         self._assert_tool_main_outputs(tool, ["tool", "help", "trivial"], expected_subcommand_help)
+
+    def test_constructor_calls_bind_to_tool(self):
+        tool = TrivialTool(commands=[TrivialCommand(), UncommonCommand()])
+        self.assertEqual(tool.commands[0]._tool, tool)
+        self.assertEqual(tool.commands[1]._tool, tool)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
index a26adba..298be7a 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/webkit_patch.py
@@ -33,7 +33,23 @@
 
 from webkitpy.common.host import Host
 from webkitpy.tool.multi_command_tool import MultiCommandTool
-from webkitpy.tool import commands
+
+from webkitpy.tool.commands.analyze_baselines import AnalyzeBaselines
+from webkitpy.tool.commands.commit_announcer import CommitAnnouncerCommand
+from webkitpy.tool.commands.flaky_tests import FlakyTests
+from webkitpy.tool.commands.layout_tests_server import LayoutTestsServer
+from webkitpy.tool.commands.pretty_diff import PrettyDiff
+from webkitpy.tool.commands.queries import CrashLog
+from webkitpy.tool.commands.queries import PrintBaselines
+from webkitpy.tool.commands.queries import PrintExpectations
+from webkitpy.tool.commands.rebaseline import AutoRebaseline
+from webkitpy.tool.commands.rebaseline import CopyExistingBaselinesInternal
+from webkitpy.tool.commands.rebaseline import OptimizeBaselines
+from webkitpy.tool.commands.rebaseline import Rebaseline
+from webkitpy.tool.commands.rebaseline import RebaselineExpectations
+from webkitpy.tool.commands.rebaseline import RebaselineJson
+from webkitpy.tool.commands.rebaseline import RebaselineTest
+from webkitpy.tool.commands.rebaseline_server import RebaselineServer
 
 
 class WebKitPatch(MultiCommandTool, Host):
@@ -44,7 +60,24 @@
     ]
 
     def __init__(self, path):
-        MultiCommandTool.__init__(self)
+        MultiCommandTool.__init__(self, commands=[
+            AnalyzeBaselines(),
+            AutoRebaseline(),
+            CommitAnnouncerCommand(),
+            CopyExistingBaselinesInternal(),
+            CrashLog(),
+            FlakyTests(),
+            LayoutTestsServer(),
+            OptimizeBaselines(),
+            PrettyDiff(),
+            PrintBaselines(),
+            PrintExpectations(),
+            Rebaseline(),
+            RebaselineExpectations(),
+            RebaselineJson(),
+            RebaselineServer(),
+            RebaselineTest(),
+        ])
         Host.__init__(self)
         self._path = path
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
index d624e2b..d56f1682 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/deps_updater.py
@@ -5,7 +5,6 @@
 """Pull latest revisions of a W3C test repo and make a local commit."""
 
 import argparse
-import re
 
 from webkitpy.common.webkit_finder import WebKitFinder
 
@@ -24,6 +23,7 @@
         self.verbose = False
         self.allow_local_commits = False
         self.keep_w3c_repos_around = False
+        self.target = None
 
     def main(self, argv=None):
         self.parse_args(argv)
@@ -171,11 +171,11 @@
         else:
             self.print_('## Done: no changes to import.')
 
-    def is_manual_test(self, fs, dirname, basename):
+    def is_manual_test(self, fs, dirname, basename):  # Callback for FileSystem.files_under; not all arguments used - pylint: disable=unused-argument
         # We are importing manual pointer event tests and we are automating them.
         return ("pointerevents" not in dirname) and (basename.endswith('-manual.html') or basename.endswith('-manual.htm'))
 
-    def is_baseline(self, fs, dirname, basename):
+    def is_baseline(self, fs, dirname, basename):  # Callback for FileSystem.files_under; not all arguments used - pylint: disable=unused-argument
         return basename.endswith('-expected.txt')
 
     def is_not_baseline(self, fs, dirname, basename):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter.py
index f2727e5f..061595e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter.py
@@ -82,8 +82,8 @@
         # These settings might vary between WebKit and Blink.
         self._css_property_file = self.path_from_webkit_root('Source', 'core', 'css', 'CSSProperties.in')
         self.prefixed_properties = self.read_webkit_prefixed_css_property_list()
-        prop_regex = '([\s{]|^)(' + "|".join(
-            prop.replace('-webkit-', '') for prop in self.prefixed_properties) + ')(\s+:|:)'
+        prop_regex = r'([\s{]|^)(' + '|'.join(
+            prop.replace('-webkit-', '') for prop in self.prefixed_properties) + r')(\s+:|:)'
         self.prop_re = re.compile(prop_regex)
 
     def output(self):
@@ -98,12 +98,12 @@
 
         contents = self._filesystem.read_text_file(self._css_property_file)
         for line in contents.splitlines():
-            if re.match('^(#|//|$)', line):
+            if re.match(r'^(#|//|$)', line):
                 # skip comments and preprocessor directives.
                 continue
             prop = line.split()[0]
             # Find properties starting with the -webkit- prefix.
-            match = re.match('-webkit-([\w|-]*)', prop)
+            match = re.match(r'-webkit-([\w|-]*)', prop)
             if match:
                 prefixed_properties.append(match.group(1))
             else:
@@ -170,8 +170,8 @@
                 converted = re.sub(re.escape(attr_value), new_style, converted)
             if attr_name == 'class' and 'instructions' in attr_value:
                 # Always hide instructions, they're for manual testers.
-                converted = re.sub(' style=".*?"', '', converted)
-                converted = re.sub('\>', ' style="display:none">', converted)
+                converted = re.sub(r' style=".*?"', '', converted)
+                converted = re.sub(r'\>', ' style="display:none">', converted)
 
         src_tags = ('script', 'img', 'style', 'frame', 'iframe', 'input', 'layer', 'textarea', 'video', 'audio')
         if tag in src_tags and self.reference_support_info is not None and self.reference_support_info != {}:
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter_unittest.py
index 88491d1..0adfd83 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_converter_unittest.py
@@ -25,14 +25,12 @@
 # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 
-import os
 import re
 import unittest
 
 from webkitpy.common.host import Host
 from webkitpy.common.system.outputcapture import OutputCapture
 from webkitpy.common.webkit_finder import WebKitFinder
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
 from webkitpy.w3c.test_converter import _W3CTestConverter, convert_for_webkit
 from webkitpy.common.system.systemhost_mock import MockSystemHost
 from webkitpy.common.system.filesystem_mock import MockFileSystem
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 933b5d5d..81d897a9 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_importer.py
@@ -384,6 +384,8 @@
                 else:
                     if not self.import_in_place and not self.options.dry_run:
                         self.filesystem.copyfile(orig_filepath, new_filepath)
+                        if self.filesystem.is_executable(orig_filepath):
+                            self.filesystem.make_executable(new_filepath)
 
                 copied_files.append(new_filepath.replace(self._webkit_root, ''))
 
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 51753781..fee91be 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
@@ -107,3 +107,12 @@
                            'jstests': 0,
                            'reftests': 0,
                            'total_tests': 0}])
+
+    def test_executablebit(self):
+        # executable source files are executable after importing
+        host = MockHost()
+        host.filesystem = MockFileSystem(files=FAKE_FILES)
+        host.filesystem.make_executable('/blink/w3c/dir/README.txt')
+        importer = TestImporter(host, FAKE_SOURCE_REPO_DIR, self.options())
+        importer.do_import()
+        self.assertTrue(host.filesystem.is_executable('/mock-checkout/third_party/WebKit/LayoutTests/w3c/blink/w3c/dir/README.txt'))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py
index 868de32f..19ccb90 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py
@@ -25,11 +25,12 @@
 # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 # SUCH DAMAGE.
 
+import HTMLParser
 import logging
 import re
 
 from webkitpy.common.host import Host
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup as Parser
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
 
 
 _log = logging.getLogger(__name__)
@@ -50,10 +51,13 @@
     def load_file(self, filename, is_ref=False):
         if self.filesystem.isfile(filename):
             try:
-                doc = Parser(self.filesystem.read_binary_file(filename))
-            except:
+                doc = BeautifulSoup(self.filesystem.read_binary_file(filename))
+            except IOError:
+                _log.error("IOError: Failed to read %s", filename)
+                doc = None
+            except HTMLParser.HTMLParseError:
                 # FIXME: Figure out what to do if we can't parse the file.
-                _log.error("Failed to parse %s", filename)
+                _log.error("HTMLParseError: Failed to parse %s", filename)
                 doc = None
         else:
             if self.filesystem.isdir(filename):
@@ -82,10 +86,10 @@
             return test_info
 
         if test_contents is not None:
-            self.test_doc = Parser(test_contents)
+            self.test_doc = BeautifulSoup(test_contents)
 
         if ref_contents is not None:
-            self.ref_doc = Parser(ref_contents)
+            self.ref_doc = BeautifulSoup(ref_contents)
 
         # First check if it's a reftest
         matches = self.reference_links_of_type('match') + self.reference_links_of_type('mismatch')
@@ -97,7 +101,7 @@
 
             try:
                 ref_file = self.filesystem.join(self.filesystem.dirname(self.filename), matches[0]['href'])
-            except KeyError as e:
+            except KeyError:
                 # FIXME: Figure out what to do w/ invalid test files.
                 _log.error('%s has a reference link but is missing the "href"', self.filesystem)
                 return None
@@ -118,7 +122,7 @@
 
         elif self.is_jstest():
             test_info = {'test': self.filename, 'jstest': True}
-        elif self.options['all'] is True and not('-ref' in self.filename) and not('reference' in self.filename):
+        elif self.options['all'] and '-ref' not in self.filename and 'reference' not in self.filename:
             test_info = {'test': self.filename}
 
         return test_info
@@ -140,12 +144,12 @@
         elements_with_src_attributes = doc.findAll(src=re.compile('.*'))
         elements_with_href_attributes = doc.findAll(href=re.compile('.*'))
 
-        url_pattern = re.compile('url\(.*\)')
+        url_pattern = re.compile(r'url\(.*\)')
         urls = []
         for url in doc.findAll(text=url_pattern):
             url = re.search(url_pattern, url)
-            url = re.sub('url\([\'\"]?', '', url.group(0))
-            url = re.sub('[\'\"]?\)', '', url)
+            url = re.sub(r'url\([\'\"]?', '', url.group(0))
+            url = re.sub(r'[\'\"]?\)', '', url)
             urls.append(url)
 
         src_paths = [src_tag['src'] for src_tag in elements_with_src_attributes]
@@ -153,8 +157,8 @@
 
         paths = src_paths + href_paths + urls
         for path in paths:
-            if not(path.startswith('http:')) and not(path.startswith('mailto:')):
-                uri_scheme_pattern = re.compile(r"[A-Za-z][A-Za-z+.-]*:")
+            if not path.startswith('http:') and not path.startswith('mailto:'):
+                uri_scheme_pattern = re.compile(r'[A-Za-z][A-Za-z+.-]*:')
                 if not uri_scheme_pattern.match(path):
                     support_files.append(path)
 
diff --git a/third_party/WebKit/public/platform/modules/payments/payment_request.mojom b/third_party/WebKit/public/platform/modules/payments/payment_request.mojom
index 0f07092..f7ef0579 100644
--- a/third_party/WebKit/public/platform/modules/payments/payment_request.mojom
+++ b/third_party/WebKit/public/platform/modules/payments/payment_request.mojom
@@ -35,7 +35,7 @@
 // The currency amount that the renderer provides to the browser process. The
 // browser shows the amount in UI and forwards it on to the payment app, if it
 // requires the amount.
-struct CurrencyAmount {
+struct PaymentCurrencyAmount {
   // ISO 4217 currency code. Three upper case ASCII letters.
   string currency;
 
@@ -46,7 +46,7 @@
 
 struct PaymentResponse {
   string method_name;
-  CurrencyAmount total_amount;
+  PaymentCurrencyAmount total_amount;
 
   // Payment method specific JSON string that is built either by the browser or
   // a payment app, for example Android Pay. Browser ensures that the string can
@@ -59,7 +59,7 @@
   string stringified_details;
 
   PaymentAddress? shipping_address;
-  string? shipping_option_id;
+  string? shipping_option;
   string? payer_email;
   string? payer_phone;
 };
@@ -75,20 +75,20 @@
 
 struct PaymentItem {
   string label;
-  CurrencyAmount amount;
+  PaymentCurrencyAmount amount;
 };
 
-struct ShippingOption {
+struct PaymentShippingOption {
   string id;
   string label;
-  CurrencyAmount amount;
+  PaymentCurrencyAmount amount;
   bool selected;
 };
 
 struct PaymentDetails {
   PaymentItem total;
   array<PaymentItem> display_items;
-  array<ShippingOption> shipping_options;
+  array<PaymentShippingOption> shipping_options;
 };
 
 struct PaymentOptions {
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index 760bfe89..e1ae36e 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -4788,13 +4788,11 @@
   files in a target are compiled. So if you depend on generated headers,
   you do not typically need to list them in the inputs section.
 
-  Inputs for binary targets will be treated as order-only dependencies,
-  meaning that they will be forced up to date before compiling or
-  any files in the target, but changes in the inputs will not
-  necessarily force the target to compile. This is because it is
-  expected that the compiler will report the precise list of input
-  dependencies required to recompile each file once the initial build
-  is done.
+  Inputs for binary targets will be treated as implicit dependencies,
+  meaning that changes in any of the inputs will force all sources in
+  the target to be recompiled. If an input only applies to a subset of
+  source files, you may want to split those into a separate target to
+  avoid unnecessary recompiles.
 
 ```
 
diff --git a/tools/gn/ninja_binary_target_writer.cc b/tools/gn/ninja_binary_target_writer.cc
index b012e42b..9b0458a 100644
--- a/tools/gn/ninja_binary_target_writer.cc
+++ b/tools/gn/ninja_binary_target_writer.cc
@@ -270,6 +270,8 @@
 
   WriteCompilerVars(used_types);
 
+  OutputFile input_dep = WriteInputsStampAndGetDep();
+
   // The input dependencies will be an order-only dependency. This will cause
   // Ninja to make sure the inputs are up to date before compiling this source,
   // but changes in the inputs deps won't cause the file to be recompiled.
@@ -301,7 +303,7 @@
   // |pch_other_files|. This is to prevent linking against them.
   std::vector<OutputFile> pch_obj_files;
   std::vector<OutputFile> pch_other_files;
-  WritePCHCommands(used_types, order_only_dep,
+  WritePCHCommands(used_types, input_dep, order_only_dep,
                    &pch_obj_files, &pch_other_files);
   std::vector<OutputFile>* pch_files = !pch_obj_files.empty() ?
       &pch_obj_files : &pch_other_files;
@@ -320,7 +322,7 @@
   //    object file list.
   std::vector<OutputFile> obj_files;
   std::vector<SourceFile> other_files;
-  WriteSources(*pch_files, order_only_dep, &obj_files, &other_files);
+  WriteSources(*pch_files, input_dep, order_only_dep, &obj_files, &other_files);
 
   // Link all MSVC pch object files. The vector will be empty on GCC toolchains.
   obj_files.insert(obj_files.end(), pch_obj_files.begin(), pch_obj_files.end());
@@ -401,6 +403,43 @@
   WriteSharedVars(subst);
 }
 
+OutputFile NinjaBinaryTargetWriter::WriteInputsStampAndGetDep() const {
+  CHECK(target_->toolchain())
+      << "Toolchain not set on target "
+      << target_->label().GetUserVisibleName(true);
+
+  if (target_->inputs().size() == 0)
+    return OutputFile();  // No inputs
+
+  // If we only have one input, return it directly instead of writing a stamp
+  // file for it.
+  if (target_->inputs().size() == 1)
+    return OutputFile(settings_->build_settings(), target_->inputs()[0]);
+
+  // Make a stamp file.
+  OutputFile input_stamp_file(
+      RebasePath(GetTargetOutputDir(target_).value(),
+                 settings_->build_settings()->build_dir(),
+                 settings_->build_settings()->root_path_utf8()));
+  input_stamp_file.value().append(target_->label().name());
+  input_stamp_file.value().append(".inputs.stamp");
+
+  out_ << "build ";
+  path_output_.WriteFile(out_, input_stamp_file);
+  out_ << ": "
+       << GetNinjaRulePrefixForToolchain(settings_)
+       << Toolchain::ToolTypeToName(Toolchain::TYPE_STAMP);
+
+  // File inputs.
+  for (const auto& input : target_->inputs()) {
+    out_ << " ";
+    path_output_.WriteFile(out_, input);
+  }
+
+  out_ << "\n";
+  return input_stamp_file;
+}
+
 void NinjaBinaryTargetWriter::WriteOneFlag(
     SubstitutionType subst_enum,
     bool has_precompiled_headers,
@@ -453,6 +492,7 @@
 
 void NinjaBinaryTargetWriter::WritePCHCommands(
     const SourceFileTypeSet& used_types,
+    const OutputFile& input_dep,
     const OutputFile& order_only_dep,
     std::vector<OutputFile>* object_files,
     std::vector<OutputFile>* other_files) {
@@ -466,7 +506,7 @@
     WritePCHCommand(SUBSTITUTION_CFLAGS_C,
                     Toolchain::TYPE_CC,
                     tool_c->precompiled_header_type(),
-                    order_only_dep, object_files, other_files);
+                    input_dep, order_only_dep, object_files, other_files);
   }
   const Tool* tool_cxx = target_->toolchain()->GetTool(Toolchain::TYPE_CXX);
   if (tool_cxx &&
@@ -475,7 +515,7 @@
     WritePCHCommand(SUBSTITUTION_CFLAGS_CC,
                     Toolchain::TYPE_CXX,
                     tool_cxx->precompiled_header_type(),
-                    order_only_dep, object_files, other_files);
+                    input_dep, order_only_dep, object_files, other_files);
   }
 
   const Tool* tool_objc = target_->toolchain()->GetTool(Toolchain::TYPE_OBJC);
@@ -485,7 +525,7 @@
     WritePCHCommand(SUBSTITUTION_CFLAGS_OBJC,
                     Toolchain::TYPE_OBJC,
                     tool_objc->precompiled_header_type(),
-                    order_only_dep, object_files, other_files);
+                    input_dep, order_only_dep, object_files, other_files);
   }
 
   const Tool* tool_objcxx =
@@ -496,7 +536,7 @@
     WritePCHCommand(SUBSTITUTION_CFLAGS_OBJCC,
                     Toolchain::TYPE_OBJCXX,
                     tool_objcxx->precompiled_header_type(),
-                    order_only_dep, object_files, other_files);
+                    input_dep, order_only_dep, object_files, other_files);
   }
 }
 
@@ -504,16 +544,17 @@
     SubstitutionType flag_type,
     Toolchain::ToolType tool_type,
     Tool::PrecompiledHeaderType header_type,
+    const OutputFile& input_dep,
     const OutputFile& order_only_dep,
     std::vector<OutputFile>* object_files,
     std::vector<OutputFile>* other_files) {
   switch (header_type) {
     case Tool::PCH_MSVC:
-      WriteWindowsPCHCommand(flag_type, tool_type, order_only_dep,
+      WriteWindowsPCHCommand(flag_type, tool_type, input_dep, order_only_dep,
                              object_files);
       break;
     case Tool::PCH_GCC:
-      WriteGCCPCHCommand(flag_type, tool_type, order_only_dep,
+      WriteGCCPCHCommand(flag_type, tool_type, input_dep, order_only_dep,
                          other_files);
       break;
     case Tool::PCH_NONE:
@@ -525,6 +566,7 @@
 void NinjaBinaryTargetWriter::WriteGCCPCHCommand(
     SubstitutionType flag_type,
     Toolchain::ToolType tool_type,
+    const OutputFile& input_dep,
     const OutputFile& order_only_dep,
     std::vector<OutputFile>* gch_files) {
   // Compute the pch output file (it will be language-specific).
@@ -535,10 +577,13 @@
 
   gch_files->insert(gch_files->end(), outputs.begin(), outputs.end());
 
+  std::vector<OutputFile> extra_deps;
+  if (!input_dep.value().empty())
+    extra_deps.push_back(input_dep);
+
   // Build line to compile the file.
   WriteCompilerBuildLine(target_->config_values().precompiled_source(),
-                         std::vector<OutputFile>(), order_only_dep, tool_type,
-                         outputs);
+                         extra_deps, order_only_dep, tool_type, outputs);
 
   // This build line needs a custom language-specific flags value. Rule-specific
   // variables are just indented underneath the rule line.
@@ -573,6 +618,7 @@
 void NinjaBinaryTargetWriter::WriteWindowsPCHCommand(
     SubstitutionType flag_type,
     Toolchain::ToolType tool_type,
+    const OutputFile& input_dep,
     const OutputFile& order_only_dep,
     std::vector<OutputFile>* object_files) {
   // Compute the pch output file (it will be language-specific).
@@ -583,10 +629,13 @@
 
   object_files->insert(object_files->end(), outputs.begin(), outputs.end());
 
+  std::vector<OutputFile> extra_deps;
+  if (!input_dep.value().empty())
+    extra_deps.push_back(input_dep);
+
   // Build line to compile the file.
   WriteCompilerBuildLine(target_->config_values().precompiled_source(),
-                         std::vector<OutputFile>(), order_only_dep, tool_type,
-                         outputs);
+                         extra_deps, order_only_dep, tool_type, outputs);
 
   // This build line needs a custom language-specific flags value. Rule-specific
   // variables are just indented underneath the rule line.
@@ -604,6 +653,7 @@
 
 void NinjaBinaryTargetWriter::WriteSources(
     const std::vector<OutputFile>& pch_deps,
+    const OutputFile& input_dep,
     const OutputFile& order_only_dep,
     std::vector<OutputFile>* object_files,
     std::vector<SourceFile>* other_files) {
@@ -621,6 +671,9 @@
       continue;  // No output for this source.
     }
 
+    if (!input_dep.value().empty())
+      deps.push_back(input_dep);
+
     if (tool_type != Toolchain::TYPE_NONE) {
       // Only include PCH deps that correspond to the tool type, for instance,
       // do not specify target_name.precompile.cc.obj (a CXX PCH file) as a dep
diff --git a/tools/gn/ninja_binary_target_writer.h b/tools/gn/ninja_binary_target_writer.h
index 1876486f..0188720 100644
--- a/tools/gn/ninja_binary_target_writer.h
+++ b/tools/gn/ninja_binary_target_writer.h
@@ -31,6 +31,12 @@
   // Writes all flags for the compiler: includes, defines, cflags, etc.
   void WriteCompilerVars(const SourceFileTypeSet& used_types);
 
+  // Writes to the output stream a stamp rule for inputs, and
+  // returns the file to be appended to source rules that encodes the
+  // implicit dependencies for the current target. The returned OutputFile
+  // will be empty if there are no inputs.
+  OutputFile WriteInputsStampAndGetDep() const;
+
   // has_precompiled_headers is set when this substitution matches a tool type
   // that supports precompiled headers, and this target supports precompiled
   // headers. It doesn't indicate if the tool has precompiled headers (this
@@ -55,6 +61,7 @@
   // compiling this target. It will be empty if there are no input deps.
   void WritePCHCommands(const SourceFileTypeSet& used_types,
                         const OutputFile& input_dep,
+                        const OutputFile& order_only_dep,
                         std::vector<OutputFile>* object_files,
                         std::vector<OutputFile>* other_files);
 
@@ -63,16 +70,19 @@
                        Toolchain::ToolType tool_type,
                        Tool::PrecompiledHeaderType header_type,
                        const OutputFile& input_dep,
+                       const OutputFile& order_only_dep,
                        std::vector<OutputFile>* object_files,
                        std::vector<OutputFile>* other_files);
 
   void WriteGCCPCHCommand(SubstitutionType flag_type,
                           Toolchain::ToolType tool_type,
+                          const OutputFile& input_dep,
                           const OutputFile& order_only_dep,
                           std::vector<OutputFile>* gch_files);
 
   void WriteWindowsPCHCommand(SubstitutionType flag_type,
                               Toolchain::ToolType tool_type,
+                              const OutputFile& input_dep,
                               const OutputFile& order_only_dep,
                               std::vector<OutputFile>* object_files);
 
@@ -84,6 +94,7 @@
   //
   // The files produced by the compiler will be added to two output vectors.
   void WriteSources(const std::vector<OutputFile>& pch_deps,
+                    const OutputFile& input_dep,
                     const OutputFile& order_only_dep,
                     std::vector<OutputFile>* object_files,
                     std::vector<SourceFile>* other_files);
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc
index f2297fbf..1cfdb56f 100644
--- a/tools/gn/ninja_binary_target_writer_unittest.cc
+++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -854,3 +854,85 @@
   // Should have issued an error.
   EXPECT_TRUE(scheduler.is_failed());
 }
+
+// This tests that output extension and output dir overrides apply, and input
+// dependencies are applied.
+TEST(NinjaBinaryTargetWriter, InputFiles) {
+  TestWithScope setup;
+  Err err;
+
+  setup.build_settings()->SetBuildDir(SourceDir("//out/Debug/"));
+
+  // This target has one input.
+  {
+    Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+    target.set_output_type(Target::SOURCE_SET);
+    target.visibility().SetPublic();
+    target.sources().push_back(SourceFile("//foo/input1.cc"));
+    target.sources().push_back(SourceFile("//foo/input2.cc"));
+    target.inputs().push_back(SourceFile("//foo/input.data"));
+    target.SetToolchain(setup.toolchain());
+    ASSERT_TRUE(target.OnResolved(&err));
+
+    std::ostringstream out;
+    NinjaBinaryTargetWriter writer(&target, out);
+    writer.Run();
+
+    const char expected[] =
+        "defines =\n"
+        "include_dirs =\n"
+        "cflags =\n"
+        "cflags_cc =\n"
+        "root_out_dir = .\n"
+        "target_out_dir = obj/foo\n"
+        "target_output_name = bar\n"
+        "\n"
+        "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
+          " | ../../foo/input.data\n"
+        "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
+          " | ../../foo/input.data\n"
+        "\n"
+        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+            "obj/foo/bar.input2.o\n";
+
+    EXPECT_EQ(expected, out.str());
+  }
+
+  // This target has multiple inputs.
+  {
+    Target target(setup.settings(), Label(SourceDir("//foo/"), "bar"));
+    target.set_output_type(Target::SOURCE_SET);
+    target.visibility().SetPublic();
+    target.sources().push_back(SourceFile("//foo/input1.cc"));
+    target.sources().push_back(SourceFile("//foo/input2.cc"));
+    target.inputs().push_back(SourceFile("//foo/input1.data"));
+    target.inputs().push_back(SourceFile("//foo/input2.data"));
+    target.SetToolchain(setup.toolchain());
+    ASSERT_TRUE(target.OnResolved(&err));
+
+    std::ostringstream out;
+    NinjaBinaryTargetWriter writer(&target, out);
+    writer.Run();
+
+    const char expected[] =
+        "defines =\n"
+        "include_dirs =\n"
+        "cflags =\n"
+        "cflags_cc =\n"
+        "root_out_dir = .\n"
+        "target_out_dir = obj/foo\n"
+        "target_output_name = bar\n"
+        "\n"
+        "build obj/foo/bar.inputs.stamp: stamp"
+          " ../../foo/input1.data ../../foo/input2.data\n"
+        "build obj/foo/bar.input1.o: cxx ../../foo/input1.cc"
+          " | obj/foo/bar.inputs.stamp\n"
+        "build obj/foo/bar.input2.o: cxx ../../foo/input2.cc"
+          " | obj/foo/bar.inputs.stamp\n"
+        "\n"
+        "build obj/foo/bar.stamp: stamp obj/foo/bar.input1.o "
+            "obj/foo/bar.input2.o\n";
+
+    EXPECT_EQ(expected, out.str());
+  }
+}
diff --git a/tools/gn/ninja_target_writer.cc b/tools/gn/ninja_target_writer.cc
index 486930b..7843d75 100644
--- a/tools/gn/ninja_target_writer.cc
+++ b/tools/gn/ninja_target_writer.cc
@@ -165,9 +165,13 @@
       target_->output_type() == Target::ACTION_FOREACH)
     input_deps_sources.push_back(&target_->action_values().script());
 
-  // Input files.
-  for (const auto& input : target_->inputs())
-    input_deps_sources.push_back(&input);
+  // Input files are only considered for non-binary targets which use an
+  // implicit dependency instead. The implicit depedency in this case is
+  // handled separately by the binary target writer.
+  if (!target_->IsBinary()) {
+    for (const auto& input : target_->inputs())
+      input_deps_sources.push_back(&input);
+  }
 
   // For an action (where we run a script only once) the sources are the same
   // as the inputs. For action_foreach, the sources will be operated on
diff --git a/tools/gn/ninja_target_writer_unittest.cc b/tools/gn/ninja_target_writer_unittest.cc
index ccb9c7a3..55bbde0 100644
--- a/tools/gn/ninja_target_writer_unittest.cc
+++ b/tools/gn/ninja_target_writer_unittest.cc
@@ -85,12 +85,9 @@
     OutputFile dep =
         writer.WriteInputDepsStampAndGetDep(std::vector<const Target*>());
 
-    // Since there is more than one dependency, a stamp file will be returned
-    // and the rule for the stamp file will be written to the stream.
-    EXPECT_EQ("obj/foo/target.inputdeps.stamp", dep.value());
-    EXPECT_EQ("build obj/foo/target.inputdeps.stamp: stamp "
-                  "../../foo/input.txt obj/foo/base.stamp\n",
-              stream.str());
+    // Since there is only one dependency, a stamp file will be returned
+    // directly without writing any additional rules.
+    EXPECT_EQ("obj/foo/base.stamp", dep.value());
   }
 
   // Input deps for action which should depend on the base since its a hard dep
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 3c717d8..7b2c4a0 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -1048,13 +1048,11 @@
     "  files in a target are compiled. So if you depend on generated headers,\n"
     "  you do not typically need to list them in the inputs section.\n"
     "\n"
-    "  Inputs for binary targets will be treated as order-only dependencies,\n"
-    "  meaning that they will be forced up to date before compiling or\n"
-    "  any files in the target, but changes in the inputs will not\n"
-    "  necessarily force the target to compile. This is because it is\n"
-    "  expected that the compiler will report the precise list of input\n"
-    "  dependencies required to recompile each file once the initial build\n"
-    "  is done.\n"
+    "  Inputs for binary targets will be treated as implicit dependencies,\n"
+    "  meaning that changes in any of the inputs will force all sources in\n"
+    "  the target to be recompiled. If an input only applies to a subset of\n"
+    "  source files, you may want to split those into a separate target to\n"
+    "  avoid unnecessary recompiles.\n"
     "\n"
     "Example\n"
     "\n"
diff --git a/tools/licenses.py b/tools/licenses.py
index 7a77710c..6051483 100755
--- a/tools/licenses.py
+++ b/tools/licenses.py
@@ -51,7 +51,6 @@
     os.path.join('third_party','gnu_binutils'),
     os.path.join('third_party','gold'),
     os.path.join('third_party','gperf'),
-    os.path.join('third_party','jarjar'),
     os.path.join('third_party','kasko'),
     os.path.join('third_party','lighttpd'),
     os.path.join('third_party','llvm'),
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 776098b..006db95 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -2907,8 +2907,13 @@
 </action>
 
 <action name="CustomTabsMenuOpenInChrome">
-  <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
-  <description>Please enter the description of the metric.</description>
+  <owner>yusufo@chromium.org</owner>
+  <description>User hit &quot;open in browser&quot; menu item.</description>
+</action>
+
+<action name="CustomTabsMenuReadItLater">
+  <owner>ianwen@chromium.org</owner>
+  <description>User hit &quot;read it later&quot; menu item.</description>
 </action>
 
 <action name="CustomTabsRemoteViewsShown">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 922fdc96..6f72e36 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -80149,6 +80149,7 @@
   <int value="716080990" label="restrict-iframe-permissions"/>
   <int value="730024226" label="enable-out-of-process-pdf"/>
   <int value="732703958" label="enable-gesture-tap-highlight"/>
+  <int value="745868416" label="disable-system-timezone-automatic-detection"/>
   <int value="752194066" label="enable-app-window-cycling"/>
   <int value="752939691" label="disable-tab-for-desktop-share"/>
   <int value="773919225" label="disable-office-editing-component-extension"/>
@@ -80218,6 +80219,7 @@
   <int value="1166169237" label="disable-delay-agnostic-aec"/>
   <int value="1167613030" label="enable-permission-action-reporting"/>
   <int value="1174088940" label="enable-wasm"/>
+  <int value="1179936481" label="enable-android-pay-integration-v1"/>
   <int value="1181056275" label="enable-cloud-backup"/>
   <int value="1183431946" label="v8-cache-options"/>
   <int value="1185424279" label="enable-media-router"/>
diff --git a/tools/perf/measurements/draw_properties.py b/tools/perf/measurements/draw_properties.py
index 5f9fe19..3bf47cc 100644
--- a/tools/perf/measurements/draw_properties.py
+++ b/tools/perf/measurements/draw_properties.py
@@ -21,7 +21,7 @@
   def WillNavigateToPage(self, page, tab):
     del page  # unused
     config = tracing_config.TracingConfig()
-    config.tracing_category_filter.AddDisabledByDefault(
+    config.chrome_trace_config.tracing_category_filter.AddDisabledByDefault(
         'disabled-by-default-cc.debug.cdp-perf')
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(config)
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py
index 62f39b4..93b2976 100644
--- a/tools/perf/measurements/image_decoding.py
+++ b/tools/perf/measurements/image_decoding.py
@@ -40,10 +40,10 @@
     # the ref builds are updated. crbug.com/386847
     # FIXME: Remove the devtools.timeline category when impl-side painting is
     # on everywhere.
-    config.tracing_category_filter.AddDisabledByDefault(
+    config.chrome_trace_config.tracing_category_filter.AddDisabledByDefault(
         'disabled-by-default-devtools.timeline')
     for c in ['blink', 'devtools.timeline', 'webkit.console', 'blink.console']:
-      config.tracing_category_filter.AddIncludedCategory(c)
+      config.chrome_trace_config.tracing_category_filter.AddIncludedCategory(c)
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(config)
 
diff --git a/tools/perf/measurements/oilpan_gc_times.py b/tools/perf/measurements/oilpan_gc_times.py
index d2e29b5..82737a26 100644
--- a/tools/perf/measurements/oilpan_gc_times.py
+++ b/tools/perf/measurements/oilpan_gc_times.py
@@ -140,7 +140,7 @@
     # the ref builds are updated. crbug.com/386847
     config = tracing_config.TracingConfig()
     for c in ['webkit.console', 'blink.console', 'blink_gc']:
-      config.tracing_category_filter.AddIncludedCategory(c)
+      config.chrome_trace_config.tracing_category_filter.AddIncludedCategory(c)
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(config, timeout=1000)
 
diff --git a/tools/perf/measurements/task_execution_time.py b/tools/perf/measurements/task_execution_time.py
index f13dec7a..dbc5b8f 100644
--- a/tools/perf/measurements/task_execution_time.py
+++ b/tools/perf/measurements/task_execution_time.py
@@ -44,7 +44,8 @@
     del page  # unused
     config = tracing_config.TracingConfig()
     for category in self._CATEGORIES:
-      config.tracing_category_filter.AddIncludedCategory(category)
+      config.chrome_trace_config.tracing_category_filter.AddIncludedCategory(
+          category)
     config.enable_chrome_trace = True
 
     tab.browser.platform.tracing_controller.StartTracing(
diff --git a/tools/perf/measurements/timeline_controller.py b/tools/perf/measurements/timeline_controller.py
index 07ac303..989f266 100644
--- a/tools/perf/measurements/timeline_controller.py
+++ b/tools/perf/measurements/timeline_controller.py
@@ -34,9 +34,11 @@
     if not tab.browser.platform.tracing_controller.IsChromeTracingSupported():
       raise Exception('Not supported')
     config = tracing_config.TracingConfig()
-    config.tracing_category_filter.AddFilterString(self.trace_categories)
+    config.chrome_trace_config.tracing_category_filter.AddFilterString(
+        self.trace_categories)
     for delay in page.GetSyntheticDelayCategories():
-      config.tracing_category_filter.AddSyntheticDelay(delay)
+      config.chrome_trace_config.tracing_category_filter.AddSyntheticDelay(
+          delay)
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(config)
 
diff --git a/tools/perf/measurements/v8_gc_times.py b/tools/perf/measurements/v8_gc_times.py
index 805b4fb..a25346d 100644
--- a/tools/perf/measurements/v8_gc_times.py
+++ b/tools/perf/measurements/v8_gc_times.py
@@ -26,7 +26,8 @@
     del page  # unused
     config = tracing_config.TracingConfig()
     for category in self._CATEGORIES:
-      config.tracing_category_filter.AddIncludedCategory(category)
+      config.chrome_trace_config.tracing_category_filter.AddIncludedCategory(
+          category)
     config.enable_chrome_trace = True
     tab.browser.platform.tracing_controller.StartTracing(
         config, self._TIME_OUT_IN_SECONDS)
diff --git a/ui/base/test/ui_controls_mac.mm b/ui/base/test/ui_controls_mac.mm
index b7615b6c..46db392 100644
--- a/ui/base/test/ui_controls_mac.mm
+++ b/ui/base/test/ui_controls_mac.mm
@@ -9,10 +9,14 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#import "base/mac/foundation_util.h"
+#import "base/mac/scoped_objc_class_swizzler.h"
 #include "base/message_loop/message_loop.h"
 #include "ui/base/cocoa/cocoa_base_utils.h"
 #include "ui/events/keycodes/keyboard_code_conversion_mac.h"
 #import "ui/events/test/cocoa_test_event_utils.h"
+#include "ui/gfx/geometry/point.h"
+#import "ui/gfx/mac/coordinate_conversion.h"
 
 // Implementation details: We use [NSApplication sendEvent:] instead
 // of [NSApplication postEvent:atStart:] so that the event gets sent
@@ -52,6 +56,10 @@
 // when firing keyboard and mouse click events.
 NSPoint g_mouse_location = { 0, 0 };
 
+// Stores the current pressed mouse buttons. Indexed by
+// ui_controls::MouseButton.
+bool g_mouse_button_down[3] = {false, false, false};
+
 bool g_ui_controls_enabled = false;
 
 // Creates the proper sequence of autoreleased key events for a key down + up.
@@ -173,10 +181,63 @@
 
 }  // namespace
 
+// Donates testing implementations of NSEvent methods.
+@interface FakeNSEventTestingDonor : NSObject
+@end
+
+@implementation FakeNSEventTestingDonor
++ (NSPoint)mouseLocation {
+  return g_mouse_location;
+}
+
++ (NSUInteger)pressedMouseButtons {
+  NSUInteger result = 0;
+  const int buttons[3] = {
+      ui_controls::LEFT, ui_controls::RIGHT, ui_controls::MIDDLE};
+  for (size_t i = 0; i < arraysize(buttons); ++i) {
+    if (g_mouse_button_down[buttons[i]])
+      result |= (1 << i);
+  }
+  return result;
+}
+@end
+
+namespace {
+
+// Swizzles several Cocoa functions that are used to directly get mouse state,
+// so that they will return the current simulated mouse position and pressed
+// mouse buttons.
+class MockNSEventClassMethods {
+ public:
+  static void Init() {
+    static MockNSEventClassMethods* swizzler = nullptr;
+    if (!swizzler) {
+      swizzler = new MockNSEventClassMethods();
+    }
+  }
+
+ private:
+  MockNSEventClassMethods()
+      : mouse_location_swizzler_([NSEvent class],
+                                 [FakeNSEventTestingDonor class],
+                                 @selector(mouseLocation)),
+        pressed_mouse_buttons_swizzler_([NSEvent class],
+                                        [FakeNSEventTestingDonor class],
+                                        @selector(pressedMouseButtons)) {}
+
+  base::mac::ScopedObjCClassSwizzler mouse_location_swizzler_;
+  base::mac::ScopedObjCClassSwizzler pressed_mouse_buttons_swizzler_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockNSEventClassMethods);
+};
+
+}  // namespace
+
 namespace ui_controls {
 
 void EnableUIControls() {
   g_ui_controls_enabled = true;
+  MockNSEventClassMethods::Init();
 }
 
 bool IsUIControlsEnabled() {
@@ -239,9 +300,7 @@
 // platforms.  E.g. (0,0) is upper-left.
 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
   CHECK(g_ui_controls_enabled);
-  CGFloat screenHeight =
-    [[[NSScreen screens] firstObject] frame].size.height;
-  g_mouse_location = NSMakePoint(x, screenHeight - y);  // flip!
+  g_mouse_location = gfx::ScreenPointToNSPoint(gfx::Point(x, y));  // flip!
 
   NSWindow* window = WindowAtCurrentMouseLocation();
 
@@ -250,16 +309,25 @@
     pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow);
   NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
 
+  NSEventType event_type = NSMouseMoved;
+  if (g_mouse_button_down[LEFT]) {
+    event_type = NSLeftMouseDragged;
+  } else if (g_mouse_button_down[RIGHT]) {
+    event_type = NSRightMouseDragged;
+  } else if (g_mouse_button_down[MIDDLE]) {
+    event_type = NSOtherMouseDragged;
+  }
+
   NSEvent* event =
-      [NSEvent mouseEventWithType:NSMouseMoved
+      [NSEvent mouseEventWithType:event_type
                          location:pointInWindow
                     modifierFlags:0
                         timestamp:timestamp
                      windowNumber:[window windowNumber]
                           context:nil
                       eventNumber:0
-                       clickCount:0
-                         pressure:0.0];
+                       clickCount:event_type == NSMouseMoved ? 0 : 1
+                         pressure:event_type == NSMouseMoved ? 0.0 : 1.0];
   [[NSApplication sharedApplication] postEvent:event atStart:NO];
 
   if (!task.is_null()) {
@@ -284,35 +352,38 @@
     return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) &&
             SendMouseEventsNotifyWhenDone(type, UP, task));
   }
-  NSEventType etype = NSLeftMouseDown;
+  NSEventType event_type = NSLeftMouseDown;
   if (type == LEFT) {
     if (state == UP) {
-      etype = NSLeftMouseUp;
+      event_type = NSLeftMouseUp;
     } else {
-      etype = NSLeftMouseDown;
+      event_type = NSLeftMouseDown;
     }
   } else if (type == MIDDLE) {
     if (state == UP) {
-      etype = NSOtherMouseUp;
+      event_type = NSOtherMouseUp;
     } else {
-      etype = NSOtherMouseDown;
+      event_type = NSOtherMouseDown;
     }
   } else if (type == RIGHT) {
     if (state == UP) {
-      etype = NSRightMouseUp;
+      event_type = NSRightMouseUp;
     } else {
-      etype = NSRightMouseDown;
+      event_type = NSRightMouseDown;
     }
   } else {
+    NOTREACHED();
     return false;
   }
+  g_mouse_button_down[type] = state == DOWN;
+
   NSWindow* window = WindowAtCurrentMouseLocation();
   NSPoint pointInWindow = g_mouse_location;
   if (window)
     pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow);
 
   NSEvent* event =
-      [NSEvent mouseEventWithType:etype
+      [NSEvent mouseEventWithType:event_type
                          location:pointInWindow
                     modifierFlags:0
                         timestamp:TimeIntervalSinceSystemStartup()
@@ -320,7 +391,7 @@
                           context:nil
                       eventNumber:0
                        clickCount:1
-                         pressure:(state == DOWN ? 1.0 : 0.0 )];
+                         pressure:state == DOWN ? 1.0 : 0.0];
   [[NSApplication sharedApplication] postEvent:event atStart:NO];
 
   if (!task.is_null()) {
diff --git a/ui/chromeos/resources/default_100_percent/arc/dual-icon-badge.png b/ui/chromeos/resources/default_100_percent/arc/dual-icon-badge.png
new file mode 100644
index 0000000..068f964
--- /dev/null
+++ b/ui/chromeos/resources/default_100_percent/arc/dual-icon-badge.png
Binary files differ
diff --git a/ui/chromeos/resources/default_200_percent/arc/dual-icon-badge.png b/ui/chromeos/resources/default_200_percent/arc/dual-icon-badge.png
new file mode 100644
index 0000000..419e4e3
--- /dev/null
+++ b/ui/chromeos/resources/default_200_percent/arc/dual-icon-badge.png
Binary files differ
diff --git a/ui/chromeos/resources/ui_chromeos_resources.grd b/ui/chromeos/resources/ui_chromeos_resources.grd
index adf6709b..5eaa36a 100644
--- a/ui/chromeos/resources/ui_chromeos_resources.grd
+++ b/ui/chromeos/resources/ui_chromeos_resources.grd
@@ -49,6 +49,9 @@
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NOTIFICATION_DATASAVER" file="network/notification_datasaver.png" />
       <structure type="chrome_scaled_image" name="IDR_AURA_UBER_TRAY_NOTIFICATION_LTE" file="network/notification_lte.png" />
 
+      <!-- Badge for Chrome Apps if Arc is enabled. -->
+      <structure type="chrome_scaled_image" name="IDR_ARC_DUAL_ICON_BADGE" file="arc/dual-icon-badge.png" />
+
       <!-- Default user profile images. -->
       <structure type="chrome_scaled_image" name="IDR_LOGIN_DEFAULT_USER" file="default_user_images/avatar_beaker.png" />
       <structure type="chrome_scaled_image" name="IDR_LOGIN_DEFAULT_USER_1" file="default_user_images/avatar_bee.png" />
diff --git a/ui/compositor/test/in_process_context_factory.cc b/ui/compositor/test/in_process_context_factory.cc
index ff160e90..e68752f8 100644
--- a/ui/compositor/test/in_process_context_factory.cc
+++ b/ui/compositor/test/in_process_context_factory.cc
@@ -14,7 +14,11 @@
 #include "cc/output/compositor_frame.h"
 #include "cc/output/context_provider.h"
 #include "cc/output/output_surface_client.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/scheduler/delay_based_time_source.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/surface_display_output_surface.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "cc/test/pixel_test_output_surface.h"
@@ -46,11 +50,11 @@
 class DirectOutputSurface : public cc::OutputSurface {
  public:
   DirectOutputSurface(
-      const scoped_refptr<cc::ContextProvider>& context_provider,
-      const scoped_refptr<cc::ContextProvider>& worker_context_provider,
-      std::unique_ptr<cc::BeginFrameSource> begin_frame_source)
-      : cc::OutputSurface(context_provider, worker_context_provider, nullptr),
-        begin_frame_source_(std::move(begin_frame_source)),
+      scoped_refptr<cc::ContextProvider> context_provider,
+      scoped_refptr<cc::ContextProvider> worker_context_provider)
+      : cc::OutputSurface(std::move(context_provider),
+                          std::move(worker_context_provider),
+                          nullptr),
         weak_ptr_factory_(this) {}
 
   ~DirectOutputSurface() override {}
@@ -59,8 +63,6 @@
   bool BindToClient(cc::OutputSurfaceClient* client) override {
     if (!OutputSurface::BindToClient(client))
       return false;
-
-    client->SetBeginFrameSource(begin_frame_source_.get());
     return true;
   }
   void SwapBuffers(cc::CompositorFrame* frame) override {
@@ -87,8 +89,6 @@
   }
 
  private:
-  std::unique_ptr<cc::BeginFrameSource> begin_frame_source_;
-
   base::WeakPtrFactory<DirectOutputSurface> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(DirectOutputSurface);
@@ -150,36 +150,38 @@
           "UICompositor");
 
   std::unique_ptr<cc::OutputSurface> display_output_surface;
-  std::unique_ptr<cc::DelayBasedBeginFrameSource> begin_frame_source(
-      new cc::DelayBasedBeginFrameSource(
-          base::MakeUnique<cc::DelayBasedTimeSource>(
-              compositor->task_runner().get())));
-
   if (use_test_surface_) {
     bool flipped_output_surface = false;
     display_output_surface = base::WrapUnique(new cc::PixelTestOutputSurface(
         context_provider, shared_worker_context_provider_,
-        flipped_output_surface, std::move(begin_frame_source)));
+        flipped_output_surface));
   } else {
     display_output_surface = base::WrapUnique(new DirectOutputSurface(
-        context_provider, shared_worker_context_provider_,
-        std::move(begin_frame_source)));
+        context_provider, shared_worker_context_provider_));
   }
 
   if (surface_manager_) {
-    std::unique_ptr<cc::Display> display(new cc::Display(
+    std::unique_ptr<cc::DelayBasedBeginFrameSource> begin_frame_source(
+        new cc::DelayBasedBeginFrameSource(
+            base::MakeUnique<cc::DelayBasedTimeSource>(
+                compositor->task_runner().get())));
+    std::unique_ptr<cc::DisplayScheduler> scheduler(new cc::DisplayScheduler(
+        begin_frame_source.get(), compositor->task_runner().get(),
+        display_output_surface->capabilities().max_frames_pending));
+    per_compositor_data_[compositor.get()] = base::MakeUnique<cc::Display>(
         surface_manager_, GetSharedBitmapManager(), GetGpuMemoryBufferManager(),
         compositor->GetRendererSettings(),
         compositor->surface_id_allocator()->id_namespace(),
-        compositor->task_runner().get(), std::move(display_output_surface)));
+        std::move(begin_frame_source), std::move(display_output_surface),
+        std::move(scheduler), base::MakeUnique<cc::TextureMailboxDeleter>(
+                                  compositor->task_runner().get()));
+
+    auto* display = per_compositor_data_[compositor.get()].get();
     std::unique_ptr<cc::SurfaceDisplayOutputSurface> surface_output_surface(
         new cc::SurfaceDisplayOutputSurface(
-            surface_manager_, compositor->surface_id_allocator(), display.get(),
+            surface_manager_, compositor->surface_id_allocator(), display,
             context_provider, shared_worker_context_provider_));
-
     compositor->SetOutputSurface(std::move(surface_output_surface));
-
-    per_compositor_data_[compositor.get()] = std::move(display);
   } else {
     compositor->SetOutputSurface(std::move(display_output_surface));
   }
diff --git a/ui/gfx/vector_icons/location_bar_https_invalid.icon b/ui/gfx/vector_icons/location_bar_https_invalid.icon
index 7396aec..880493c 100644
--- a/ui/gfx/vector_icons/location_bar_https_invalid.icon
+++ b/ui/gfx/vector_icons/location_bar_https_invalid.icon
@@ -3,10 +3,10 @@
 // found in the LICENSE file.
 
 CANVAS_DIMENSIONS, 32,
-MOVE_TO, 4, 26,
+MOVE_TO, 4, 27,
 R_H_LINE_TO, 25,
-LINE_TO, 16.5f, 4,
-LINE_TO, 4, 26,
+LINE_TO, 16.5f, 5,
+LINE_TO, 4, 27,
 CLOSE,
 R_MOVE_TO, 14, -3,
 R_H_LINE_TO, -3,
diff --git a/ui/gfx/vector_icons/location_bar_https_valid.icon b/ui/gfx/vector_icons/location_bar_https_valid.icon
index 3da8b0d3..e374e83 100644
--- a/ui/gfx/vector_icons/location_bar_https_valid.icon
+++ b/ui/gfx/vector_icons/location_bar_https_valid.icon
@@ -3,23 +3,23 @@
 // found in the LICENSE file.
 
 CANVAS_DIMENSIONS, 32,
-MOVE_TO, 21, 12,
+MOVE_TO, 21, 13,
 R_V_LINE_TO, -2,
 R_CUBIC_TO, 0, -2.76f, -2.24f, -5, -5, -5,
 R_CUBIC_TO, -2.76f, 0.02f, -5, 2.24f, -5, 5,
 R_V_LINE_TO, 2,
 R_H_LINE_TO, -1,
 R_CUBIC_TO, -1.1f, 0, -2, 0.9f, -2, 1.99f,
-V_LINE_TO, 24,
+V_LINE_TO, 25,
 R_CUBIC_TO, 0, 1.1f, 0.9f, 2, 2, 2,
 R_H_LINE_TO, 12,
 R_CUBIC_TO, 1.1f, 0, 2, -0.9f, 2, -2,
-V_LINE_TO, 14,
+V_LINE_TO, 15,
 R_CUBIC_TO, 0, -1.05f, -0.9f, -2, -2, -2,
 R_H_LINE_TO, -1,
 CLOSE,
 R_MOVE_TO, -8, 0.02f,
-V_LINE_TO, 10,
+V_LINE_TO, 11,
 R_CUBIC_TO, 0, -1.66f, 1.34f, -3, 3, -3,
 R_CUBIC_TO, 1.66f, 0, 3, 1.34f, 3, 3,
 R_V_LINE_TO, 2.02f,
diff --git a/ui/native_theme/common_theme.cc b/ui/native_theme/common_theme.cc
index d7a29ed..f2a21c5 100644
--- a/ui/native_theme/common_theme.cc
+++ b/ui/native_theme/common_theme.cc
@@ -21,28 +21,22 @@
 
 SkColor GetAuraColor(NativeTheme::ColorId color_id,
                      const NativeTheme* base_theme) {
-  // Shared colors.
-  static const SkColor kTextfieldDefaultBackground = SK_ColorWHITE;
-  static const SkColor kTextfieldSelectionBackgroundFocused =
-      SkColorSetARGB(0x54, 0x60, 0xA8, 0xEB);
-
   // MD colors.
   if (ui::MaterialDesignController::IsModeMaterial()) {
     // Dialogs:
     static const SkColor kDialogBackgroundColorMd = SK_ColorWHITE;
+    // Buttons:
+    static const SkColor kButtonEnabledColorMd = gfx::kChromeIconGrey;
     // MenuItem:
     static const SkColor kMenuHighlightBackgroundColorMd =
         SkColorSetARGB(0x14, 0x00, 0x00, 0x00);
     static const SkColor kSelectedMenuItemForegroundColorMd = SK_ColorBLACK;
     // Link:
-    static const SkColor kLinkDisabledColorMd = SK_ColorBLACK;
     static const SkColor kLinkEnabledColorMd = gfx::kGoogleBlue700;
     // Results tables:
     static const SkColor kResultsTableTextMd = SK_ColorBLACK;
     static const SkColor kResultsTableDimmedTextMd =
         SkColorSetRGB(0x64, 0x64, 0x64);
-    static const SkColor kPositiveTextColorMd = SkColorSetRGB(0x0b, 0x80, 0x43);
-    static const SkColor kNegativeTextColorMd = SkColorSetRGB(0xc5, 0x39, 0x29);
 
     switch (color_id) {
       // Dialogs
@@ -50,14 +44,17 @@
       case NativeTheme::kColorId_BubbleBackground:
         return kDialogBackgroundColorMd;
 
+      // Buttons
+      case NativeTheme::kColorId_ButtonEnabledColor:
+      case NativeTheme::kColorId_ButtonHoverColor:
+        return kButtonEnabledColorMd;
+
       // MenuItem
       case NativeTheme::kColorId_FocusedMenuItemBackgroundColor:
         return kMenuHighlightBackgroundColorMd;
       case NativeTheme::kColorId_SelectedMenuItemForegroundColor:
         return kSelectedMenuItemForegroundColorMd;
       // Link
-      case NativeTheme::kColorId_LinkDisabled:
-        return kLinkDisabledColorMd;
       case NativeTheme::kColorId_LinkEnabled:
       case NativeTheme::kColorId_LinkPressed:
         // Normal and pressed share a color.
@@ -81,9 +78,6 @@
       case NativeTheme::kColorId_ResultsTableNormalText:
       case NativeTheme::kColorId_ResultsTableHoveredText:
       case NativeTheme::kColorId_ResultsTableSelectedText:
-      case NativeTheme::kColorId_ResultsTableNormalHeadline:
-      case NativeTheme::kColorId_ResultsTableHoveredHeadline:
-      case NativeTheme::kColorId_ResultsTableSelectedHeadline:
         return kResultsTableTextMd;
       case NativeTheme::kColorId_ResultsTableNormalDimmedText:
       case NativeTheme::kColorId_ResultsTableHoveredDimmedText:
@@ -93,14 +87,6 @@
       case NativeTheme::kColorId_ResultsTableHoveredUrl:
       case NativeTheme::kColorId_ResultsTableSelectedUrl:
         return base_theme->GetSystemColor(NativeTheme::kColorId_LinkEnabled);
-      case NativeTheme::kColorId_ResultsTablePositiveText:
-      case NativeTheme::kColorId_ResultsTablePositiveHoveredText:
-      case NativeTheme::kColorId_ResultsTablePositiveSelectedText:
-        return kPositiveTextColorMd;
-      case NativeTheme::kColorId_ResultsTableNegativeText:
-      case NativeTheme::kColorId_ResultsTableNegativeHoveredText:
-      case NativeTheme::kColorId_ResultsTableNegativeSelectedText:
-        return kNegativeTextColorMd;
 
       default:
         break;
@@ -155,8 +141,11 @@
   static const SkColor kLinkPressedColor = SK_ColorRED;
   // Textfield:
   static const SkColor kTextfieldDefaultColor = SK_ColorBLACK;
+  static const SkColor kTextfieldDefaultBackground = SK_ColorWHITE;
   static const SkColor kTextfieldReadOnlyColor = SK_ColorDKGRAY;
   static const SkColor kTextfieldReadOnlyBackground = SK_ColorWHITE;
+  static const SkColor kTextfieldSelectionBackgroundFocused =
+      SkColorSetARGB(0x54, 0x60, 0xA8, 0xEB);
   static const SkColor kTextfieldSelectionColor = color_utils::AlphaBlend(
       SK_ColorBLACK, kTextfieldSelectionBackgroundFocused, 0xdd);
   // Tooltip
@@ -370,13 +359,10 @@
     case NativeTheme::kColorId_ResultsTableSelectedText:
       return kResultsTableSelectedText;
     case NativeTheme::kColorId_ResultsTableNormalDimmedText:
-    case NativeTheme::kColorId_ResultsTableNormalHeadline:
       return kResultsTableNormalDimmedText;
     case NativeTheme::kColorId_ResultsTableHoveredDimmedText:
-    case NativeTheme::kColorId_ResultsTableHoveredHeadline:
       return kResultsTableHoveredDimmedText;
     case NativeTheme::kColorId_ResultsTableSelectedDimmedText:
-    case NativeTheme::kColorId_ResultsTableSelectedHeadline:
       return kResultsTableSelectedDimmedText;
     case NativeTheme::kColorId_ResultsTableNormalUrl:
       return kResultsTableNormalUrl;
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 917ed95..3b78de9e 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -324,9 +324,6 @@
     kColorId_ResultsTableNormalDimmedText,
     kColorId_ResultsTableHoveredDimmedText,
     kColorId_ResultsTableSelectedDimmedText,
-    kColorId_ResultsTableNormalHeadline,
-    kColorId_ResultsTableHoveredHeadline,
-    kColorId_ResultsTableSelectedHeadline,
     kColorId_ResultsTableNormalUrl,
     kColorId_ResultsTableHoveredUrl,
     kColorId_ResultsTableSelectedUrl,
diff --git a/ui/native_theme/native_theme_dark_aura.cc b/ui/native_theme/native_theme_dark_aura.cc
index 4c642622..f8bcef452 100644
--- a/ui/native_theme/native_theme_dark_aura.cc
+++ b/ui/native_theme/native_theme_dark_aura.cc
@@ -57,9 +57,6 @@
     case kColorId_ResultsTableNormalText:
     case kColorId_ResultsTableHoveredText:
     case kColorId_ResultsTableSelectedText:
-    case kColorId_ResultsTableNormalHeadline:
-    case kColorId_ResultsTableHoveredHeadline:
-    case kColorId_ResultsTableSelectedHeadline:
       return kResultsTableText;
     case kColorId_ResultsTableNormalDimmedText:
     case kColorId_ResultsTableHoveredDimmedText:
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index eb7b82f..69954dd 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -465,8 +465,26 @@
 }
 
 SkColor NativeThemeWin::GetSystemColor(ColorId color_id) const {
+  const bool md = ui::MaterialDesignController::IsModeMaterial();
+  if (!md) {
+    // Link:
+    const SkColor kLinkPressedColor = SkColorSetRGB(200, 0, 0);
+
+    switch (color_id) {
+      // Link
+      case kColorId_LinkDisabled:
+        return system_colors_[COLOR_WINDOWTEXT];
+      case kColorId_LinkEnabled:
+        return system_colors_[COLOR_HOTLIGHT];
+      case kColorId_LinkPressed:
+        return kLinkPressedColor;
+
+      default:
+        break;
+    }
+  }
+
   // TODO: Obtain the correct colors using GetSysColor.
-  const SkColor kUrlTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
   // Dialogs:
   const SkColor kDialogBackgroundColor = SkColorSetRGB(251, 251, 251);
   // FocusableBorder:
@@ -480,11 +498,13 @@
   // MenuItem:
   const SkColor kMenuSchemeHighlightBackgroundColorInvert =
       SkColorSetRGB(0x30, 0x30, 0x30);
-  // Link:
-  const SkColor kLinkPressedColor = SkColorSetRGB(200, 0, 0);
   // Table:
   const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
   const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29);
+  // Results Tables:
+  const SkColor kResultsTableUrlColor =
+      md ? gfx::kGoogleBlue700 : SkColorSetRGB(0x0b, 0x80, 0x43);
+  const SkColor kResultsTableSelectedUrlColor = SK_ColorWHITE;
 
   switch (color_id) {
     // Windows
@@ -522,20 +542,6 @@
     case kColorId_LabelBackgroundColor:
       return system_colors_[COLOR_WINDOW];
 
-    // Link
-    case kColorId_LinkDisabled:
-      if (ui::MaterialDesignController::IsModeMaterial())
-        break;
-      return system_colors_[COLOR_WINDOWTEXT];
-    case kColorId_LinkEnabled:
-      if (ui::MaterialDesignController::IsModeMaterial())
-        break;
-      return system_colors_[COLOR_HOTLIGHT];
-    case kColorId_LinkPressed:
-      if (ui::MaterialDesignController::IsModeMaterial())
-        break;
-      return kLinkPressedColor;
-
     // Textfield
     case kColorId_TextfieldDefaultColor:
       return system_colors_[COLOR_WINDOWTEXT];
@@ -618,15 +624,16 @@
       return color_utils::AlphaBlend(system_colors_[COLOR_HIGHLIGHTTEXT],
                                      system_colors_[COLOR_HIGHLIGHT], 0x80);
     case kColorId_ResultsTableNormalUrl:
-      return color_utils::GetReadableColor(kUrlTextColor,
-                                           system_colors_[COLOR_WINDOW]);
+      return color_utils::GetReadableColor(kResultsTableUrlColor,
+                                            system_colors_[COLOR_WINDOW]);
     case kColorId_ResultsTableHoveredUrl:
-      return color_utils::GetReadableColor(
-          kUrlTextColor,
+      return color_utils::PickContrastingColor(
+          kResultsTableUrlColor, kResultsTableSelectedUrlColor,
           GetSystemColor(kColorId_ResultsTableHoveredBackground));
     case kColorId_ResultsTableSelectedUrl:
-      return color_utils::GetReadableColor(kUrlTextColor,
-                                           system_colors_[COLOR_HIGHLIGHT]);
+      return color_utils::PickContrastingColor(
+          kResultsTableUrlColor, kResultsTableSelectedUrlColor,
+          system_colors_[COLOR_HIGHLIGHT]);
     case kColorId_ResultsTablePositiveText:
       return color_utils::GetReadableColor(kPositiveTextColor,
                                            system_colors_[COLOR_WINDOW]);
diff --git a/ui/ozone/public/ozone_platform.cc b/ui/ozone/public/ozone_platform.cc
index 51fd047..4242c988 100644
--- a/ui/ozone/public/ozone_platform.cc
+++ b/ui/ozone/public/ozone_platform.cc
@@ -34,11 +34,17 @@
 
 // static
 void OzonePlatform::InitializeForUI() {
+  const InitParams params;
+  OzonePlatform::InitializeForUI(params);
+}
+
+// static
+void OzonePlatform::InitializeForUI(const InitParams& args) {
   CreateInstance();
   if (g_platform_initialized_ui)
     return;
   g_platform_initialized_ui = true;
-  instance_->InitializeUI();
+  instance_->InitializeUI(args);
   // This is deliberately created after initializing so that the platform can
   // create its own version of DDM.
   DeviceDataManager::CreateInstance();
@@ -46,11 +52,17 @@
 
 // static
 void OzonePlatform::InitializeForGPU() {
+  const InitParams params;
+  OzonePlatform::InitializeForGPU(params);
+}
+
+// static
+void OzonePlatform::InitializeForGPU(const InitParams& args) {
   CreateInstance();
   if (g_platform_initialized_gpu)
     return;
   g_platform_initialized_gpu = true;
-  instance_->InitializeGPU();
+  instance_->InitializeGPU(args);
 }
 
 // static
@@ -78,4 +90,14 @@
 // static
 OzonePlatform* OzonePlatform::instance_;
 
+// Convenience methods to facilitate transitionning to new API.
+void OzonePlatform::InitializeUI(const InitParams& args) {
+  InitializeUI();
+}
+void OzonePlatform::InitializeGPU(const InitParams& args) {
+  InitializeGPU();
+}
+
+void OzonePlatform::AddInterfaces(shell::Connection* connection) {}
+
 }  // namespace ui
diff --git a/ui/ozone/public/ozone_platform.h b/ui/ozone/public/ozone_platform.h
index 95e5d5b..5757660 100644
--- a/ui/ozone/public/ozone_platform.h
+++ b/ui/ozone/public/ozone_platform.h
@@ -14,6 +14,11 @@
 class Rect;
 }
 
+namespace shell {
+class Connector;
+class Connection;
+}
+
 namespace ui {
 
 class CursorFactoryOzone;
@@ -46,13 +51,39 @@
   OzonePlatform();
   virtual ~OzonePlatform();
 
+  // Additional initalization params for the platform. Platforms must not retain
+  // a reference to this structure.
+  struct InitParams {
+    // Ozone may retain this pointer for later use. An Ozone platform embedder
+    // must set this parameter in order for the Ozone platform implementation to
+    // be able to use Mojo.
+    shell::Connector* connector = nullptr;
+
+    // Setting this to true indicates that the platform implementation should
+    // operate as a single process for platforms (i.e. drm) that are usually
+    // split between a main and gpu specific portion.
+    bool single_process = false;
+  };
+
   // Initializes the subsystems/resources necessary for the UI process (e.g.
-  // events, surface, etc.)
+  // events, etc.)
+  // TODO(rjkroege): Remove deprecated entry point (http://crbug.com/620934)
   static void InitializeForUI();
 
-  // Initializes the subsystems/resources necessary for the GPU process.
+  // Initializes the subsystems/resources necessary for the UI process (e.g.
+  // events) with additional properties to customize the ozone platform
+  // implementation. Ozone will not retain InitParams after returning from
+  // InitalizeForUI.
+  static void InitializeForUI(const InitParams& args);
+
+  // Initializes the subsystems/resources necessary for rendering (i.e. GPU).
+  // TODO(rjkroege): Remove deprecated entry point (http://crbug.com/620934)
   static void InitializeForGPU();
 
+  // Initializes the subsystems for rendering but with additional properties
+  // provided by |args| as with InitalizeForUI.
+  static void InitializeForGPU(const InitParams& args);
+
   static OzonePlatform* GetInstance();
 
   // Factory getters to override in subclasses. The returned objects will be
@@ -71,9 +102,20 @@
   virtual std::unique_ptr<ui::NativeDisplayDelegate>
   CreateNativeDisplayDelegate() = 0;
 
+  // Ozone platform implementations may also choose to expose mojo interfaces to
+  // internal functionality. Embedders wishing to take advantage of ozone mojo
+  // implementations must invoke AddInterfaces with a valid shell::Connection*
+  // pointer to export all Mojo interfaces defined within Ozone.
+  //
+  // A default do-nothing implementation is provided to permit platform
+  // implementations to opt out of implementing any Mojo interfaces.
+  virtual void AddInterfaces(shell::Connection* connection);
+
  private:
   virtual void InitializeUI() = 0;
   virtual void InitializeGPU() = 0;
+  virtual void InitializeUI(const InitParams& args);
+  virtual void InitializeGPU(const InitParams& args);
 
   static void CreateInstance();
 
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h
index 1b2607c..adbe281 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views/cocoa/bridged_native_widget.h
@@ -34,6 +34,7 @@
 }
 
 class CocoaMouseCapture;
+class CocoaWindowMoveLoop;
 class DragDropClientMac;
 class NativeWidgetMac;
 class View;
@@ -100,6 +101,12 @@
   void ReleaseCapture();
   bool HasCapture();
 
+  // Start moving the window, pinned to the mouse cursor, and monitor events.
+  // Return MOVE_LOOP_SUCCESSFUL on mouse up or MOVE_LOOP_CANCELED on premature
+  // termination via EndMoveLoop() or when window is destroyed during the drag.
+  Widget::MoveLoopResult RunMoveLoop(const gfx::Vector2d& drag_offset);
+  void EndMoveLoop();
+
   // See views::Widget.
   void SetNativeWindowProperty(const char* key, void* value);
   void* GetNativeWindowProperty(const char* key) const;
@@ -126,6 +133,10 @@
   // Called by the NSWindowDelegate when the size of the window changes.
   void OnSizeChanged();
 
+  // Called once by the NSWindowDelegate when the position of the window has
+  // changed.
+  void OnPositionChanged();
+
   // Called by the NSWindowDelegate when the visibility of the window may have
   // changed. For example, due to a (de)miniaturize operation, or the window
   // being reordered in (or out of) the screen list.
@@ -265,6 +276,7 @@
   base::scoped_nsobject<BridgedContentView> bridged_view_;
   std::unique_ptr<ui::InputMethod> input_method_;
   std::unique_ptr<CocoaMouseCapture> mouse_capture_;
+  std::unique_ptr<CocoaWindowMoveLoop> window_move_loop_;
   std::unique_ptr<TooltipManager> tooltip_manager_;
   std::unique_ptr<DragDropClientMac> drag_drop_client_;
   FocusManager* focus_manager_;  // Weak. Owned by our Widget.
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index 987b313..47373d0 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -26,6 +26,7 @@
 #import "ui/views/cocoa/bridged_content_view.h"
 #import "ui/views/cocoa/drag_drop_client_mac.h"
 #import "ui/views/cocoa/cocoa_mouse_capture.h"
+#import "ui/views/cocoa/cocoa_window_move_loop.h"
 #include "ui/views/cocoa/tooltip_manager_mac.h"
 #import "ui/views/cocoa/views_nswindow_delegate.h"
 #import "ui/views/cocoa/widget_owner_nswindow_adapter.h"
@@ -619,6 +620,39 @@
   return mouse_capture_ && mouse_capture_->IsActive();
 }
 
+Widget::MoveLoopResult BridgedNativeWidget::RunMoveLoop(
+      const gfx::Vector2d& drag_offset) {
+  DCHECK(!HasCapture());
+  DCHECK(!window_move_loop_);
+
+  // RunMoveLoop caller is responsible for updating the window to be under the
+  // mouse, but it does this using possibly outdated coordinate from the mouse
+  // event, and mouse is very likely moved beyound that point.
+
+  // Compensate for mouse drift by shifting the initial mouse position we pass
+  // to CocoaWindowMoveLoop, so as it handles incoming move events the window's
+  // top left corner will be |drag_offset| from the current mouse position.
+
+  const gfx::Rect frame = gfx::ScreenRectFromNSRect([window_ frame]);
+  const gfx::Point mouse_in_screen(frame.x() + drag_offset.x(),
+                                   frame.y() + drag_offset.y());
+  window_move_loop_.reset(new CocoaWindowMoveLoop(
+      this, gfx::ScreenPointToNSPoint(mouse_in_screen)));
+
+  return window_move_loop_->Run();
+
+  // |this| may be destroyed during the RunLoop, causing it to exit early.
+  // Even if that doesn't happen, CocoaWindowMoveLoop will clean itself up by
+  // calling EndMoveLoop(). So window_move_loop_ will always be null before the
+  // function returns. But don't DCHECK since |this| might not be valid.
+}
+
+void BridgedNativeWidget::EndMoveLoop() {
+  DCHECK(window_move_loop_);
+  window_move_loop_->End();
+  window_move_loop_.reset();
+}
+
 void BridgedNativeWidget::SetNativeWindowProperty(const char* name,
                                                   void* value) {
   NSString* key = [NSString stringWithUTF8String:name];
@@ -737,6 +771,10 @@
     [bridged_view_ updateWindowMask];
 }
 
+void BridgedNativeWidget::OnPositionChanged() {
+  native_widget_mac_->GetWidget()->OnNativeWidgetMove();
+}
+
 void BridgedNativeWidget::OnVisibilityChanged() {
   OnVisibilityChangedTo([window_ isVisible]);
 }
diff --git a/ui/views/cocoa/cocoa_window_move_loop.h b/ui/views/cocoa/cocoa_window_move_loop.h
new file mode 100644
index 0000000..e688884
--- /dev/null
+++ b/ui/views/cocoa/cocoa_window_move_loop.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 UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
+#define UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "ui/views/widget/widget.h"
+
+namespace views {
+class BridgedNativeWidget;
+
+// Used by views::BridgedNativeWidget when dragging detached tabs.
+class CocoaWindowMoveLoop {
+ public:
+  CocoaWindowMoveLoop(BridgedNativeWidget* owner,
+                      const NSPoint& initial_mouse_in_screen);
+  ~CocoaWindowMoveLoop();
+
+  // Initiates the drag until a mouse up event is observed, or End() is called.
+  Widget::MoveLoopResult Run();
+  void End();
+
+ private:
+  enum LoopExitReason {
+    ENDED_EXTERNALLY,
+    MOUSE_UP,
+    WINDOW_DESTROYED,
+  };
+
+  BridgedNativeWidget* owner_;  // Weak. Owns this.
+
+  // Initial mouse location at the time before the CocoaWindowMoveLoop is
+  // created.
+  NSPoint initial_mouse_in_screen_;
+
+  // Pointer to a stack variable holding the exit reason.
+  LoopExitReason* exit_reason_ref_ = nullptr;
+  base::Closure quit_closure_;
+
+  // WeakPtrFactory for event monitor safety.
+  base::WeakPtrFactory<CocoaWindowMoveLoop> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CocoaWindowMoveLoop);
+};
+
+}  // namespace views
+
+#endif  // UI_VIEWS_COCOA_COCOA_WINDOW_MOVE_LOOP_H_
diff --git a/ui/views/cocoa/cocoa_window_move_loop.mm b/ui/views/cocoa/cocoa_window_move_loop.mm
new file mode 100644
index 0000000..a306f9c
--- /dev/null
+++ b/ui/views/cocoa/cocoa_window_move_loop.mm
@@ -0,0 +1,127 @@
+// 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 "ui/views/cocoa/cocoa_window_move_loop.h"
+
+#include "base/run_loop.h"
+#include "ui/display/screen.h"
+#import "ui/gfx/mac/coordinate_conversion.h"
+#import "ui/views/cocoa/bridged_native_widget.h"
+
+// When event monitors process the events the full list of monitors is cached,
+// and if we unregister the event monitor that's at the end of the list while
+// processing the first monitor's handler -- the callback for the unregistered
+// monitor will still be called even though it's unregistered. This will result
+// in dereferencing an invalid pointer.
+//
+// WeakCocoaWindowMoveLoop is retained by the event monitor and stores weak
+// pointer for the CocoaWindowMoveLoop, so there will be no invalid memory
+// access.
+@interface WeakCocoaWindowMoveLoop : NSObject {
+ @private
+  base::WeakPtr<views::CocoaWindowMoveLoop> weak_;
+}
+@end
+
+@implementation WeakCocoaWindowMoveLoop
+- (id)initWithWeakPtr:(const base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
+  if ((self = [super init])) {
+    weak_ = weak;
+  }
+  return self;
+}
+
+- (base::WeakPtr<views::CocoaWindowMoveLoop>&)weak {
+  return weak_;
+}
+@end
+
+namespace views {
+
+CocoaWindowMoveLoop::CocoaWindowMoveLoop(
+    BridgedNativeWidget* owner,
+    const NSPoint& initial_mouse_in_screen)
+    : owner_(owner),
+      initial_mouse_in_screen_(initial_mouse_in_screen),
+      weak_factory_(this) {
+}
+
+CocoaWindowMoveLoop::~CocoaWindowMoveLoop() {
+  // Handle the pathological case, where |this| is destroyed while running.
+  if (exit_reason_ref_) {
+    *exit_reason_ref_ = WINDOW_DESTROYED;
+    quit_closure_.Run();
+  }
+
+  owner_ = nullptr;
+}
+
+Widget::MoveLoopResult CocoaWindowMoveLoop::Run() {
+  LoopExitReason exit_reason = ENDED_EXTERNALLY;
+  exit_reason_ref_ = &exit_reason;
+  NSWindow* window = owner_->ns_window();
+  const NSRect initial_frame = [window frame];
+
+  base::RunLoop run_loop;
+  quit_closure_ = run_loop.QuitClosure();
+
+  // Will be retained by the monitor handler block.
+  WeakCocoaWindowMoveLoop* weak_cocoa_window_move_loop =
+      [[[WeakCocoaWindowMoveLoop alloc]
+          initWithWeakPtr:weak_factory_.GetWeakPtr()] autorelease];
+
+  // Esc keypress is handled by EscapeTracker, which is installed by
+  // TabDragController.
+  NSEventMask mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
+  auto handler = ^NSEvent*(NSEvent* event) {
+    CocoaWindowMoveLoop* strong = [weak_cocoa_window_move_loop weak].get();
+    if (!strong || !strong->exit_reason_ref_) {
+      // By this point CocoaWindowMoveLoop was deleted while processing this
+      // same event, and this event monitor was not unregistered in time. See
+      // the WeakCocoaWindowMoveLoop comment above.
+      // Continue processing the event.
+      return event;
+    }
+
+    if ([event type] == NSLeftMouseDragged) {
+      const NSPoint mouse_in_screen = [NSEvent mouseLocation];
+
+      const NSRect ns_frame = NSOffsetRect(
+          initial_frame, mouse_in_screen.x - initial_mouse_in_screen_.x,
+          mouse_in_screen.y - initial_mouse_in_screen_.y);
+      [window setFrame:ns_frame display:NO animate:NO];
+
+      return event;
+    }
+
+    DCHECK_EQ([event type], NSLeftMouseUp);
+    *strong->exit_reason_ref_ = MOUSE_UP;
+    strong->quit_closure_.Run();
+    return event;  // Process the MouseUp.
+  };
+  id monitor =
+      [NSEvent addLocalMonitorForEventsMatchingMask:mask handler:handler];
+
+  run_loop.Run();
+  [NSEvent removeMonitor:monitor];
+
+  if (exit_reason != WINDOW_DESTROYED && exit_reason != ENDED_EXTERNALLY) {
+    exit_reason_ref_ = nullptr;  // Ensure End() doesn't replace the reason.
+    owner_->EndMoveLoop();       // Deletes |this|.
+  }
+
+  return exit_reason != MOUSE_UP ? Widget::MOVE_LOOP_CANCELED
+                                 : Widget::MOVE_LOOP_SUCCESSFUL;
+}
+
+void CocoaWindowMoveLoop::End() {
+  if (exit_reason_ref_) {
+    DCHECK_EQ(*exit_reason_ref_, ENDED_EXTERNALLY);
+    // Ensure the destructor doesn't replace the reason.
+    exit_reason_ref_ = nullptr;
+    quit_closure_.Run();
+  }
+}
+
+}  // namespace views
diff --git a/ui/views/cocoa/views_nswindow_delegate.mm b/ui/views/cocoa/views_nswindow_delegate.mm
index 75346a6a..e08ae56e 100644
--- a/ui/views/cocoa/views_nswindow_delegate.mm
+++ b/ui/views/cocoa/views_nswindow_delegate.mm
@@ -79,6 +79,13 @@
   parent_->OnSizeChanged();
 }
 
+- (void)windowDidMove:(NSNotification*)notification {
+  // Note: windowDidMove: is sent only once at the end of a window drag. There
+  // is also windowWillMove: sent at the start, also once. When the window is
+  // being moved by the WindowServer live updates are not provided.
+  parent_->OnPositionChanged();
+}
+
 - (void)windowDidBecomeKey:(NSNotification*)notification {
   parent_->OnWindowKeyStatusChangedTo(true);
 }
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h
index 8f907c1..3776402c 100644
--- a/ui/views/controls/button/label_button.h
+++ b/ui/views/controls/button/label_button.h
@@ -46,7 +46,7 @@
 
   // Gets or sets the text shown on the button.
   const base::string16& GetText() const;
-  virtual void SetText(const base::string16& text);
+  void SetText(const base::string16& text);
 
   // Sets the text color shown for the specified button |for_state| to |color|.
   void SetTextColor(ButtonState for_state, SkColor color);
diff --git a/ui/views/controls/button/md_text_button.cc b/ui/views/controls/button/md_text_button.cc
index 1cd874e..fd6822a 100644
--- a/ui/views/controls/button/md_text_button.cc
+++ b/ui/views/controls/button/md_text_button.cc
@@ -19,15 +19,14 @@
 namespace {
 
 // Inset between clickable region border and button contents (text).
-const int kHorizontalPadding = 12;
-const int kVerticalPadding = 6;
+const int kHorizontalPadding = 16;
 
 // Minimum size to reserve for the button contents.
 const int kMinWidth = 48;
 
 // The amount to enlarge the focus border in all directions relative to the
 // button.
-const int kFocusBorderOutset = -2;
+const int kFocusBorderOutset = -1;
 
 // The corner radius of the focus border roundrect.
 const int kFocusBorderCornerRadius = 3;
@@ -92,7 +91,7 @@
     const base::string16& text) {
   if (ui::MaterialDesignController::IsSecondaryUiMaterial()) {
     MdTextButton* md_button = MdTextButton::CreateMdButton(listener, text);
-    md_button->SetCallToAction(MdTextButton::STRONG_CALL_TO_ACTION);
+    md_button->SetCallToAction(true);
     return md_button;
   }
 
@@ -104,11 +103,6 @@
                                            const base::string16& text) {
   MdTextButton* button = new MdTextButton(listener);
   button->SetText(text);
-  // TODO(estade): can we get rid of the platform style border hoopla if
-  // we apply the MD treatment to all buttons, even GTK buttons?
-  button->SetBorder(
-      Border::CreateEmptyBorder(kVerticalPadding, kHorizontalPadding,
-                                kVerticalPadding, kHorizontalPadding));
   button->SetFocusForPlatform();
   return button;
 }
@@ -117,8 +111,8 @@
 void MdTextButton::PaintMdFocusRing(gfx::Canvas* canvas, views::View* view) {
   SkPaint paint;
   paint.setAntiAlias(true);
-  paint.setColor(view->GetNativeTheme()->GetSystemColor(
-      ui::NativeTheme::kColorId_CallToActionColor));
+  paint.setColor(SkColorSetA(view->GetNativeTheme()->GetSystemColor(
+      ui::NativeTheme::kColorId_CallToActionColor), 0x33));
   paint.setStyle(SkPaint::kStroke_Style);
   paint.setStrokeWidth(1);
   gfx::RectF rect(view->GetLocalBounds());
@@ -126,7 +120,7 @@
   canvas->DrawRoundRect(rect, kFocusBorderCornerRadius, paint);
 }
 
-void MdTextButton::SetCallToAction(CallToAction cta) {
+void MdTextButton::SetCallToAction(bool cta) {
   if (cta_ == cta)
     return;
 
@@ -165,23 +159,14 @@
   return false;
 }
 
-void MdTextButton::SetText(const base::string16& text) {
-  LabelButton::SetText(base::i18n::ToUpper(text));
-}
-
 void MdTextButton::UpdateStyleToIndicateDefaultStatus() {
-  // Update the call to action state to reflect defaultness. Don't change strong
-  // call to action to weak.
-  if (!is_default())
-    SetCallToAction(NO_CALL_TO_ACTION);
-  else if (cta_ == NO_CALL_TO_ACTION)
-    SetCallToAction(WEAK_CALL_TO_ACTION);
+  UpdateColorsFromNativeTheme();
 }
 
 MdTextButton::MdTextButton(ButtonListener* listener)
     : LabelButton(listener, base::string16()),
       focus_ring_(new MdFocusRing()),
-      cta_(NO_CALL_TO_ACTION) {
+      cta_(false) {
   SetHasInkDrop(true);
   set_has_ink_drop_action_on_click(true);
   SetHorizontalAlignment(gfx::ALIGN_CENTER);
@@ -194,39 +179,51 @@
   AddChildView(focus_ring_);
   focus_ring_->SetVisible(false);
   set_request_focus_on_press(false);
+
+  // Top and bottom padding depend on the font. Example: if font cap height is
+  // 9dp, use 8dp bottom padding and 7dp top padding to total 24dp.
+  const gfx::FontList& font = label()->font_list();
+  int text_height = font.GetCapHeight();
+  int even_text_height = text_height - (text_height % 2);
+  const int top_padding = even_text_height - (text_height - even_text_height);
+  const int bottom_padding = even_text_height;
+  DCHECK_EQ(3 * even_text_height, top_padding + text_height + bottom_padding);
+
+  const int inbuilt_top_padding = font.GetBaseline() - font.GetCapHeight();
+  const int inbuilt_bottom_padding =
+      font.GetHeight() - label()->font_list().GetBaseline();
+
+  // TODO(estade): can we get rid of the platform style border hoopla if
+  // we apply the MD treatment to all buttons, even GTK buttons?
+  SetBorder(Border::CreateEmptyBorder(
+      top_padding - inbuilt_top_padding, kHorizontalPadding,
+      bottom_padding - inbuilt_bottom_padding, kHorizontalPadding));
 }
 
 MdTextButton::~MdTextButton() {}
 
 void MdTextButton::UpdateColorsFromNativeTheme() {
-  ui::NativeTheme::ColorId fg_color_id = ui::NativeTheme::kColorId_NumColors;
-  switch (cta_) {
-    case NO_CALL_TO_ACTION:
-      // When there's no call to action, respect a color override if one has
-      // been set. For other call to action states, don't let individual buttons
-      // specify a color.
-      if (!explicitly_set_normal_color())
-        fg_color_id = ui::NativeTheme::kColorId_ButtonEnabledColor;
-      break;
-    case WEAK_CALL_TO_ACTION:
-      fg_color_id = ui::NativeTheme::kColorId_CallToActionColor;
-      break;
-    case STRONG_CALL_TO_ACTION:
-      fg_color_id = ui::NativeTheme::kColorId_TextOnCallToActionColor;
-      break;
-  }
+  ui::NativeTheme::ColorId fg_color_id =
+      cta_ ? ui::NativeTheme::kColorId_TextOnCallToActionColor
+           : ui::NativeTheme::kColorId_ButtonEnabledColor;
+
+  // When there's no call to action, respect a color override if one has
+  // been set. For call to action styling, don't let individual buttons
+  // specify a color.
   ui::NativeTheme* theme = GetNativeTheme();
-  if (fg_color_id != ui::NativeTheme::kColorId_NumColors)
+  if (cta_ || !explicitly_set_normal_color())
     SetEnabledTextColors(theme->GetSystemColor(fg_color_id));
 
-  set_background(
-      cta_ == STRONG_CALL_TO_ACTION
-          ? Background::CreateBackgroundPainter(
-                true, Painter::CreateSolidRoundRectPainter(
-                          theme->GetSystemColor(
-                              ui::NativeTheme::kColorId_CallToActionColor),
-                          kInkDropSmallCornerRadius))
-          : nullptr);
+  SkColor text_color = label()->enabled_color();
+  SkColor bg_color =
+      cta_ ? theme->GetSystemColor(ui::NativeTheme::kColorId_CallToActionColor)
+           : is_default()
+                 ? color_utils::BlendTowardOppositeLuma(text_color, 0xD8)
+                 : SK_ColorTRANSPARENT;
+  SkColor stroke_color = SkColorSetA(SK_ColorBLACK, 0x1A);
+  set_background(Background::CreateBackgroundPainter(
+      true, Painter::CreateRoundRectWith1PxBorderPainter(
+                bg_color, stroke_color, kInkDropSmallCornerRadius)));
 }
 
 }  // namespace views
diff --git a/ui/views/controls/button/md_text_button.h b/ui/views/controls/button/md_text_button.h
index 034f012..1932a40d 100644
--- a/ui/views/controls/button/md_text_button.h
+++ b/ui/views/controls/button/md_text_button.h
@@ -14,14 +14,6 @@
 // A button class that implements the Material Design text button spec.
 class VIEWS_EXPORT MdTextButton : public LabelButton {
  public:
-  // Describes the presentation of a button. A stronger call to action draws
-  // more attention.
-  enum CallToAction {
-    NO_CALL_TO_ACTION,  // Default.
-    WEAK_CALL_TO_ACTION,
-    STRONG_CALL_TO_ACTION,
-  };
-
   // Creates a normal STYLE_BUTTON LabelButton in pre-MD, or an MdTextButton
   // in MD mode.
   static LabelButton* CreateStandardButton(ButtonListener* listener,
@@ -38,7 +30,7 @@
   // Paint an MD-style focus ring on the given canvas at the given bounds.
   static void PaintMdFocusRing(gfx::Canvas* canvas, View* view);
 
-  void SetCallToAction(CallToAction cta);
+  void SetCallToAction(bool cta);
 
   // LabelButton:
   void Layout() override;
@@ -47,7 +39,6 @@
   void OnNativeThemeChanged(const ui::NativeTheme* theme) override;
   SkColor GetInkDropBaseColor() const override;
   bool ShouldShowInkDropForFocus() const override;
-  void SetText(const base::string16& text) override;
   void UpdateStyleToIndicateDefaultStatus() override;
 
  private:
@@ -62,7 +53,7 @@
   views::View* focus_ring_;
 
   // The call to action style for this button.
-  CallToAction cta_;
+  bool cta_;
 
   DISALLOW_COPY_AND_ASSIGN(MdTextButton);
 };
diff --git a/ui/views/examples/button_example.cc b/ui/views/examples/button_example.cc
index 9736f85..b3a2f13 100644
--- a/ui/views/examples/button_example.cc
+++ b/ui/views/examples/button_example.cc
@@ -62,12 +62,12 @@
   container->AddChildView(MdTextButton::CreateMdButton(
       nullptr, base::ASCIIToUTF16("Material design")));
   MdTextButton* md_button = MdTextButton::CreateMdButton(
-      nullptr, base::ASCIIToUTF16("Strong call to action"));
-  md_button->SetCallToAction(MdTextButton::STRONG_CALL_TO_ACTION);
+      nullptr, base::ASCIIToUTF16("Default"));
+  md_button->SetIsDefault(true);
   container->AddChildView(md_button);
   md_button = MdTextButton::CreateMdButton(
-      nullptr, base::ASCIIToUTF16("Weak call to action"));
-  md_button->SetCallToAction(MdTextButton::WEAK_CALL_TO_ACTION);
+      nullptr, base::ASCIIToUTF16("Call to action"));
+  md_button->SetCallToAction(true);
   container->AddChildView(md_button);
 
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
diff --git a/ui/views/painter.cc b/ui/views/painter.cc
index d48a7ef..c9cc6a64 100644
--- a/ui/views/painter.cc
+++ b/ui/views/painter.cc
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
+#include "third_party/skia/include/pathops/SkPathOps.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/insets.h"
@@ -21,6 +22,7 @@
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_operations.h"
 #include "ui/gfx/nine_image_painter.h"
+#include "ui/gfx/scoped_canvas.h"
 #include "ui/views/view.h"
 
 namespace views {
@@ -29,9 +31,11 @@
 
 // SolidRoundRectPainter -------------------------------------------------------
 
+// Creates a round rect painter with a 1 pixel border. The border paints on top
+// of the background.
 class SolidRoundRectPainter : public Painter {
  public:
-  SolidRoundRectPainter(SkColor color, float radius);
+  SolidRoundRectPainter(SkColor bg_color, SkColor stroke_color, float radius);
   ~SolidRoundRectPainter() override;
 
   // Painter:
@@ -39,14 +43,17 @@
   void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
 
  private:
-  const SkColor color_;
+  const SkColor bg_color_;
+  const SkColor stroke_color_;
   const float radius_;
 
   DISALLOW_COPY_AND_ASSIGN(SolidRoundRectPainter);
 };
 
-SolidRoundRectPainter::SolidRoundRectPainter(SkColor color, float radius)
-    : color_(color), radius_(radius) {}
+SolidRoundRectPainter::SolidRoundRectPainter(SkColor bg_color,
+                                             SkColor stroke_color,
+                                             float radius)
+    : bg_color_(bg_color), stroke_color_(stroke_color), radius_(radius) {}
 
 SolidRoundRectPainter::~SolidRoundRectPainter() {}
 
@@ -55,11 +62,24 @@
 }
 
 void SolidRoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
-  gfx::RectF rect((gfx::SizeF(size)));
+  gfx::ScopedCanvas scoped_canvas(canvas);
+  const float scale = canvas->UndoDeviceScaleFactor();
+
+  gfx::RectF border_rect_f((gfx::SizeF(size)));
+  border_rect_f.Scale(scale);
+  const SkScalar scaled_corner_radius = SkFloatToScalar(radius_ * scale);
+
   SkPaint paint;
   paint.setAntiAlias(true);
-  paint.setColor(color_);
-  canvas->DrawRoundRect(rect, radius_, paint);
+  paint.setStyle(SkPaint::kFill_Style);
+  paint.setColor(bg_color_);
+  canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, paint);
+
+  border_rect_f.Inset(gfx::InsetsF(0.5f));
+  paint.setStyle(SkPaint::kStroke_Style);
+  paint.setStrokeWidth(1);
+  paint.setColor(stroke_color_);
+  canvas->DrawRoundRect(border_rect_f, scaled_corner_radius, paint);
 }
 
 // DashedFocusPainter ----------------------------------------------------------
@@ -276,7 +296,14 @@
 
 // static
 Painter* Painter::CreateSolidRoundRectPainter(SkColor color, float radius) {
-  return new SolidRoundRectPainter(color, radius);
+  return new SolidRoundRectPainter(color, SK_ColorTRANSPARENT, radius);
+}
+
+// static
+Painter* Painter::CreateRoundRectWith1PxBorderPainter(SkColor bg_color,
+                                                      SkColor stroke_color,
+                                                      float radius) {
+  return new SolidRoundRectPainter(bg_color, stroke_color, radius);
 }
 
 // static
diff --git a/ui/views/painter.h b/ui/views/painter.h
index cffe1c1..e58ced9 100644
--- a/ui/views/painter.h
+++ b/ui/views/painter.h
@@ -51,6 +51,12 @@
   // corner radius.
   static Painter* CreateSolidRoundRectPainter(SkColor color, float radius);
 
+  // Creates a painter that draws a RoundRect with a solid color and a given
+  // corner radius, and also adds a 1px border (inset) in the given color.
+  static Painter* CreateRoundRectWith1PxBorderPainter(SkColor bg_color,
+                                                      SkColor stroke_color,
+                                                      float radius);
+
   // Creates a painter that draws a gradient between the two colors.
   static Painter* CreateHorizontalGradient(SkColor c1, SkColor c2);
   static Painter* CreateVerticalGradient(SkColor c1, SkColor c2);
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index bd69b63..c4bc8d4 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -62,6 +62,8 @@
       'cocoa/cocoa_mouse_capture.h',
       'cocoa/cocoa_mouse_capture.mm',
       'cocoa/cocoa_mouse_capture_delegate.h',
+      'cocoa/cocoa_window_move_loop.h',
+      'cocoa/cocoa_window_move_loop.mm',
       'cocoa/native_widget_mac_nswindow.h',
       'cocoa/native_widget_mac_nswindow.mm',
       'cocoa/tooltip_manager_mac.h',
diff --git a/ui/views/widget/native_widget_mac.mm b/ui/views/widget/native_widget_mac.mm
index 96580ce5..8050abe 100644
--- a/ui/views/widget/native_widget_mac.mm
+++ b/ui/views/widget/native_widget_mac.mm
@@ -551,12 +551,15 @@
     const gfx::Vector2d& drag_offset,
     Widget::MoveLoopSource source,
     Widget::MoveLoopEscapeBehavior escape_behavior) {
-  NOTIMPLEMENTED();
-  return Widget::MOVE_LOOP_CANCELED;
+  if (!bridge_)
+    return Widget::MOVE_LOOP_CANCELED;
+
+  return bridge_->RunMoveLoop(drag_offset);
 }
 
 void NativeWidgetMac::EndMoveLoop() {
-  NOTIMPLEMENTED();
+  if (bridge_)
+    bridge_->EndMoveLoop();
 }
 
 void NativeWidgetMac::SetVisibilityChangedAnimationsEnabled(bool value) {