diff --git a/DEPS b/DEPS
index 5d35fd00..3b01e1f 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '4ccd862d2940c47e7815c1309814e3de1c791e84',
+  'skia_revision': '9fa740365215931c8208fe57a55c7ebac1303d95',
   # 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': '66930adb48a5aff530971c6afcddd827e55bd5e6',
+  'v8_revision': 'e9a711fa15ac8a3654d8f7c794965cc1965699a0',
   # 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.
@@ -52,7 +52,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '20e005b2a1548cf16c627ba82144446bffd69493',
+  'angle_revision': '67f5ce42461d831cce30f737fa81919508c1368e',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'f6baf6b1d101a889d2cfc7cb925e726dbffb89db',
+  'pdfium_revision': '5eb58cd552c184998ed24634db4b2e6e770f39bd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
diff --git a/android_webview/native/aw_metrics_service_client_impl.cc b/android_webview/native/aw_metrics_service_client_impl.cc
index d3848cb..381fb98 100644
--- a/android_webview/native/aw_metrics_service_client_impl.cc
+++ b/android_webview/native/aw_metrics_service_client_impl.cc
@@ -147,8 +147,8 @@
 void AwMetricsServiceClientImpl::SetMetricsEnabled(bool enabled) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  // For now, UMA is only enabled on future versions.
-  if (base::android::BuildInfo::GetInstance()->sdk_int() <=
+  // For now, UMA is only enabled on Android N+.
+  if (base::android::BuildInfo::GetInstance()->sdk_int() <
       base::android::SDK_VERSION_NOUGAT) {
     return;
   }
diff --git a/ash/devtools/ash_devtools_unittest.cc b/ash/devtools/ash_devtools_unittest.cc
index f840134f..5ebb719c 100644
--- a/ash/devtools/ash_devtools_unittest.cc
+++ b/ash/devtools/ash_devtools_unittest.cc
@@ -5,6 +5,7 @@
 #include "ash/devtools/ash_devtools_css_agent.h"
 #include "ash/devtools/ash_devtools_dom_agent.h"
 #include "ash/root_window_controller.h"
+#include "ash/shell.h"
 #include "ash/shell_port.h"
 #include "ash/test/ash_test.h"
 #include "ash/wm/widget_finder.h"
@@ -134,14 +135,13 @@
   return -1;
 }
 
-WmWindow* GetHighlightingWindow(int root_window_index) {
-  WmWindow::Windows overlay_windows =
-      ShellPort::Get()
-          ->GetAllRootWindows()[root_window_index]
-          ->GetChildByShellWindowId(kShellWindowId_OverlayContainer)
-          ->GetChildren();
-  for (WmWindow* window : overlay_windows) {
-    if (window->aura_window()->GetName() == "HighlightingWidget")
+aura::Window* GetHighlightingWindow(int root_window_index) {
+  const aura::Window::Windows& overlay_windows =
+      Shell::GetAllRootWindows()[root_window_index]
+          ->GetChildById(kShellWindowId_OverlayContainer)
+          ->children();
+  for (aura::Window* window : overlay_windows) {
+    if (window->GetName() == "HighlightingWidget")
       return window;
   }
   NOTREACHED();
@@ -167,14 +167,13 @@
 }
 
 void ExpectHighlighted(const gfx::Rect& bounds, int root_window_index) {
-  WmWindow* highlighting_window = GetHighlightingWindow(root_window_index);
+  aura::Window* highlighting_window = GetHighlightingWindow(root_window_index);
   EXPECT_TRUE(highlighting_window->IsVisible());
   EXPECT_EQ(bounds, highlighting_window->GetBoundsInScreen());
-  EXPECT_EQ(kBackgroundColor,
-            GetInternalWidgetForWindow(highlighting_window->aura_window())
-                ->GetRootView()
-                ->background()
-                ->get_color());
+  EXPECT_EQ(kBackgroundColor, GetInternalWidgetForWindow(highlighting_window)
+                                  ->GetRootView()
+                                  ->background()
+                                  ->get_color());
 }
 
 }  // namespace
diff --git a/ash/laser/laser_pointer_view.cc b/ash/laser/laser_pointer_view.cc
index 956fbd9..5f5b757a 100644
--- a/ash/laser/laser_pointer_view.cc
+++ b/ash/laser/laser_pointer_view.cc
@@ -438,7 +438,8 @@
 
 void LaserPointerView::DidReceiveCompositorFrameAck(
     const cc::ReturnedResourceArray& resources) {
-  ReclaimResources(resources);
+  if (!resources.empty())
+    ReclaimResources(resources);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&LaserPointerView::OnDidDrawSurface,
diff --git a/ash/mus/app_launch_unittest.cc b/ash/mus/app_launch_unittest.cc
index 1ee880a4..e9a3e60 100644
--- a/ash/mus/app_launch_unittest.cc
+++ b/ash/mus/app_launch_unittest.cc
@@ -34,8 +34,8 @@
 };
 
 TEST_F(AppLaunchTest, TestQuickLaunch) {
-  connector()->Connect(mojom::kServiceName);
-  connector()->Connect(mash::quick_launch::mojom::kServiceName);
+  connector()->StartService(mojom::kServiceName);
+  connector()->StartService(mash::quick_launch::mojom::kServiceName);
 
   ui::mojom::WindowServerTestPtr test_interface;
   connector()->BindInterface(ui::mojom::kServiceName, &test_interface);
diff --git a/ash/mus/test/ash_test_impl_mus.cc b/ash/mus/test/ash_test_impl_mus.cc
index 32a33bd..92e5bb5 100644
--- a/ash/mus/test/ash_test_impl_mus.cc
+++ b/ash/mus/test/ash_test_impl_mus.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "services/ui/public/cpp/property_type_converters.h"
 #include "services/ui/public/interfaces/window_manager.mojom.h"
+#include "ui/aura/window.h"
 #include "ui/wm/core/window_util.h"
 
 namespace ash {
@@ -54,10 +55,10 @@
     const gfx::Rect& bounds_in_screen,
     ui::wm::WindowType type,
     int shell_window_id) {
-  WmWindow* window =
-      WmWindow::Get(wm_test_base_->CreateTestWindow(bounds_in_screen, type));
-  window->SetShellWindowId(shell_window_id);
-  return base::MakeUnique<WindowOwner>(window);
+  aura::Window* window =
+      wm_test_base_->CreateTestWindow(bounds_in_screen, type);
+  window->set_id(shell_window_id);
+  return base::MakeUnique<WindowOwner>(WmWindow::Get(window));
 }
 
 std::unique_ptr<WindowOwner> AshTestImplMus::CreateToplevelTestWindow(
diff --git a/ash/mus/top_level_window_factory.cc b/ash/mus/top_level_window_factory.cc
index 1c810c12..0a92119 100644
--- a/ash/mus/top_level_window_factory.cc
+++ b/ash/mus/top_level_window_factory.cc
@@ -131,9 +131,8 @@
   aura::Window* context = nullptr;
   aura::Window* container_window = nullptr;
   if (GetInitialContainerId(*properties, &container_id)) {
-    container_window = root_window_controller->GetWindow()
-                           ->GetChildByShellWindowId(container_id)
-                           ->aura_window();
+    container_window =
+        root_window_controller->GetRootWindow()->GetChildById(container_id);
   } else {
     context = root_window_controller->GetRootWindow();
   }
@@ -160,9 +159,8 @@
     // Pick a parent so display information is obtained. Will pick the real one
     // once transient parent found.
     aura::Window* unparented_control_container =
-        root_window_controller->GetWindow()
-            ->GetChildByShellWindowId(kShellWindowId_UnparentedControlContainer)
-            ->aura_window();
+        root_window_controller->GetRootWindow()->GetChildById(
+            kShellWindowId_UnparentedControlContainer);
     // DetachedTitleAreaRendererForClient is owned by the client.
     DetachedTitleAreaRendererForClient* renderer =
         new DetachedTitleAreaRendererForClient(unparented_control_container,
diff --git a/ash/mus/window_manager.cc b/ash/mus/window_manager.cc
index e8ca3eb..a8e3e2d5 100644
--- a/ash/mus/window_manager.cc
+++ b/ash/mus/window_manager.cc
@@ -245,11 +245,10 @@
   root_window_controller->Init(root_window_type);
   // TODO: To avoid lots of IPC AddActivationParent() should take an array.
   // http://crbug.com/682048.
-  WmWindow* root_window = root_window_controller->GetWindow();
+  aura::Window* root_window = root_window_controller->GetRootWindow();
   for (size_t i = 0; i < kNumActivatableShellWindowIds; ++i) {
     window_manager_client_->AddActivationParent(
-        root_window->GetChildByShellWindowId(kActivatableShellWindowIds[i])
-            ->aura_window());
+        root_window->GetChildById(kActivatableShellWindowIds[i]));
   }
   root_window_controllers_.insert(std::move(root_window_controller));
 }
diff --git a/ash/mus/window_manager_application.cc b/ash/mus/window_manager_application.cc
index d530f49d..abd098e 100644
--- a/ash/mus/window_manager_application.cc
+++ b/ash/mus/window_manager_application.cc
@@ -22,7 +22,6 @@
 #include "chromeos/system/fake_statistics_provider.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/dbus/bluez_dbus_manager.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/tracing/public/cpp/provider.h"
diff --git a/ash/mus/window_manager_unittest.cc b/ash/mus/window_manager_unittest.cc
index 84f23a4..3604021 100644
--- a/ash/mus/window_manager_unittest.cc
+++ b/ash/mus/window_manager_unittest.cc
@@ -87,7 +87,7 @@
 
   WindowTreeClientDelegate window_tree_delegate;
 
-  connector()->Connect(mojom::kServiceName);
+  connector()->StartService(mojom::kServiceName);
 
   // Connect to mus and create a new top level window. The request goes to
   // |ash|, but is async.
diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc
index 38906af6..fa9d48b 100644
--- a/ash/root_window_controller.cc
+++ b/ash/root_window_controller.cc
@@ -20,6 +20,7 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_settings.h"
+#include "ash/screen_util.h"
 #include "ash/session/session_controller.h"
 #include "ash/shelf/shelf_delegate.h"
 #include "ash/shelf/shelf_layout_manager.h"
@@ -164,18 +165,17 @@
 }
 
 // Reparents |window| to |new_parent|.
-// TODO(sky): This should take an aura::Window. http://crbug.com/671246.
-void ReparentWindow(WmWindow* window, WmWindow* new_parent) {
-  const gfx::Size src_size = window->GetParent()->GetBounds().size();
-  const gfx::Size dst_size = new_parent->GetBounds().size();
+void ReparentWindow(aura::Window* window, aura::Window* new_parent) {
+  const gfx::Size src_size = window->parent()->bounds().size();
+  const gfx::Size dst_size = new_parent->bounds().size();
   // Update the restore bounds to make it relative to the display.
-  wm::WindowState* state = window->GetWindowState();
+  wm::WindowState* state = wm::GetWindowState(window);
   gfx::Rect restore_bounds;
   const bool has_restore_bounds = state->HasRestoreBounds();
 
   const bool update_bounds = state->IsNormalOrSnapped() || state->IsMinimized();
   gfx::Rect work_area_in_new_parent =
-      wm::GetDisplayWorkAreaBoundsInParent(new_parent);
+      ScreenUtil::GetDisplayWorkAreaBoundsInParent(new_parent);
 
   gfx::Rect local_bounds;
   if (update_bounds) {
@@ -201,8 +201,7 @@
 }
 
 // Reparents the appropriate set of windows from |src| to |dst|.
-// TODO(sky): This should take an aura::Window. http://crbug.com/671246.
-void ReparentAllWindows(WmWindow* src, WmWindow* dst) {
+void ReparentAllWindows(aura::Window* src, aura::Window* dst) {
   // Set of windows to move.
   const int kContainerIdsToMove[] = {
       kShellWindowId_DefaultContainer,
@@ -228,15 +227,17 @@
   }
 
   for (int id : container_ids) {
-    WmWindow* src_container = src->GetChildByShellWindowId(id);
-    WmWindow* dst_container = dst->GetChildByShellWindowId(id);
-    while (!src_container->GetChildren().empty()) {
+    aura::Window* src_container = src->GetChildById(id);
+    aura::Window* dst_container = dst->GetChildById(id);
+    while (!src_container->children().empty()) {
       // Restart iteration from the source container windows each time as they
       // may change as a result of moving other windows.
-      WmWindow::Windows src_container_children = src_container->GetChildren();
-      WmWindow::Windows::const_iterator iter = src_container_children.begin();
+      const aura::Window::Windows& src_container_children =
+          src_container->children();
+      auto iter = src_container_children.begin();
       while (iter != src_container_children.end() &&
-             SystemModalContainerLayoutManager::IsModalBackground(*iter)) {
+             SystemModalContainerLayoutManager::IsModalBackground(
+                 WmWindow::Get(*iter))) {
         ++iter;
       }
       // If the entire window list is modal background windows then stop.
@@ -389,9 +390,8 @@
   WmWindow* modal_container = nullptr;
   if (window) {
     WmWindow* window_container = wm::GetContainerForWindow(window);
-    if (window_container &&
-        window_container->GetShellWindowId() >=
-            kShellWindowId_LockScreenContainer) {
+    if (window_container && window_container->aura_window()->id() >=
+                                kShellWindowId_LockScreenContainer) {
       modal_container = GetWmContainer(kShellWindowId_LockSystemModalContainer);
     } else {
       modal_container = GetWmContainer(kShellWindowId_SystemModalContainer);
@@ -618,7 +618,7 @@
 void RootWindowController::MoveWindowsTo(aura::Window* dst) {
   // Clear the workspace controller, so it doesn't incorrectly update the shelf.
   workspace_controller_.reset();
-  ReparentAllWindows(GetWindow(), WmWindow::Get(dst));
+  ReparentAllWindows(GetRootWindow(), dst);
 }
 
 void RootWindowController::UpdateShelfVisibility() {
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 22bc7b2..ad89d6d7 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -77,9 +77,8 @@
 
 // Returns true if the window is in the app list window container.
 bool IsAppListWindow(WmWindow* window) {
-  return window->GetParent() &&
-         window->GetParent()->GetShellWindowId() ==
-             kShellWindowId_AppListContainer;
+  return window->GetParent() && window->GetParent()->aura_window()->id() ==
+                                    kShellWindowId_AppListContainer;
 }
 
 }  // namespace
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc
index 2b3fdfa..abaf370 100644
--- a/ash/shelf/shelf_widget.cc
+++ b/ash/shelf/shelf_widget.cc
@@ -148,7 +148,7 @@
   params.delegate = delegate_view_;
   shelf_container->GetRootWindowController()
       ->ConfigureWidgetInitParamsForContainer(
-          this, shelf_container->GetShellWindowId(), &params);
+          this, shelf_container->aura_window()->id(), &params);
   Init(params);
 
   // The shelf should not take focus when initially shown.
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index ed36c787..af2627c 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -45,7 +45,7 @@
   params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
   status_container->GetRootWindowController()
       ->ConfigureWidgetInitParamsForContainer(
-          this, status_container->GetShellWindowId(), &params);
+          this, status_container->aura_window()->id(), &params);
   Init(params);
   set_focus_on_creation(false);
   SetContentsView(status_area_widget_delegate_);
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc
index d3b3f10a..6f6892a 100644
--- a/ash/system/tray/system_tray.cc
+++ b/ash/system/tray/system_tray.cc
@@ -180,7 +180,7 @@
 
     WmWindow* wm_gained_active = WmWindow::Get(gained_active);
     int container_id =
-        wm::GetContainerForWindow(wm_gained_active)->GetShellWindowId();
+        wm::GetContainerForWindow(wm_gained_active)->aura_window()->id();
 
     // Don't close the bubble if a popup notification is activated.
     if (container_id == kShellWindowId_StatusContainer)
diff --git a/ash/system/tray/tray_event_filter.cc b/ash/system/tray/tray_event_filter.cc
index f6d98c2..df42c1b 100644
--- a/ash/system/tray/tray_event_filter.cc
+++ b/ash/system/tray/tray_event_filter.cc
@@ -10,6 +10,7 @@
 #include "ash/system/tray/tray_bubble_wrapper.h"
 #include "ash/wm/container_finder.h"
 #include "ash/wm_window.h"
+#include "ui/aura/window.h"
 #include "ui/views/widget/widget.h"
 
 namespace ash {
@@ -47,7 +48,7 @@
                                           views::Widget* target) {
   if (target) {
     WmWindow* window = WmWindow::Get(target->GetNativeWindow());
-    int container_id = wm::GetContainerForWindow(window)->GetShellWindowId();
+    int container_id = wm::GetContainerForWindow(window)->aura_window()->id();
     // Don't process events that occurred inside an embedded menu, for example
     // the right-click menu in a popup notification.
     if (container_id == kShellWindowId_MenuContainer)
diff --git a/ash/wallpaper/wallpaper_controller_unittest.cc b/ash/wallpaper/wallpaper_controller_unittest.cc
index 90e7a6da..29591f6 100644
--- a/ash/wallpaper/wallpaper_controller_unittest.cc
+++ b/ash/wallpaper/wallpaper_controller_unittest.cc
@@ -13,7 +13,6 @@
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
-#include "ash/shell_port.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/test_session_controller_client.h"
 #include "ash/test/test_wallpaper_delegate.h"
@@ -27,6 +26,7 @@
 #include "base/threading/sequenced_worker_pool.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkColor.h"
+#include "ui/aura/window.h"
 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
 #include "ui/compositor/test/layer_animator_test_controller.h"
 #include "ui/gfx/canvas.h"
@@ -49,9 +49,9 @@
 
 // Returns number of child windows in a shell window container.
 int ChildCountForContainer(int container_id) {
-  WmWindow* root = ShellPort::Get()->GetPrimaryRootWindow();
-  WmWindow* container = root->GetChildByShellWindowId(container_id);
-  return static_cast<int>(container->GetChildren().size());
+  aura::Window* root = Shell::Get()->GetPrimaryRootWindow();
+  aura::Window* container = root->GetChildById(container_id);
+  return static_cast<int>(container->children().size());
 }
 
 // Steps a widget's layer animation until it is completed. Animations must be
@@ -120,7 +120,7 @@
     // Ash shell initialization creates wallpaper. Reset it so we can manually
     // control wallpaper creation and animation in our tests.
     RootWindowController* root_window_controller =
-        ShellPort::Get()->GetPrimaryRootWindow()->GetRootWindowController();
+        Shell::Get()->GetPrimaryRootWindowController();
     root_window_controller->SetWallpaperWidgetController(nullptr);
     root_window_controller->SetAnimatingWallpaperWidgetController(nullptr);
     controller_ = Shell::Get()->wallpaper_controller();
@@ -131,9 +131,8 @@
 
   WallpaperView* wallpaper_view() {
     WallpaperWidgetController* controller =
-        ShellPort::Get()
-            ->GetPrimaryRootWindow()
-            ->GetRootWindowController()
+        Shell::Get()
+            ->GetPrimaryRootWindowController()
             ->animating_wallpaper_widget_controller()
             ->GetController(false);
     EXPECT_TRUE(controller);
@@ -187,9 +186,8 @@
   // TODO(bshe): Don't require tests to run animations; it's slow.
   void RunDesktopControllerAnimation() {
     WallpaperWidgetController* controller =
-        ShellPort::Get()
-            ->GetPrimaryRootWindow()
-            ->GetRootWindowController()
+        Shell::Get()
+            ->GetPrimaryRootWindowController()
             ->animating_wallpaper_widget_controller()
             ->GetController(false);
     EXPECT_TRUE(controller);
@@ -266,7 +264,7 @@
 
   // The new wallpaper is ready to animate.
   RootWindowController* root_window_controller =
-      ShellPort::Get()->GetPrimaryRootWindow()->GetRootWindowController();
+      Shell::Get()->GetPrimaryRootWindowController();
   EXPECT_TRUE(root_window_controller->animating_wallpaper_widget_controller()
                   ->GetController(false));
   EXPECT_FALSE(root_window_controller->wallpaper_widget_controller());
@@ -302,7 +300,7 @@
   // In this state we have two wallpaper views stored in different properties.
   // Both are in the lock screen wallpaper container.
   RootWindowController* root_window_controller =
-      ShellPort::Get()->GetPrimaryRootWindow()->GetRootWindowController();
+      Shell::Get()->GetPrimaryRootWindowController();
   EXPECT_TRUE(root_window_controller->animating_wallpaper_widget_controller()
                   ->GetController(false));
   EXPECT_TRUE(root_window_controller->wallpaper_widget_controller());
@@ -343,7 +341,7 @@
   controller->CreateEmptyWallpaper();
 
   RootWindowController* root_window_controller =
-      ShellPort::Get()->GetPrimaryRootWindow()->GetRootWindowController();
+      Shell::Get()->GetPrimaryRootWindowController();
   WallpaperWidgetController* animating_controller =
       root_window_controller->animating_wallpaper_widget_controller()
           ->GetController(false);
diff --git a/ash/wm/always_on_top_controller.cc b/ash/wm/always_on_top_controller.cc
index de8b48c..c5eabb3 100644
--- a/ash/wm/always_on_top_controller.cc
+++ b/ash/wm/always_on_top_controller.cc
@@ -15,7 +15,7 @@
 
 AlwaysOnTopController::AlwaysOnTopController(WmWindow* viewport)
     : always_on_top_container_(viewport) {
-  DCHECK_NE(kShellWindowId_DefaultContainer, viewport->GetShellWindowId());
+  DCHECK_NE(kShellWindowId_DefaultContainer, viewport->aura_window()->id());
   always_on_top_container_->SetLayoutManager(
       base::MakeUnique<WorkspaceLayoutManager>(viewport));
   // Container should be empty.
diff --git a/ash/wm/container_finder.cc b/ash/wm/container_finder.cc
index 03f553db..1371655 100644
--- a/ash/wm/container_finder.cc
+++ b/ash/wm/container_finder.cc
@@ -46,7 +46,7 @@
   // Otherwise those that originate from LockScreen container and above are
   // placed in the screen lock modal container.
   int window_container_id =
-      window->GetTransientParent()->GetParent()->GetShellWindowId();
+      window->GetTransientParent()->GetParent()->aura_window()->id();
   if (window_container_id < kShellWindowId_LockScreenContainer)
     return root->GetChildByShellWindowId(kShellWindowId_SystemModalContainer);
   return root->GetChildByShellWindowId(kShellWindowId_LockSystemModalContainer);
@@ -64,7 +64,7 @@
 WmWindow* GetContainerForWindow(WmWindow* window) {
   WmWindow* parent = window->GetParent();
   // The first parent with an explicit shell window ID is the container.
-  while (parent && parent->GetShellWindowId() == kShellWindowId_Invalid)
+  while (parent && parent->aura_window()->id() == kShellWindowId_Invalid)
     parent = parent->GetParent();
   return parent;
 }
@@ -101,7 +101,7 @@
       return target_root->GetChildByShellWindowId(
           kShellWindowId_DragImageAndTooltipContainer);
     default:
-      NOTREACHED() << "Window " << window->GetShellWindowId()
+      NOTREACHED() << "Window " << window->aura_window()->id()
                    << " has unhandled type " << window->GetType();
       break;
   }
diff --git a/ash/wm/container_finder_unittest.cc b/ash/wm/container_finder_unittest.cc
index 459ac7d..44b8261 100644
--- a/ash/wm/container_finder_unittest.cc
+++ b/ash/wm/container_finder_unittest.cc
@@ -9,6 +9,7 @@
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/test/ash_test.h"
 #include "ash/wm_window.h"
+#include "ui/aura/window.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/widget/widget.h"
 
@@ -20,15 +21,15 @@
   // Create a normal widget in the default container.
   std::unique_ptr<views::Widget> widget =
       CreateTestWidget(gfx::Rect(1, 2, 3, 4));
-  WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
+  aura::Window* window = widget->GetNativeWindow();
 
   // The window itself is not a container.
-  EXPECT_EQ(kShellWindowId_Invalid, window->GetShellWindowId());
+  EXPECT_EQ(kShellWindowId_Invalid, window->id());
 
   // Container lookup finds the default container.
-  WmWindow* container = wm::GetContainerForWindow(window);
+  WmWindow* container = wm::GetContainerForWindow(WmWindow::Get(window));
   ASSERT_TRUE(container);
-  EXPECT_EQ(kShellWindowId_DefaultContainer, container->GetShellWindowId());
+  EXPECT_EQ(kShellWindowId_DefaultContainer, container->aura_window()->id());
 }
 
 }  // namespace ash
diff --git a/ash/wm/default_state.cc b/ash/wm/default_state.cc
index b8b835c..f7899c2 100644
--- a/ash/wm/default_state.cc
+++ b/ash/wm/default_state.cc
@@ -18,6 +18,7 @@
 #include "ash/wm/wm_event.h"
 #include "ash/wm/wm_screen_util.h"
 #include "ash/wm_window.h"
+#include "ui/aura/window.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
 
@@ -55,12 +56,14 @@
   if (!display_area.Intersects(restore_bounds)) {
     const display::Display& display =
         display::Screen::GetScreen()->GetDisplayMatching(restore_bounds);
-    WmWindow* new_root =
-        ShellPort::Get()->GetRootWindowForDisplayId(display.id());
-    if (new_root != window_state->window()->GetRootWindow()) {
-      WmWindow* new_container = new_root->GetChildByShellWindowId(
-          window_state->window()->GetParent()->GetShellWindowId());
-      new_container->AddChild(window_state->window());
+    RootWindowController* new_root_controller =
+        Shell::Get()->GetRootWindowControllerWithDisplayId(display.id());
+    if (new_root_controller->GetRootWindow() !=
+        window_state->window()->GetRootWindow()->aura_window()) {
+      aura::Window* new_container =
+          new_root_controller->GetRootWindow()->GetChildById(
+              window_state->window()->GetParent()->aura_window()->id());
+      new_container->AddChild(window_state->window()->aura_window());
     }
   }
 }
diff --git a/ash/wm/focus_rules.cc b/ash/wm/focus_rules.cc
index 4477e9d..6bb9484 100644
--- a/ash/wm/focus_rules.cc
+++ b/ash/wm/focus_rules.cc
@@ -20,7 +20,7 @@
 
   // The window must exist within a container that supports activation.
   // The window cannot be blocked by a modal transient.
-  return IsActivatableShellWindowId(window->GetParent()->GetShellWindowId());
+  return IsActivatableShellWindowId(window->GetParent()->aura_window()->id());
 }
 
 bool IsWindowConsideredActivatable(WmWindow* window) {
@@ -51,7 +51,7 @@
   if (!window->GetTargetVisibility())
     return false;
 
-  const int parent_shell_window_id = window->GetParent()->GetShellWindowId();
+  const int parent_shell_window_id = window->GetParent()->aura_window()->id();
   return parent_shell_window_id == kShellWindowId_DefaultContainer ||
          parent_shell_window_id == kShellWindowId_LockScreenContainer;
 }
diff --git a/ash/wm/maximize_mode/workspace_backdrop_delegate.cc b/ash/wm/maximize_mode/workspace_backdrop_delegate.cc
index fc812136..496cc7f1 100644
--- a/ash/wm/maximize_mode/workspace_backdrop_delegate.cc
+++ b/ash/wm/maximize_mode/workspace_backdrop_delegate.cc
@@ -35,9 +35,9 @@
   // To disallow the MRU list from picking this window up it should not be
   // activateable.
   params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
-  DCHECK_NE(kShellWindowId_Invalid, container_->GetShellWindowId());
+  DCHECK_NE(kShellWindowId_Invalid, container_->aura_window()->id());
   container_->GetRootWindowController()->ConfigureWidgetInitParamsForContainer(
-      background_, container_->GetShellWindowId(), &params);
+      background_, container_->aura_window()->id(), &params);
   background_->Init(params);
   background_window_ = WmWindow::Get(background_->GetNativeWindow());
   // Do not use the animation system. We don't want the bounds animation and
diff --git a/ash/wm/overview/scoped_transform_overview_window.cc b/ash/wm/overview/scoped_transform_overview_window.cc
index 1f70ded9..71ac284e 100644
--- a/ash/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/wm/overview/scoped_transform_overview_window.cc
@@ -483,7 +483,7 @@
   window_->GetRootWindow()
       ->GetRootWindowController()
       ->ConfigureWidgetInitParamsForContainer(
-          minimized_widget_.get(), window_->GetParent()->GetShellWindowId(),
+          minimized_widget_.get(), window_->GetParent()->aura_window()->id(),
           &params);
   minimized_widget_->set_focus_on_creation(false);
   minimized_widget_->Init(params);
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index 12aa74d..cba7519 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -529,7 +529,7 @@
     return;
 
   for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) {
-    if (new_window->GetParent()->GetShellWindowId() ==
+    if (new_window->GetParent()->aura_window()->id() ==
             wm::kSwitchableWindowContainerIds[i] &&
         !new_window->GetTransientParent()) {
       // The new window is in one of the switchable containers, abort overview.
diff --git a/ash/wm/overview/window_selector_item.cc b/ash/wm/overview/window_selector_item.cc
index dd2acf6..eb53ce63 100644
--- a/ash/wm/overview/window_selector_item.cc
+++ b/ash/wm/overview/window_selector_item.cc
@@ -619,7 +619,7 @@
   root_window_->GetRootWindowController()
       ->ConfigureWidgetInitParamsForContainer(
           item_widget_.get(),
-          transform_window_.window()->GetParent()->GetShellWindowId(),
+          transform_window_.window()->GetParent()->aura_window()->id(),
           &params_label);
   item_widget_->set_focus_on_creation(false);
   item_widget_->Init(params_label);
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 6cdd5e83..3548346f 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -516,9 +516,9 @@
   ToggleOverview();
   const std::vector<std::unique_ptr<WindowSelectorItem>>& overview1 =
       GetWindowItemsForRoot(0);
-  EXPECT_EQ(1, overview1[0]->GetWindow()->GetShellWindowId());
-  EXPECT_EQ(3, overview1[1]->GetWindow()->GetShellWindowId());
-  EXPECT_EQ(2, overview1[2]->GetWindow()->GetShellWindowId());
+  EXPECT_EQ(1, overview1[0]->GetWindow()->aura_window()->id());
+  EXPECT_EQ(3, overview1[1]->GetWindow()->aura_window()->id());
+  EXPECT_EQ(2, overview1[2]->GetWindow()->aura_window()->id());
   ToggleOverview();
 
   // Activate the second window.
@@ -528,9 +528,9 @@
       GetWindowItemsForRoot(0);
 
   // The order should be MRU.
-  EXPECT_EQ(2, overview2[0]->GetWindow()->GetShellWindowId());
-  EXPECT_EQ(1, overview2[1]->GetWindow()->GetShellWindowId());
-  EXPECT_EQ(3, overview2[2]->GetWindow()->GetShellWindowId());
+  EXPECT_EQ(2, overview2[0]->GetWindow()->aura_window()->id());
+  EXPECT_EQ(1, overview2[1]->GetWindow()->aura_window()->id());
+  EXPECT_EQ(3, overview2[2]->GetWindow()->aura_window()->id());
   ToggleOverview();
 }
 
@@ -1403,7 +1403,7 @@
       // string from the window IDs.
       const int index = index_path_for_direction[key_index][i];
       EXPECT_EQ(GetSelectedWindow()->id(),
-                overview_windows[index - 1]->GetWindow()->GetShellWindowId());
+                overview_windows[index - 1]->GetWindow()->aura_window()->id());
     }
     ToggleOverview();
   }
diff --git a/ash/wm/panels/panel_layout_manager.cc b/ash/wm/panels/panel_layout_manager.cc
index c3d9cd13..6478520 100644
--- a/ash/wm/panels/panel_layout_manager.cc
+++ b/ash/wm/panels/panel_layout_manager.cc
@@ -222,7 +222,7 @@
     params.bounds.set_height(kArrowHeight);
     params.accept_events = false;
     parent->GetRootWindowController()->ConfigureWidgetInitParamsForContainer(
-        this, parent->GetShellWindowId(), &params);
+        this, parent->aura_window()->id(), &params);
     set_focus_on_creation(false);
     Init(params);
     WmWindow* widget_window = WmWindow::Get(this->GetNativeWindow());
@@ -274,8 +274,8 @@
 
   return static_cast<PanelLayoutManager*>(
       window->GetRootWindow()
-          ->GetChildByShellWindowId(kShellWindowId_PanelContainer)
           ->aura_window()
+          ->GetChildById(kShellWindowId_PanelContainer)
           ->layout_manager());
 }
 
diff --git a/ash/wm/switchable_windows.cc b/ash/wm/switchable_windows.cc
index 6e0920d..a82e3dd6 100644
--- a/ash/wm/switchable_windows.cc
+++ b/ash/wm/switchable_windows.cc
@@ -6,6 +6,7 @@
 
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/wm_window.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 namespace wm {
@@ -20,7 +21,7 @@
 bool IsSwitchableContainer(const WmWindow* window) {
   if (!window)
     return false;
-  const int shell_window_id = window->GetShellWindowId();
+  const int shell_window_id = window->aura_window()->id();
   for (size_t i = 0; i < kSwitchableWindowContainerIdsLength; ++i) {
     if (shell_window_id == kSwitchableWindowContainerIds[i])
       return true;
diff --git a/ash/wm/system_modal_container_layout_manager.cc b/ash/wm/system_modal_container_layout_manager.cc
index d76a045b..1a2d659 100644
--- a/ash/wm/system_modal_container_layout_manager.cc
+++ b/ash/wm/system_modal_container_layout_manager.cc
@@ -81,7 +81,7 @@
   // TODO(mash): IsUserSessionBlocked() depends on knowing the login state. We
   // need a non-stub version of SessionStateDelegate. crbug.com/648964
   if (Shell::GetAshConfig() != Config::MASH) {
-    DCHECK(container_->GetShellWindowId() !=
+    DCHECK(container_->aura_window()->id() !=
                kShellWindowId_LockSystemModalContainer ||
            Shell::Get()->session_controller()->IsUserSessionBlocked());
   }
@@ -184,7 +184,7 @@
 
 // static
 bool SystemModalContainerLayoutManager::IsModalBackground(WmWindow* window) {
-  int id = window->GetParent()->GetShellWindowId();
+  int id = window->GetParent()->aura_window()->id();
   if (id != kShellWindowId_SystemModalContainer &&
       id != kShellWindowId_LockSystemModalContainer)
     return false;
diff --git a/ash/wm/window_positioning_utils.cc b/ash/wm/window_positioning_utils.cc
index 7140703a..f5e981ad 100644
--- a/ash/wm/window_positioning_utils.cc
+++ b/ash/wm/window_positioning_utils.cc
@@ -50,7 +50,7 @@
   WmWindow* dst_root =
       Shell::GetRootWindowControllerWithDisplayId(display.id())->GetWindow();
   for (WmWindow* transient_child : window->GetTransientChildren()) {
-    const int container_id = transient_child->GetParent()->GetShellWindowId();
+    const int container_id = transient_child->GetParent()->aura_window()->id();
     DCHECK_GE(container_id, 0);
     WmWindow* container = dst_root->GetChildByShellWindowId(container_id);
     const gfx::Rect transient_child_bounds_in_screen =
@@ -144,7 +144,7 @@
     DCHECK(dst_root);
     WmWindow* dst_container = nullptr;
     if (dst_root != window->GetRootWindow()) {
-      int container_id = window->GetParent()->GetShellWindowId();
+      int container_id = window->GetParent()->aura_window()->id();
       // All containers that uses screen coordinates must have valid window ids.
       DCHECK_GE(container_id, 0);
       // Don't move modal background.
diff --git a/ash/wm/wm_snap_to_pixel_layout_manager.cc b/ash/wm/wm_snap_to_pixel_layout_manager.cc
index e27d77e..a645cc8 100644
--- a/ash/wm/wm_snap_to_pixel_layout_manager.cc
+++ b/ash/wm/wm_snap_to_pixel_layout_manager.cc
@@ -20,8 +20,8 @@
 // static
 void WmSnapToPixelLayoutManager::InstallOnContainers(WmWindow* window) {
   for (WmWindow* child : window->GetChildren()) {
-    if (child->GetShellWindowId() < kShellWindowId_Min ||
-        child->GetShellWindowId() > kShellWindowId_Max)  // not a container
+    if (child->aura_window()->id() < kShellWindowId_Min ||
+        child->aura_window()->id() > kShellWindowId_Max)  // not a container
       continue;
     if (child->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)) {
       if (!child->GetLayoutManager() && !child->aura_window()->layout_manager())
diff --git a/ash/wm/workspace/phantom_window_controller.cc b/ash/wm/workspace/phantom_window_controller.cc
index 143d922..d334e9c 100644
--- a/ash/wm/workspace/phantom_window_controller.cc
+++ b/ash/wm/workspace/phantom_window_controller.cc
@@ -120,7 +120,7 @@
   phantom_widget->SetVisibilityChangedAnimationsEnabled(false);
   WmWindow* phantom_widget_window =
       WmWindow::Get(phantom_widget->GetNativeWindow());
-  phantom_widget_window->SetShellWindowId(kShellWindowId_PhantomWindow);
+  phantom_widget_window->aura_window()->set_id(kShellWindowId_PhantomWindow);
   phantom_widget->SetBounds(bounds_in_screen);
   // TODO(sky): I suspect this is never true, verify that.
   if (phantom_widget_window->GetParent() == window_->GetParent()) {
diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc
index 9eb5c6c..2017cdd 100644
--- a/ash/wm/workspace/workspace_layout_manager.cc
+++ b/ash/wm/workspace/workspace_layout_manager.cc
@@ -374,7 +374,7 @@
   // only windows in the default workspace container will go fullscreen but
   // this should really be tracked by the RootWindowController since
   // technically any container could get a fullscreen window.
-  if (window_->GetShellWindowId() != kShellWindowId_DefaultContainer)
+  if (window_->aura_window()->id() != kShellWindowId_DefaultContainer)
     return;
   bool is_fullscreen = wm::GetWindowForFullscreenMode(window_) != nullptr;
   if (is_fullscreen != is_fullscreen_) {
diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc
index 8b227d4..8243788b 100644
--- a/ash/wm/workspace/workspace_window_resizer.cc
+++ b/ash/wm/workspace/workspace_window_resizer.cc
@@ -72,7 +72,7 @@
 
   window_state->CreateDragDetails(point_in_parent, window_component, source);
   const int parent_shell_window_id =
-      window->GetParent() ? window->GetParent()->GetShellWindowId() : -1;
+      window->GetParent() ? window->GetParent()->aura_window()->id() : -1;
   if (window->GetParent() &&
       (parent_shell_window_id == kShellWindowId_DefaultContainer ||
        parent_shell_window_id == kShellWindowId_PanelContainer)) {
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc
index af1162e8..14ca8c9 100644
--- a/ash/wm/workspace_controller.cc
+++ b/ash/wm/workspace_controller.cc
@@ -12,12 +12,14 @@
 #include "ash/shell_port.h"
 #include "ash/wm/fullscreen_window_finder.h"
 #include "ash/wm/window_state.h"
+#include "ash/wm/window_state_aura.h"
 #include "ash/wm/wm_window_animations.h"
 #include "ash/wm/workspace/workspace_event_handler.h"
 #include "ash/wm/workspace/workspace_layout_manager.h"
 #include "ash/wm/workspace/workspace_layout_manager_backdrop_delegate.h"
 #include "ash/wm_window.h"
 #include "base/memory/ptr_util.h"
+#include "ui/aura/window.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 
@@ -62,17 +64,18 @@
   bool window_overlaps_launcher = false;
   // The default container may contain windows that may overlap the launcher
   // shelf and affect its transparency.
-  WmWindow* container = viewport_->GetRootWindow()->GetChildByShellWindowId(
-      kShellWindowId_DefaultContainer);
-  for (WmWindow* window : container->GetChildren()) {
-    wm::WindowState* window_state = window->GetWindowState();
+  aura::Window* container =
+      viewport_->GetRootWindow()->aura_window()->GetChildById(
+          kShellWindowId_DefaultContainer);
+  for (aura::Window* window : container->children()) {
+    wm::WindowState* window_state = wm::GetWindowState(window);
     if (window_state->ignored_by_shelf() ||
-        (window->GetLayer() && !window->GetLayer()->GetTargetVisibility())) {
+        (window->layer() && !window->layer()->GetTargetVisibility())) {
       continue;
     }
     if (window_state->IsMaximized())
       return wm::WORKSPACE_WINDOW_STATE_MAXIMIZED;
-    window_overlaps_launcher |= window->GetBounds().Intersects(shelf_bounds);
+    window_overlaps_launcher |= window->bounds().Intersects(shelf_bounds);
   }
 
   return window_overlaps_launcher
diff --git a/ash/wm_window.cc b/ash/wm_window.cc
index aa950b0..186d14e 100644
--- a/ash/wm_window.cc
+++ b/ash/wm_window.cc
@@ -155,14 +155,6 @@
   return root ? RootWindowController::ForWindow(root) : nullptr;
 }
 
-void WmWindow::SetShellWindowId(int id) {
-  window_->set_id(id);
-}
-
-int WmWindow::GetShellWindowId() const {
-  return window_->id();
-}
-
 ui::wm::WindowType WmWindow::GetType() const {
   return window_->type();
 }
diff --git a/ash/wm_window.h b/ash/wm_window.h
index 7ce8e27..de47237a 100644
--- a/ash/wm_window.h
+++ b/ash/wm_window.h
@@ -109,8 +109,6 @@
   RootWindowController* GetRootWindowController();
 
   // See shell_window_ids.h for list of known ids.
-  void SetShellWindowId(int id);
-  int GetShellWindowId() const;
   WmWindow* GetChildByShellWindowId(int id);
 
   ui::wm::WindowType GetType() const;
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 48686b8..f7918544 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -523,6 +523,8 @@
     "test/fake_compositor_frame_sink.h",
     "test/fake_compositor_frame_sink_client.cc",
     "test/fake_compositor_frame_sink_client.h",
+    "test/fake_compositor_frame_sink_support_client.cc",
+    "test/fake_compositor_frame_sink_support_client.h",
     "test/fake_content_layer_client.cc",
     "test/fake_content_layer_client.h",
     "test/fake_external_begin_frame_source.cc",
diff --git a/cc/surfaces/compositor_frame_sink_support.cc b/cc/surfaces/compositor_frame_sink_support.cc
index d1227031..84b0a41 100644
--- a/cc/surfaces/compositor_frame_sink_support.cc
+++ b/cc/surfaces/compositor_frame_sink_support.cc
@@ -74,7 +74,6 @@
     const ReturnedResourceArray& resources) {
   if (resources.empty())
     return;
-
   if (!ack_pending_count_ && client_) {
     client_->ReclaimResources(resources);
     return;
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index d9559eea..603d068 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -14,13 +14,12 @@
 #include "cc/quads/render_pass.h"
 #include "cc/resources/shared_bitmap_manager.h"
 #include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/display_client.h"
 #include "cc/surfaces/display_scheduler.h"
 #include "cc/surfaces/frame_sink_id.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
 #include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_manager.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/scheduler_test_common.h"
@@ -36,22 +35,6 @@
 
 static constexpr FrameSinkId kArbitraryFrameSinkId(3, 3);
 
-class FakeSurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  FakeSurfaceFactoryClient() : begin_frame_source_(nullptr) {}
-
-  void ReturnResources(const ReturnedResourceArray& resources) override {}
-
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {
-    begin_frame_source_ = begin_frame_source;
-  }
-
-  BeginFrameSource* begin_frame_source() { return begin_frame_source_; }
-
- private:
-  BeginFrameSource* begin_frame_source_;
-};
-
 class TestSoftwareOutputDevice : public SoftwareOutputDevice {
  public:
   TestSoftwareOutputDevice() {}
@@ -99,15 +82,16 @@
 class DisplayTest : public testing::Test {
  public:
   DisplayTest()
-      : factory_(kArbitraryFrameSinkId, &manager_, &surface_factory_client_),
-        task_runner_(new base::NullTaskRunner) {
-    manager_.RegisterFrameSinkId(kArbitraryFrameSinkId);
-  }
+      : support_(CompositorFrameSinkSupport::Create(
+            nullptr,
+            &manager_,
+            kArbitraryFrameSinkId,
+            true /* is_root */,
+            true /* handles_frame_sink_id_invalidation */,
+            true /* needs_sync_points */)),
+        task_runner_(new base::NullTaskRunner) {}
 
-  ~DisplayTest() override {
-    manager_.InvalidateFrameSinkId(kArbitraryFrameSinkId);
-    factory_.EvictSurface();
-  }
+  ~DisplayTest() override { support_->EvictFrame(); }
 
   void SetUpDisplay(const RendererSettings& settings,
                     std::unique_ptr<TestWebGraphicsContext3D> context) {
@@ -144,13 +128,11 @@
     CompositorFrame frame;
     pass_list->swap(frame.render_pass_list);
 
-    factory_.SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
   }
 
   SurfaceManager manager_;
-  FakeSurfaceFactoryClient surface_factory_client_;
-  SurfaceFactory factory_;
+  std::unique_ptr<CompositorFrameSinkSupport> support_;
   LocalSurfaceIdAllocator id_allocator_;
   scoped_refptr<base::NullTaskRunner> task_runner_;
   TestSharedBitmapManager shared_bitmap_manager_;
@@ -352,8 +334,7 @@
     pass_list.swap(frame.render_pass_list);
     frame.metadata.latency_info.push_back(ui::LatencyInfo());
 
-    factory_.SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
     EXPECT_TRUE(scheduler_->damaged);
     EXPECT_FALSE(scheduler_->display_resized_);
     EXPECT_FALSE(scheduler_->has_new_root_surface);
@@ -382,8 +363,7 @@
     CompositorFrame frame;
     pass_list.swap(frame.render_pass_list);
 
-    factory_.SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(local_surface_id, std::move(frame));
     EXPECT_TRUE(scheduler_->damaged);
     EXPECT_FALSE(scheduler_->display_resized_);
     EXPECT_FALSE(scheduler_->has_new_root_surface);
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 0e4e133a..04cca79 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -18,11 +18,11 @@
 #include "cc/quads/surface_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/shared_bitmap_manager.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
 #include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_manager.h"
+#include "cc/test/fake_compositor_frame_sink_support_client.h"
 #include "cc/test/fake_resource_provider.h"
 #include "cc/test/render_pass_test_utils.h"
 #include "cc/test/surface_aggregator_test_helpers.h"
@@ -35,10 +35,16 @@
 namespace {
 
 constexpr FrameSinkId kArbitraryRootFrameSinkId(1, 1);
-constexpr FrameSinkId kArbitraryChildFrameSinkId1(2, 2);
-constexpr FrameSinkId kArbitraryChildFrameSinkId2(3, 3);
+constexpr FrameSinkId kArbitraryFrameSinkId1(2, 2);
+constexpr FrameSinkId kArbitraryFrameSinkId2(3, 3);
 constexpr FrameSinkId kArbitraryMiddleFrameSinkId(4, 4);
+constexpr FrameSinkId kArbitraryReservedFrameSinkId(5, 5);
+constexpr FrameSinkId kArbitraryFrameSinkId3(6, 6);
 const base::UnguessableToken kArbitraryToken = base::UnguessableToken::Create();
+constexpr bool kRootIsRoot = true;
+constexpr bool kChildIsRoot = false;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = false;
 
 SurfaceId InvalidSurfaceId() {
   static SurfaceId invalid(FrameSinkId(),
@@ -51,47 +57,36 @@
   return size;
 }
 
-class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  void ReturnResources(const ReturnedResourceArray& resources) override {}
-
-  void WillDrawSurface(const LocalSurfaceId& id,
-                       const gfx::Rect& damage_rect) override {
-    last_local_surface_id_ = id;
-    last_damage_rect_ = damage_rect;
-  }
-
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {}
-
-  gfx::Rect last_damage_rect_;
-  LocalSurfaceId last_local_surface_id_;
-};
-
 class SurfaceAggregatorTest : public testing::Test {
  public:
   explicit SurfaceAggregatorTest(bool use_damage_rect)
-      : factory_(kArbitraryRootFrameSinkId, &manager_, &empty_client_),
+      : support_(
+            CompositorFrameSinkSupport::Create(&fake_client_,
+                                               &manager_,
+                                               kArbitraryRootFrameSinkId,
+                                               kRootIsRoot,
+                                               kHandlesFrameSinkIdInvalidation,
+                                               kNeedsSyncPoints)),
         aggregator_(&manager_, NULL, use_damage_rect) {}
 
   SurfaceAggregatorTest() : SurfaceAggregatorTest(false) {}
 
   void TearDown() override {
-    factory_.EvictSurface();
+    support_->EvictFrame();
     testing::Test::TearDown();
   }
 
  protected:
   SurfaceManager manager_;
-  EmptySurfaceFactoryClient empty_client_;
-  SurfaceFactory factory_;
+  FakeCompositorFrameSinkSupportClient fake_client_;
+  std::unique_ptr<CompositorFrameSinkSupport> support_;
   SurfaceAggregator aggregator_;
 };
 
 TEST_F(SurfaceAggregatorTest, ValidSurfaceNoFrame) {
   LocalSurfaceId local_surface_id(7, base::UnguessableToken::Create());
   SurfaceId one_id(kArbitraryRootFrameSinkId, local_surface_id);
-  factory_.SubmitCompositorFrame(local_surface_id, CompositorFrame(),
-                                 SurfaceFactory::DrawCallback());
+  support_->SubmitCompositorFrame(local_surface_id, CompositorFrame());
 
   CompositorFrame frame = aggregator_.Aggregate(one_id);
   EXPECT_TRUE(frame.render_pass_list.empty());
@@ -101,9 +96,13 @@
  public:
   explicit SurfaceAggregatorValidSurfaceTest(bool use_damage_rect)
       : SurfaceAggregatorTest(use_damage_rect),
-        child_factory_(kArbitraryChildFrameSinkId1,
-                       &manager_,
-                       &empty_child_client_) {}
+        child_support_(
+            CompositorFrameSinkSupport::Create(nullptr,
+                                               &manager_,
+                                               kArbitraryReservedFrameSinkId,
+                                               kChildIsRoot,
+                                               kHandlesFrameSinkIdInvalidation,
+                                               kNeedsSyncPoints)) {}
   SurfaceAggregatorValidSurfaceTest()
       : SurfaceAggregatorValidSurfaceTest(false) {}
 
@@ -111,11 +110,11 @@
     SurfaceAggregatorTest::SetUp();
     root_local_surface_id_ = allocator_.GenerateId();
     root_surface_ = manager_.GetSurfaceForId(
-        SurfaceId(factory_.frame_sink_id(), root_local_surface_id_));
+        SurfaceId(support_->frame_sink_id(), root_local_surface_id_));
   }
 
   void TearDown() override {
-    child_factory_.EvictSurface();
+    child_support_->EvictFrame();
     SurfaceAggregatorTest::TearDown();
   }
 
@@ -124,7 +123,7 @@
                           SurfaceId* surface_ids,
                           size_t expected_surface_count) {
     CompositorFrame aggregated_frame = aggregator_.Aggregate(
-        SurfaceId(factory_.frame_sink_id(), root_local_surface_id_));
+        SurfaceId(support_->frame_sink_id(), root_local_surface_id_));
 
     TestPassesMatchExpectations(expected_passes, expected_pass_count,
                                 &aggregated_frame.render_pass_list);
@@ -144,41 +143,38 @@
     }
   }
 
-  void SubmitPassListAsFrame(SurfaceFactory* factory,
+  void SubmitPassListAsFrame(CompositorFrameSinkSupport* support,
                              const LocalSurfaceId& local_surface_id,
                              RenderPassList* pass_list) {
     CompositorFrame frame;
     pass_list->swap(frame.render_pass_list);
 
-    factory->SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support->SubmitCompositorFrame(local_surface_id, std::move(frame));
   }
 
-  void SubmitCompositorFrame(SurfaceFactory* factory,
+  void SubmitCompositorFrame(CompositorFrameSinkSupport* support,
                              test::Pass* passes,
                              size_t pass_count,
                              const LocalSurfaceId& local_surface_id) {
     RenderPassList pass_list;
     AddPasses(&pass_list, gfx::Rect(SurfaceSize()), passes, pass_count);
-    SubmitPassListAsFrame(factory, local_surface_id, &pass_list);
+    SubmitPassListAsFrame(support, local_surface_id, &pass_list);
   }
 
   void QueuePassAsFrame(std::unique_ptr<RenderPass> pass,
                         const LocalSurfaceId& local_surface_id,
-                        SurfaceFactory* factory) {
+                        CompositorFrameSinkSupport* support) {
     CompositorFrame child_frame;
     child_frame.render_pass_list.push_back(std::move(pass));
 
-    factory->SubmitCompositorFrame(local_surface_id, std::move(child_frame),
-                                   SurfaceFactory::DrawCallback());
+    support->SubmitCompositorFrame(local_surface_id, std::move(child_frame));
   }
 
  protected:
   LocalSurfaceId root_local_surface_id_;
   Surface* root_surface_;
   LocalSurfaceIdAllocator allocator_;
-  EmptySurfaceFactoryClient empty_child_client_;
-  SurfaceFactory child_factory_;
+  std::unique_ptr<CompositorFrameSinkSupport> child_support_;
   LocalSurfaceIdAllocator child_allocator_;
 };
 
@@ -189,24 +185,26 @@
                         test::Quad::SolidColorQuad(SK_ColorBLUE)};
   test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id};
 
   AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids));
 
   // Check that WillDrawSurface was called.
-  EXPECT_EQ(gfx::Rect(SurfaceSize()), empty_client_.last_damage_rect_);
-  EXPECT_EQ(root_local_surface_id_, empty_client_.last_local_surface_id_);
+  EXPECT_EQ(gfx::Rect(SurfaceSize()), fake_client_.last_damage_rect());
+  EXPECT_EQ(root_local_surface_id_, fake_client_.last_local_surface_id());
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
-  SurfaceFactory embedded_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                  &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> embedded_support(
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kRootIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
   LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
-  SurfaceId embedded_surface_id(embedded_factory.frame_sink_id(),
+  SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
                                 embedded_local_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
@@ -214,17 +212,17 @@
   test::Pass embedded_passes[] = {
       test::Pass(embedded_quads, arraysize(embedded_quads))};
 
-  SubmitCompositorFrame(&embedded_factory, embedded_passes,
+  SubmitCompositorFrame(embedded_support.get(), embedded_passes,
                         arraysize(embedded_passes), embedded_local_surface_id);
 
   test::Quad quads[] = {
       test::Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(), .5f)};
   test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   RenderPassList& render_pass_list(aggregated_frame.render_pass_list);
@@ -240,7 +238,7 @@
   ASSERT_EQ(1u, shared_quad_state_list2.size());
   EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity);
 
-  embedded_factory.EvictSurface();
+  embedded_support->EvictFrame();
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSimpleFrame) {
@@ -251,10 +249,10 @@
   test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0]), 1),
                          test::Pass(quads[1], arraysize(quads[1]), 2)};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id};
 
   AggregateAndVerify(passes, arraysize(passes), ids, arraysize(ids));
@@ -269,10 +267,10 @@
   test::Pass passes[] = {test::Pass(quads[0], arraysize(quads[0]), 2),
                          test::Pass(quads[1], arraysize(quads[1]), 1)};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
-  SurfaceId surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId surface_id(support_->frame_sink_id(), root_local_surface_id_);
 
   CompositorFrame aggregated_frame;
   aggregated_frame = aggregator_.Aggregate(surface_id);
@@ -288,7 +286,7 @@
   test::Pass passes2[] = {test::Pass(quads[0], arraysize(quads[0]), 3),
                           test::Pass(quads[1], arraysize(quads[1]), 1)};
 
-  SubmitCompositorFrame(&factory_, passes2, arraysize(passes2),
+  SubmitCompositorFrame(support_.get(), passes2, arraysize(passes2),
                         root_local_surface_id_);
 
   // The RenderPass that still exists should keep the same ID.
@@ -298,7 +296,7 @@
   EXPECT_NE(id2, id0);
   EXPECT_EQ(id1, aggregated_frame.render_pass_list[1]->id);
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
   // |id1| didn't exist in the previous frame, so it should be
@@ -316,17 +314,19 @@
 // embedded_surface has a frame containing only a solid color quad. The solid
 // color quad should be aggregated into the final frame.
 TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleSurfaceReference) {
-  SurfaceFactory embedded_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                  &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> embedded_support(
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kRootIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints));
   LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
-  SurfaceId embedded_surface_id(embedded_factory.frame_sink_id(),
+  SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
                                 embedded_local_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
       test::Pass(embedded_quads, arraysize(embedded_quads))};
 
-  SubmitCompositorFrame(&embedded_factory, embedded_passes,
+  SubmitCompositorFrame(embedded_support.get(), embedded_passes,
                         arraysize(embedded_passes), embedded_local_surface_id);
 
   test::Quad root_quads[] = {
@@ -335,7 +335,7 @@
       test::Quad::SolidColorQuad(SK_ColorBLACK)};
   test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
 
-  SubmitCompositorFrame(&factory_, root_passes, arraysize(root_passes),
+  SubmitCompositorFrame(support_.get(), root_passes, arraysize(root_passes),
                         root_local_surface_id_);
 
   test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
@@ -343,28 +343,32 @@
                                  test::Quad::SolidColorQuad(SK_ColorBLACK)};
   test::Pass expected_passes[] = {
       test::Pass(expected_quads, arraysize(expected_quads))};
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id, embedded_surface_id};
   AggregateAndVerify(
       expected_passes, arraysize(expected_passes), ids, arraysize(ids));
 
-  embedded_factory.EvictSurface();
+  embedded_support->EvictFrame();
 }
 
 // This test verifies that in the absence of a primary Surface,
 // SurfaceAggregator will embed a fallback Surface, if available. If the primary
 // Surface is available, though, the fallback will not be used.
 TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReference) {
-  SurfaceFactory primary_child_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                       &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> primary_child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId primary_child_local_surface_id = allocator_.GenerateId();
-  SurfaceId primary_child_surface_id(primary_child_factory.frame_sink_id(),
+  SurfaceId primary_child_surface_id(primary_child_support->frame_sink_id(),
                                      primary_child_local_surface_id);
 
-  SurfaceFactory fallback_child_factory(kArbitraryChildFrameSinkId2, &manager_,
-                                        &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> fallback_child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId fallback_child_local_surface_id = allocator_.GenerateId();
-  SurfaceId fallback_child_surface_id(fallback_child_factory.frame_sink_id(),
+  SurfaceId fallback_child_surface_id(fallback_child_support->frame_sink_id(),
                                       fallback_child_local_surface_id);
 
   test::Quad fallback_child_quads[] = {test::Quad::SolidColorQuad(SK_ColorRED)};
@@ -373,7 +377,7 @@
 
   // Submit a CompositorFrame to the fallback Surface containing a red
   // SolidColorDrawQuad.
-  SubmitCompositorFrame(&fallback_child_factory, fallback_child_passes,
+  SubmitCompositorFrame(fallback_child_support.get(), fallback_child_passes,
                         arraysize(fallback_child_passes),
                         fallback_child_local_surface_id);
 
@@ -383,7 +387,7 @@
       primary_child_surface_id, fallback_child_surface_id, 1.f)};
   test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
 
-  SubmitCompositorFrame(&factory_, root_passes, arraysize(root_passes),
+  SubmitCompositorFrame(support_.get(), root_passes, arraysize(root_passes),
                         root_local_surface_id_);
 
   // There is no CompositorFrame submitted to |primary_child_surface_id| and so
@@ -393,7 +397,7 @@
   test::Pass expected_passes1[] = {
       test::Pass(expected_quads1, arraysize(expected_quads1))};
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id, primary_child_surface_id,
                      fallback_child_surface_id};
   AggregateAndVerify(expected_passes1, arraysize(expected_passes1), ids,
@@ -406,7 +410,7 @@
 
   // Submit a CompositorFrame to the primary Surface containing a green
   // SolidColorDrawQuad.
-  SubmitCompositorFrame(&primary_child_factory, primary_child_passes,
+  SubmitCompositorFrame(primary_child_support.get(), primary_child_passes,
                         arraysize(primary_child_passes),
                         primary_child_local_surface_id);
 
@@ -419,17 +423,19 @@
   AggregateAndVerify(expected_passes2, arraysize(expected_passes2), ids,
                      arraysize(ids));
 
-  primary_child_factory.EvictSurface();
-  fallback_child_factory.EvictSurface();
+  primary_child_support->EvictFrame();
+  fallback_child_support->EvictFrame();
 }
 
 // This test verifies that in the presence of both primary Surface and fallback
 // Surface, the fallback will not be used.
 TEST_F(SurfaceAggregatorValidSurfaceTest, FallbackSurfaceReferenceWithPrimary) {
-  SurfaceFactory primary_child_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                       &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> primary_child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId primary_child_local_surface_id = allocator_.GenerateId();
-  SurfaceId primary_child_surface_id(primary_child_factory.frame_sink_id(),
+  SurfaceId primary_child_surface_id(primary_child_support->frame_sink_id(),
                                      primary_child_local_surface_id);
   test::Quad primary_child_quads[] = {
       test::Quad::SolidColorQuad(SK_ColorGREEN)};
@@ -438,14 +444,16 @@
 
   // Submit a CompositorFrame to the primary Surface containing a green
   // SolidColorDrawQuad.
-  SubmitCompositorFrame(&primary_child_factory, primary_child_passes,
+  SubmitCompositorFrame(primary_child_support.get(), primary_child_passes,
                         arraysize(primary_child_passes),
                         primary_child_local_surface_id);
 
-  SurfaceFactory fallback_child_factory(kArbitraryChildFrameSinkId2, &manager_,
-                                        &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> fallback_child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId fallback_child_local_surface_id = allocator_.GenerateId();
-  SurfaceId fallback_child_surface_id(fallback_child_factory.frame_sink_id(),
+  SurfaceId fallback_child_surface_id(fallback_child_support->frame_sink_id(),
                                       fallback_child_local_surface_id);
 
   test::Quad fallback_child_quads[] = {test::Quad::SolidColorQuad(SK_ColorRED)};
@@ -454,7 +462,7 @@
 
   // Submit a CompositorFrame to the fallback Surface containing a red
   // SolidColorDrawQuad.
-  SubmitCompositorFrame(&fallback_child_factory, fallback_child_passes,
+  SubmitCompositorFrame(fallback_child_support.get(), fallback_child_passes,
                         arraysize(fallback_child_passes),
                         fallback_child_local_surface_id);
 
@@ -464,7 +472,7 @@
       primary_child_surface_id, fallback_child_surface_id, 1.f)};
   test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
 
-  SubmitCompositorFrame(&factory_, root_passes, arraysize(root_passes),
+  SubmitCompositorFrame(support_.get(), root_passes, arraysize(root_passes),
                         root_local_surface_id_);
 
   // The CompositorFrame is submitted to |primary_child_surface_id|, so
@@ -474,33 +482,35 @@
   test::Pass expected_passes1[] = {
       test::Pass(expected_quads1, arraysize(expected_quads1))};
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id, primary_child_surface_id,
                      fallback_child_surface_id};
   AggregateAndVerify(expected_passes1, arraysize(expected_passes1), ids,
                      arraysize(ids));
 
-  primary_child_factory.EvictSurface();
-  fallback_child_factory.EvictSurface();
+  primary_child_support->EvictFrame();
+  fallback_child_support->EvictFrame();
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, CopyRequest) {
-  SurfaceFactory embedded_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                  &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> embedded_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
-  SurfaceId embedded_surface_id(embedded_factory.frame_sink_id(),
+  SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
                                 embedded_local_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
       test::Pass(embedded_quads, arraysize(embedded_quads))};
 
-  SubmitCompositorFrame(&embedded_factory, embedded_passes,
+  SubmitCompositorFrame(embedded_support.get(), embedded_passes,
                         arraysize(embedded_passes), embedded_local_surface_id);
   std::unique_ptr<CopyOutputRequest> copy_request(
       CopyOutputRequest::CreateEmptyRequest());
   CopyOutputRequest* copy_request_ptr = copy_request.get();
-  embedded_factory.RequestCopyOfSurface(std::move(copy_request));
+  embedded_support->RequestCopyOfSurface(std::move(copy_request));
 
   test::Quad root_quads[] = {
       test::Quad::SolidColorQuad(SK_ColorWHITE),
@@ -508,10 +518,10 @@
       test::Quad::SolidColorQuad(SK_ColorBLACK)};
   test::Pass root_passes[] = {test::Pass(root_quads, arraysize(root_quads))};
 
-  SubmitCompositorFrame(&factory_, root_passes, arraysize(root_passes),
+  SubmitCompositorFrame(support_.get(), root_passes, arraysize(root_passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   test::Quad expected_quads[] = {
@@ -537,22 +547,24 @@
         aggregator_.previous_contained_surfaces().end());
   }
 
-  embedded_factory.EvictSurface();
+  embedded_support->EvictFrame();
 }
 
 // Root surface may contain copy requests.
 TEST_F(SurfaceAggregatorValidSurfaceTest, RootCopyRequest) {
-  SurfaceFactory embedded_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                  &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> embedded_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
-  SurfaceId embedded_surface_id(embedded_factory.frame_sink_id(),
+  SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
                                 embedded_local_surface_id);
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
       test::Pass(embedded_quads, arraysize(embedded_quads))};
 
-  SubmitCompositorFrame(&embedded_factory, embedded_passes,
+  SubmitCompositorFrame(embedded_support.get(), embedded_passes,
                         arraysize(embedded_passes), embedded_local_surface_id);
   std::unique_ptr<CopyOutputRequest> copy_request(
       CopyOutputRequest::CreateEmptyRequest());
@@ -577,11 +589,10 @@
     frame.render_pass_list[1]->copy_requests.push_back(
         std::move(copy_request2));
 
-    factory_.SubmitCompositorFrame(root_local_surface_id_, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
   }
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
@@ -617,33 +628,37 @@
   DCHECK(original_pass_list[0]->copy_requests.empty());
   DCHECK(original_pass_list[1]->copy_requests.empty());
 
-  embedded_factory.EvictSurface();
+  embedded_support->EvictFrame();
 }
 
 TEST_F(SurfaceAggregatorValidSurfaceTest, UnreferencedSurface) {
-  SurfaceFactory embedded_factory(kArbitraryChildFrameSinkId1, &manager_,
-                                  &empty_client_);
-  SurfaceFactory parent_factory(kArbitraryRootFrameSinkId, &manager_,
-                                &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> embedded_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> parent_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId2, kRootIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId embedded_local_surface_id = allocator_.GenerateId();
-  SurfaceId embedded_surface_id(embedded_factory.frame_sink_id(),
+  SurfaceId embedded_surface_id(embedded_support->frame_sink_id(),
                                 embedded_local_surface_id);
-  SurfaceId nonexistent_surface_id(factory_.frame_sink_id(),
+  SurfaceId nonexistent_surface_id(support_->frame_sink_id(),
                                    allocator_.GenerateId());
 
   test::Quad embedded_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN)};
   test::Pass embedded_passes[] = {
       test::Pass(embedded_quads, arraysize(embedded_quads))};
 
-  SubmitCompositorFrame(&embedded_factory, embedded_passes,
+  SubmitCompositorFrame(embedded_support.get(), embedded_passes,
                         arraysize(embedded_passes), embedded_local_surface_id);
   std::unique_ptr<CopyOutputRequest> copy_request(
       CopyOutputRequest::CreateEmptyRequest());
   CopyOutputRequest* copy_request_ptr = copy_request.get();
-  embedded_factory.RequestCopyOfSurface(std::move(copy_request));
+  embedded_support->RequestCopyOfSurface(std::move(copy_request));
 
   LocalSurfaceId parent_local_surface_id = allocator_.GenerateId();
-  SurfaceId parent_surface_id(parent_factory.frame_sink_id(),
+  SurfaceId parent_surface_id(parent_support->frame_sink_id(),
                               parent_local_surface_id);
 
   test::Quad parent_quads[] = {
@@ -661,9 +676,8 @@
 
     frame.metadata.referenced_surfaces.push_back(embedded_surface_id);
 
-    parent_factory.SubmitCompositorFrame(parent_local_surface_id,
-                                         std::move(frame),
-                                         SurfaceFactory::DrawCallback());
+    parent_support->SubmitCompositorFrame(parent_local_surface_id,
+                                          std::move(frame));
   }
 
   test::Quad root_quads[] = {test::Quad::SolidColorQuad(SK_ColorWHITE),
@@ -680,11 +694,10 @@
     // included in previous_contained_surfaces, but otherwise ignored.
     frame.metadata.referenced_surfaces.push_back(nonexistent_surface_id);
 
-    factory_.SubmitCompositorFrame(root_local_surface_id_, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(root_local_surface_id_, std::move(frame));
   }
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   // First pass should come from surface that had a copy request but was not
@@ -702,7 +715,7 @@
             aggregated_frame.render_pass_list[0]->copy_requests[0].get());
 
   SurfaceId surface_ids[] = {
-      SurfaceId(factory_.frame_sink_id(), root_local_surface_id_),
+      SurfaceId(support_->frame_sink_id(), root_local_surface_id_),
       parent_surface_id, embedded_surface_id, nonexistent_surface_id};
   EXPECT_EQ(arraysize(surface_ids),
             aggregator_.previous_contained_surfaces().size());
@@ -712,14 +725,14 @@
         aggregator_.previous_contained_surfaces().end());
   }
 
-  embedded_factory.EvictSurface();
-  parent_factory.EvictSurface();
+  embedded_support->EvictFrame();
+  parent_support->EvictFrame();
 }
 
 // This tests referencing a surface that has multiple render passes.
 TEST_F(SurfaceAggregatorValidSurfaceTest, MultiPassSurfaceReference) {
   LocalSurfaceId embedded_local_surface_id = child_allocator_.GenerateId();
-  SurfaceId embedded_surface_id(child_factory_.frame_sink_id(),
+  SurfaceId embedded_surface_id(child_support_->frame_sink_id(),
                                 embedded_local_surface_id);
 
   int pass_ids[] = {1, 2, 3};
@@ -733,7 +746,7 @@
       test::Pass(embedded_quads[1], arraysize(embedded_quads[1]), pass_ids[1]),
       test::Pass(embedded_quads[2], arraysize(embedded_quads[2]), pass_ids[2])};
 
-  SubmitCompositorFrame(&child_factory_, embedded_passes,
+  SubmitCompositorFrame(child_support_.get(), embedded_passes,
                         arraysize(embedded_passes), embedded_local_surface_id);
 
   test::Quad root_quads[][2] = {
@@ -746,10 +759,10 @@
       test::Pass(root_quads[1], arraysize(root_quads[1]), pass_ids[1]),
       test::Pass(root_quads[2], arraysize(root_quads[2]), pass_ids[2])};
 
-  SubmitCompositorFrame(&factory_, root_passes, arraysize(root_passes),
+  SubmitCompositorFrame(support_.get(), root_passes, arraysize(root_passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   const RenderPassList& aggregated_pass_list =
@@ -861,14 +874,14 @@
       test::Quad::SolidColorQuad(SK_ColorBLUE)};
   test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
   test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
                                  test::Quad::SolidColorQuad(SK_ColorBLUE)};
   test::Pass expected_passes[] = {
       test::Pass(expected_quads, arraysize(expected_quads))};
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id, InvalidSurfaceId()};
 
   AggregateAndVerify(
@@ -879,7 +892,7 @@
 // should also just be dropped.
 TEST_F(SurfaceAggregatorValidSurfaceTest, ValidSurfaceReferenceWithNoFrame) {
   LocalSurfaceId empty_local_surface_id = allocator_.GenerateId();
-  SurfaceId surface_with_no_frame_id(factory_.frame_sink_id(),
+  SurfaceId surface_with_no_frame_id(support_->frame_sink_id(),
                                      empty_local_surface_id);
 
   test::Quad quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
@@ -888,14 +901,14 @@
                         test::Quad::SolidColorQuad(SK_ColorBLUE)};
   test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
   test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorGREEN),
                                  test::Quad::SolidColorQuad(SK_ColorBLUE)};
   test::Pass expected_passes[] = {
       test::Pass(expected_quads, arraysize(expected_quads))};
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   SurfaceId ids[] = {root_surface_id, surface_with_no_frame_id};
   AggregateAndVerify(
       expected_passes, arraysize(expected_passes), ids, arraysize(ids));
@@ -904,13 +917,13 @@
 // Tests a surface quad referencing itself, generating a trivial cycle.
 // The quad creating the cycle should be dropped from the final frame.
 TEST_F(SurfaceAggregatorValidSurfaceTest, SimpleCyclicalReference) {
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   test::Quad quads[] = {
       test::Quad::SurfaceQuad(root_surface_id, InvalidSurfaceId(), 1.f),
       test::Quad::SolidColorQuad(SK_ColorYELLOW)};
   test::Pass passes[] = {test::Pass(quads, arraysize(quads))};
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
   test::Quad expected_quads[] = {test::Quad::SolidColorQuad(SK_ColorYELLOW)};
@@ -924,7 +937,7 @@
 // Tests a more complex cycle with one intermediate surface.
 TEST_F(SurfaceAggregatorValidSurfaceTest, TwoSurfaceCyclicalReference) {
   LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_surface_id(child_factory_.frame_sink_id(),
+  SurfaceId child_surface_id(child_support_->frame_sink_id(),
                              child_local_surface_id);
 
   test::Quad parent_quads[] = {
@@ -934,18 +947,18 @@
   test::Pass parent_passes[] = {
       test::Pass(parent_quads, arraysize(parent_quads))};
 
-  SubmitCompositorFrame(&factory_, parent_passes, arraysize(parent_passes),
+  SubmitCompositorFrame(support_.get(), parent_passes, arraysize(parent_passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   test::Quad child_quads[] = {
       test::Quad::SolidColorQuad(SK_ColorGREEN),
       test::Quad::SurfaceQuad(root_surface_id, InvalidSurfaceId(), 1.f),
       test::Quad::SolidColorQuad(SK_ColorMAGENTA)};
   test::Pass child_passes[] = {test::Pass(child_quads, arraysize(child_quads))};
 
-  SubmitCompositorFrame(&child_factory_, child_passes, arraysize(child_passes),
-                        child_local_surface_id);
+  SubmitCompositorFrame(child_support_.get(), child_passes,
+                        arraysize(child_passes), child_local_surface_id);
 
   // The child surface's reference to the root_surface_ will be dropped, so
   // we'll end up with:
@@ -968,7 +981,7 @@
 // namespace and update RenderPassDrawQuad's id references to match.
 TEST_F(SurfaceAggregatorValidSurfaceTest, RenderPassIdMapping) {
   LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_surface_id(child_factory_.frame_sink_id(),
+  SurfaceId child_surface_id(child_support_->frame_sink_id(),
                              child_local_surface_id);
 
   int child_pass_id[] = {1, 2};
@@ -978,7 +991,7 @@
       test::Pass(child_quad[0], arraysize(child_quad[0]), child_pass_id[0]),
       test::Pass(child_quad[1], arraysize(child_quad[1]), child_pass_id[1])};
 
-  SubmitCompositorFrame(&child_factory_, surface_passes,
+  SubmitCompositorFrame(child_support_.get(), surface_passes,
                         arraysize(surface_passes), child_local_surface_id);
 
   // Pass IDs from the parent surface may collide with ones from the child.
@@ -990,10 +1003,10 @@
       test::Pass(parent_quad[0], arraysize(parent_quad[0]), parent_pass_id[0]),
       test::Pass(parent_quad[1], arraysize(parent_quad[1]), parent_pass_id[1])};
 
-  SubmitCompositorFrame(&factory_, parent_passes, arraysize(parent_passes),
+  SubmitCompositorFrame(support_.get(), parent_passes, arraysize(parent_passes),
                         root_local_surface_id_);
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   const RenderPassList& aggregated_pass_list =
@@ -1085,20 +1098,24 @@
       SkBlendMode::kSrcIn,    // 5
       SkBlendMode::kDstIn,    // 6
   };
-
-  SurfaceFactory grandchild_factory(FrameSinkId(2, 2), &manager_,
-                                    &empty_client_);
-  SurfaceFactory child_one_factory(FrameSinkId(3, 3), &manager_,
-                                   &empty_client_);
-  SurfaceFactory child_two_factory(FrameSinkId(4, 4), &manager_,
-                                   &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> grandchild_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> child_one_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId2, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> child_two_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId3, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   int pass_id = 1;
   LocalSurfaceId grandchild_local_surface_id = allocator_.GenerateId();
-  SurfaceId grandchild_surface_id(grandchild_factory.frame_sink_id(),
+  SurfaceId grandchild_surface_id(grandchild_support->frame_sink_id(),
                                   grandchild_local_surface_id);
-  grandchild_factory.SubmitCompositorFrame(grandchild_local_surface_id,
-                                           CompositorFrame(),
-                                           SurfaceFactory::DrawCallback());
+  grandchild_support->SubmitCompositorFrame(grandchild_local_surface_id,
+                                            CompositorFrame());
   std::unique_ptr<RenderPass> grandchild_pass = RenderPass::Create();
   gfx::Rect output_rect(SurfaceSize());
   gfx::Rect damage_rect(SurfaceSize());
@@ -1108,14 +1125,13 @@
   AddSolidColorQuadWithBlendMode(
       SurfaceSize(), grandchild_pass.get(), blend_modes[2]);
   QueuePassAsFrame(std::move(grandchild_pass), grandchild_local_surface_id,
-                   &grandchild_factory);
+                   grandchild_support.get());
 
   LocalSurfaceId child_one_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_one_surface_id(child_one_factory.frame_sink_id(),
+  SurfaceId child_one_surface_id(child_one_support->frame_sink_id(),
                                  child_one_local_surface_id);
-  child_one_factory.SubmitCompositorFrame(child_one_local_surface_id,
-                                          CompositorFrame(),
-                                          SurfaceFactory::DrawCallback());
+  child_one_support->SubmitCompositorFrame(child_one_local_surface_id,
+                                           CompositorFrame());
 
   std::unique_ptr<RenderPass> child_one_pass = RenderPass::Create();
   child_one_pass->SetNew(pass_id, output_rect, damage_rect,
@@ -1131,14 +1147,13 @@
   AddSolidColorQuadWithBlendMode(
       SurfaceSize(), child_one_pass.get(), blend_modes[3]);
   QueuePassAsFrame(std::move(child_one_pass), child_one_local_surface_id,
-                   &child_one_factory);
+                   child_one_support.get());
 
   LocalSurfaceId child_two_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_two_surface_id(child_two_factory.frame_sink_id(),
+  SurfaceId child_two_surface_id(child_two_support->frame_sink_id(),
                                  child_two_local_surface_id);
-  child_two_factory.SubmitCompositorFrame(child_two_local_surface_id,
-                                          CompositorFrame(),
-                                          SurfaceFactory::DrawCallback());
+  child_two_support->SubmitCompositorFrame(child_two_local_surface_id,
+                                           CompositorFrame());
 
   std::unique_ptr<RenderPass> child_two_pass = RenderPass::Create();
   child_two_pass->SetNew(pass_id, output_rect, damage_rect,
@@ -1146,7 +1161,7 @@
   AddSolidColorQuadWithBlendMode(
       SurfaceSize(), child_two_pass.get(), blend_modes[5]);
   QueuePassAsFrame(std::move(child_two_pass), child_two_local_surface_id,
-                   &child_two_factory);
+                   child_two_support.get());
 
   std::unique_ptr<RenderPass> root_pass = RenderPass::Create();
   root_pass->SetNew(pass_id, output_rect, damage_rect,
@@ -1171,9 +1186,10 @@
   AddSolidColorQuadWithBlendMode(
       SurfaceSize(), root_pass.get(), blend_modes[6]);
 
-  QueuePassAsFrame(std::move(root_pass), root_local_surface_id_, &factory_);
+  QueuePassAsFrame(std::move(root_pass), root_local_surface_id_,
+                   support_.get());
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   const RenderPassList& aggregated_pass_list =
@@ -1192,9 +1208,9 @@
         << iter.index();
   }
 
-  grandchild_factory.EvictSurface();
-  child_one_factory.EvictSurface();
-  child_two_factory.EvictSurface();
+  grandchild_support->EvictFrame();
+  child_one_support->EvictFrame();
+  child_two_support->EvictFrame();
 }
 
 // This tests that when aggregating a frame with multiple render passes that we
@@ -1216,11 +1232,13 @@
 // contributing render pass' transform in the aggregate frame should not be
 // affected.
 TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateMultiplePassWithTransform) {
-  SurfaceFactory middle_factory(kArbitraryMiddleFrameSinkId, &manager_,
-                                &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> middle_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   // Innermost child surface.
   LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_surface_id(child_factory_.frame_sink_id(),
+  SurfaceId child_surface_id(child_support_->frame_sink_id(),
                              child_local_surface_id);
   {
     int child_pass_id[] = {1, 2};
@@ -1250,14 +1268,13 @@
     child_root_pass_sqs->is_clipped = true;
     child_root_pass_sqs->clip_rect = gfx::Rect(0, 0, 5, 5);
 
-    child_factory_.SubmitCompositorFrame(child_local_surface_id,
-                                         std::move(child_frame),
-                                         SurfaceFactory::DrawCallback());
+    child_support_->SubmitCompositorFrame(child_local_surface_id,
+                                          std::move(child_frame));
   }
 
   // Middle child surface.
   LocalSurfaceId middle_local_surface_id = allocator_.GenerateId();
-  SurfaceId middle_surface_id(middle_factory.frame_sink_id(),
+  SurfaceId middle_surface_id(middle_support->frame_sink_id(),
                               middle_local_surface_id);
   {
     test::Quad middle_quads[] = {
@@ -1277,9 +1294,8 @@
         middle_root_pass->shared_quad_state_list.front();
     middle_root_pass_sqs->quad_to_target_transform.Scale(2, 3);
 
-    middle_factory.SubmitCompositorFrame(middle_local_surface_id,
-                                         std::move(middle_frame),
-                                         SurfaceFactory::DrawCallback());
+    middle_support->SubmitCompositorFrame(middle_local_surface_id,
+                                          std::move(middle_frame));
   }
 
   // Root surface.
@@ -1306,10 +1322,10 @@
 
   root_frame.render_pass_list[0]->transform_to_root_target.Translate(10, 5);
 
-  factory_.SubmitCompositorFrame(root_local_surface_id_, std::move(root_frame),
-                                 SurfaceFactory::DrawCallback());
+  support_->SubmitCompositorFrame(root_local_surface_id_,
+                                  std::move(root_frame));
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   const RenderPassList& aggregated_pass_list =
@@ -1382,13 +1398,15 @@
                 ->shared_quad_state_list.ElementAt(1)
                 ->clip_rect.ToString());
 
-  middle_factory.EvictSurface();
+  middle_support->EvictFrame();
 }
 
 // Tests that damage rects are aggregated correctly when surfaces change.
 TEST_F(SurfaceAggregatorValidSurfaceTest, AggregateDamageRect) {
-  SurfaceFactory parent_factory(kArbitraryMiddleFrameSinkId, &manager_,
-                                &empty_client_);
+  std::unique_ptr<CompositorFrameSinkSupport> parent_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   test::Quad child_quads[] = {test::Quad::RenderPassQuad(1)};
   test::Pass child_passes[] = {
       test::Pass(child_quads, arraysize(child_quads), 1)};
@@ -1403,11 +1421,10 @@
   child_root_pass_sqs->quad_to_target_transform.Translate(8, 0);
 
   LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_surface_id(child_factory_.frame_sink_id(),
+  SurfaceId child_surface_id(child_support_->frame_sink_id(),
                              child_local_surface_id);
-  child_factory_.SubmitCompositorFrame(child_local_surface_id,
-                                       std::move(child_frame),
-                                       SurfaceFactory::DrawCallback());
+  child_support_->SubmitCompositorFrame(child_local_surface_id,
+                                        std::move(child_frame));
 
   test::Quad parent_surface_quads[] = {
       test::Quad::SurfaceQuad(child_surface_id, InvalidSurfaceId(), 1.f)};
@@ -1421,11 +1438,10 @@
             parent_surface_passes, arraysize(parent_surface_passes));
 
   LocalSurfaceId parent_local_surface_id = allocator_.GenerateId();
-  SurfaceId parent_surface_id(parent_factory.frame_sink_id(),
+  SurfaceId parent_surface_id(parent_support->frame_sink_id(),
                               parent_local_surface_id);
-  parent_factory.SubmitCompositorFrame(parent_local_surface_id,
-                                       std::move(parent_surface_frame),
-                                       SurfaceFactory::DrawCallback());
+  parent_support->SubmitCompositorFrame(parent_local_surface_id,
+                                        std::move(parent_surface_frame));
 
   test::Quad root_surface_quads[] = {
       test::Quad::SurfaceQuad(parent_surface_id, InvalidSurfaceId(), 1.f)};
@@ -1445,10 +1461,10 @@
   root_frame.render_pass_list[0]->damage_rect = gfx::Rect(5, 5, 10, 10);
   root_frame.render_pass_list[1]->damage_rect = gfx::Rect(5, 5, 100, 100);
 
-  factory_.SubmitCompositorFrame(root_local_surface_id_, std::move(root_frame),
-                                 SurfaceFactory::DrawCallback());
+  support_->SubmitCompositorFrame(root_local_surface_id_,
+                                  std::move(root_frame));
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   const RenderPassList& aggregated_pass_list =
@@ -1471,11 +1487,11 @@
     child_root_pass_sqs->quad_to_target_transform.Translate(8, 0);
     child_root_pass->damage_rect = gfx::Rect(10, 10, 10, 10);
 
-    child_factory_.SubmitCompositorFrame(child_local_surface_id,
-                                         std::move(child_frame),
-                                         SurfaceFactory::DrawCallback());
+    child_support_->SubmitCompositorFrame(child_local_surface_id,
+                                          std::move(child_frame));
 
-    SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+    SurfaceId root_surface_id(support_->frame_sink_id(),
+                              root_local_surface_id_);
     CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
     const RenderPassList& aggregated_pass_list =
@@ -1499,9 +1515,8 @@
         ->quad_to_target_transform.Translate(0, 10);
     root_frame.render_pass_list[0]->damage_rect = gfx::Rect(0, 0, 1, 1);
 
-    factory_.SubmitCompositorFrame(root_local_surface_id_,
-                                   std::move(root_frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(root_local_surface_id_,
+                                    std::move(root_frame));
   }
 
   {
@@ -1514,11 +1529,11 @@
         ->quad_to_target_transform.Translate(0, 10);
     root_frame.render_pass_list[0]->damage_rect = gfx::Rect(1, 1, 1, 1);
 
-    factory_.SubmitCompositorFrame(root_local_surface_id_,
-                                   std::move(root_frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(root_local_surface_id_,
+                                    std::move(root_frame));
 
-    SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+    SurfaceId root_surface_id(support_->frame_sink_id(),
+                              root_local_surface_id_);
     CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
     const RenderPassList& aggregated_pass_list =
@@ -1534,7 +1549,8 @@
 
   // No Surface changed, so no damage should be given.
   {
-    SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+    SurfaceId root_surface_id(support_->frame_sink_id(),
+                              root_local_surface_id_);
     CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
     const RenderPassList& aggregated_pass_list =
@@ -1560,7 +1576,7 @@
         gfx::Rect(SurfaceSize())));
   }
 
-  parent_factory.EvictSurface();
+  parent_support->EvictFrame();
 }
 
 // Check that damage is correctly calculated for surfaces.
@@ -1576,11 +1592,12 @@
 
   root_frame.render_pass_list[0]->damage_rect = gfx::Rect(5, 5, 100, 100);
 
-  factory_.SubmitCompositorFrame(root_local_surface_id_, std::move(root_frame),
-                                 SurfaceFactory::DrawCallback());
+  support_->SubmitCompositorFrame(root_local_surface_id_,
+                                  std::move(root_frame));
 
   {
-    SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+    SurfaceId root_surface_id(support_->frame_sink_id(),
+                              root_local_surface_id_);
     CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
     const RenderPassList& aggregated_pass_list =
@@ -1594,7 +1611,7 @@
   }
 
   LocalSurfaceId second_root_local_surface_id = allocator_.GenerateId();
-  SurfaceId second_root_surface_id(factory_.frame_sink_id(),
+  SurfaceId second_root_surface_id(support_->frame_sink_id(),
                                    second_root_local_surface_id);
   {
     test::Quad root_render_pass_quads[] = {test::Quad::SolidColorQuad(1)};
@@ -1608,9 +1625,8 @@
 
     root_frame.render_pass_list[0]->damage_rect = gfx::Rect(1, 2, 3, 4);
 
-    factory_.SubmitCompositorFrame(second_root_local_surface_id,
-                                   std::move(root_frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(second_root_local_surface_id,
+                                    std::move(root_frame));
   }
   {
     CompositorFrame aggregated_frame =
@@ -1647,7 +1663,7 @@
 // Tests that quads outside the damage rect are ignored.
 TEST_F(SurfaceAggregatorPartialSwapTest, IgnoreOutside) {
   LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_surface_id(child_factory_.frame_sink_id(),
+  SurfaceId child_surface_id(child_support_->frame_sink_id(),
                              child_local_surface_id);
   // The child surface has three quads, one with a visible rect of 13,13 4x4 and
   // the other other with a visible rect of 10,10 2x2 (relative to root target
@@ -1685,7 +1701,7 @@
     child_pass_list[2]->quad_list.ElementAt(0)->visible_rect =
         gfx::Rect(0, 0, 2, 2);
 
-    SubmitPassListAsFrame(&child_factory_, child_local_surface_id,
+    SubmitPassListAsFrame(child_support_.get(), child_local_surface_id,
                           &child_pass_list);
   }
 
@@ -1704,10 +1720,11 @@
         ->quad_to_target_transform.Translate(10, 10);
     root_pass->damage_rect = gfx::Rect(0, 0, 1, 1);
 
-    SubmitPassListAsFrame(&factory_, root_local_surface_id_, &root_pass_list);
+    SubmitPassListAsFrame(support_.get(), root_local_surface_id_,
+                          &root_pass_list);
   }
 
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
   CompositorFrame aggregated_frame = aggregator_.Aggregate(root_surface_id);
 
   const RenderPassList& aggregated_pass_list =
@@ -1736,7 +1753,8 @@
     root_pass->shared_quad_state_list.front()
         ->quad_to_target_transform.Translate(10, 10);
     root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
-    SubmitPassListAsFrame(&factory_, root_local_surface_id_, &root_pass_list);
+    SubmitPassListAsFrame(support_.get(), root_local_surface_id_,
+                          &root_pass_list);
   }
 
   {
@@ -1786,7 +1804,7 @@
     child_root_pass->copy_requests.push_back(
         CopyOutputRequest::CreateEmptyRequest());
     child_root_pass->damage_rect = gfx::Rect();
-    SubmitPassListAsFrame(&child_factory_, child_local_surface_id,
+    SubmitPassListAsFrame(child_support_.get(), child_local_surface_id,
                           &child_pass_list);
   }
 
@@ -1846,7 +1864,8 @@
     RenderPass* root_pass = root_pass_list[2].get();
     filter_pass->filters.Append(FilterOperation::CreateBlurFilter(2));
     root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
-    SubmitPassListAsFrame(&factory_, root_local_surface_id_, &root_pass_list);
+    SubmitPassListAsFrame(support_.get(), root_local_surface_id_,
+                          &root_pass_list);
   }
 
   {
@@ -1894,7 +1913,8 @@
         ->quad_to_target_transform.Translate(10, 10);
     pass->background_filters.Append(FilterOperation::CreateBlurFilter(2));
     root_pass->damage_rect = gfx::Rect(10, 10, 2, 2);
-    SubmitPassListAsFrame(&factory_, root_local_surface_id_, &root_pass_list);
+    SubmitPassListAsFrame(support_.get(), root_local_surface_id_,
+                          &root_pass_list);
   }
 
   {
@@ -1938,32 +1958,11 @@
   std::unique_ptr<SurfaceAggregator> aggregator_;
 };
 
-class ResourceTrackingSurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  ResourceTrackingSurfaceFactoryClient() {}
-  ~ResourceTrackingSurfaceFactoryClient() override {}
-
-  void ReturnResources(const ReturnedResourceArray& resources) override {
-    returned_resources_ = resources;
-  }
-
-  ReturnedResourceArray returned_resources() const {
-    return returned_resources_;
-  }
-
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {}
-
- private:
-  ReturnedResourceArray returned_resources_;
-
-  DISALLOW_COPY_AND_ASSIGN(ResourceTrackingSurfaceFactoryClient);
-};
-
 void SubmitCompositorFrameWithResources(ResourceId* resource_ids,
                                         size_t num_resource_ids,
                                         bool valid,
                                         SurfaceId child_id,
-                                        SurfaceFactory* factory,
+                                        CompositorFrameSinkSupport* support,
                                         SurfaceId surface_id) {
   CompositorFrame frame;
   std::unique_ptr<RenderPass> pass = RenderPass::Create();
@@ -2002,27 +2001,29 @@
                  nearest_neighbor, secure_output_only);
   }
   frame.render_pass_list.push_back(std::move(pass));
-  factory->SubmitCompositorFrame(surface_id.local_surface_id(),
-                                 std::move(frame),
-                                 SurfaceFactory::DrawCallback());
+  support->SubmitCompositorFrame(surface_id.local_surface_id(),
+                                 std::move(frame));
 }
 
 TEST_F(SurfaceAggregatorWithResourcesTest, TakeResourcesOneSurface) {
-  ResourceTrackingSurfaceFactoryClient client;
-  SurfaceFactory factory(kArbitraryRootFrameSinkId, &manager_, &client);
+  FakeCompositorFrameSinkSupportClient client;
+  std::unique_ptr<CompositorFrameSinkSupport> support =
+      CompositorFrameSinkSupport::Create(
+          &client, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId local_surface_id(7u, base::UnguessableToken::Create());
-  SurfaceId surface_id(factory.frame_sink_id(), local_surface_id);
+  SurfaceId surface_id(support->frame_sink_id(), local_surface_id);
 
   ResourceId ids[] = {11, 12, 13};
   SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
-                                     &factory, surface_id);
+                                     support.get(), surface_id);
 
   CompositorFrame frame = aggregator_->Aggregate(surface_id);
 
   // Nothing should be available to be returned yet.
   EXPECT_TRUE(client.returned_resources().empty());
 
-  SubmitCompositorFrameWithResources(NULL, 0u, true, SurfaceId(), &factory,
+  SubmitCompositorFrameWithResources(NULL, 0u, true, SurfaceId(), support.get(),
                                      surface_id);
 
   frame = aggregator_->Aggregate(surface_id);
@@ -2035,14 +2036,17 @@
   EXPECT_THAT(returned_ids,
               testing::WhenSorted(testing::ElementsAreArray(ids)));
 
-  factory.EvictSurface();
+  support->EvictFrame();
 }
 
 TEST_F(SurfaceAggregatorWithResourcesTest, TakeInvalidResources) {
-  ResourceTrackingSurfaceFactoryClient client;
-  SurfaceFactory factory(kArbitraryRootFrameSinkId, &manager_, &client);
+  FakeCompositorFrameSinkSupportClient client;
+  std::unique_ptr<CompositorFrameSinkSupport> support =
+      CompositorFrameSinkSupport::Create(
+          &client, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId local_surface_id(7u, base::UnguessableToken::Create());
-  SurfaceId surface_id(factory.frame_sink_id(), local_surface_id);
+  SurfaceId surface_id(support->frame_sink_id(), local_surface_id);
 
   CompositorFrame frame;
   std::unique_ptr<RenderPass> pass = RenderPass::Create();
@@ -2054,42 +2058,47 @@
   resource.is_software = false;
   frame.resource_list.push_back(resource);
   frame.render_pass_list.push_back(std::move(pass));
-  factory.SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                SurfaceFactory::DrawCallback());
+  support->SubmitCompositorFrame(local_surface_id, std::move(frame));
 
   CompositorFrame returned_frame = aggregator_->Aggregate(surface_id);
 
   // Nothing should be available to be returned yet.
   EXPECT_TRUE(client.returned_resources().empty());
 
-  SubmitCompositorFrameWithResources(NULL, 0, true, SurfaceId(), &factory,
+  SubmitCompositorFrameWithResources(NULL, 0, true, SurfaceId(), support.get(),
                                      surface_id);
   ASSERT_EQ(1u, client.returned_resources().size());
   EXPECT_EQ(11u, client.returned_resources()[0].id);
 
-  factory.EvictSurface();
+  support->EvictFrame();
 }
 
 TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
-  ResourceTrackingSurfaceFactoryClient client;
-  SurfaceFactory factory1(FrameSinkId(1, 1), &manager_, &client);
-  SurfaceFactory factory2(FrameSinkId(2, 2), &manager_, &client);
+  FakeCompositorFrameSinkSupportClient client;
+  std::unique_ptr<CompositorFrameSinkSupport> support1 =
+      CompositorFrameSinkSupport::Create(
+          &client, &manager_, FrameSinkId(1, 1), kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> support2 =
+      CompositorFrameSinkSupport::Create(
+          &client, &manager_, FrameSinkId(2, 2), kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId local_frame1_id(7u, base::UnguessableToken::Create());
-  SurfaceId surface1_id(factory1.frame_sink_id(), local_frame1_id);
+  SurfaceId surface1_id(support1->frame_sink_id(), local_frame1_id);
 
   LocalSurfaceId local_frame2_id(8u, base::UnguessableToken::Create());
-  SurfaceId surface2_id(factory2.frame_sink_id(), local_frame2_id);
+  SurfaceId surface2_id(support2->frame_sink_id(), local_frame2_id);
 
   ResourceId ids[] = {11, 12, 13};
   SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
-                                     &factory1, surface1_id);
+                                     support1.get(), surface1_id);
   ResourceId ids2[] = {14, 15, 16};
   SubmitCompositorFrameWithResources(ids2, arraysize(ids2), true, SurfaceId(),
-                                     &factory2, surface2_id);
+                                     support2.get(), surface2_id);
 
   CompositorFrame frame = aggregator_->Aggregate(surface1_id);
 
-  SubmitCompositorFrameWithResources(NULL, 0, true, SurfaceId(), &factory1,
+  SubmitCompositorFrameWithResources(NULL, 0, true, SurfaceId(), support1.get(),
                                      surface1_id);
 
   // Nothing should be available to be returned yet.
@@ -2107,40 +2116,47 @@
               testing::WhenSorted(testing::ElementsAreArray(ids)));
   EXPECT_EQ(3u, resource_provider_->num_resources());
 
-  factory1.EvictSurface();
-  factory2.EvictSurface();
+  support1->EvictFrame();
+  support2->EvictFrame();
 }
 
 // Ensure that aggregator completely ignores Surfaces that reference invalid
 // resources.
 TEST_F(SurfaceAggregatorWithResourcesTest, InvalidChildSurface) {
-  ResourceTrackingSurfaceFactoryClient client;
-  SurfaceFactory root_factory(kArbitraryRootFrameSinkId, &manager_, &client);
-  SurfaceFactory middle_factory(kArbitraryMiddleFrameSinkId, &manager_,
-                                &client);
-  SurfaceFactory child_factory(kArbitraryChildFrameSinkId1, &manager_, &client);
+  std::unique_ptr<CompositorFrameSinkSupport> root_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryRootFrameSinkId, kRootIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> middle_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryMiddleFrameSinkId, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryFrameSinkId1, kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId root_local_surface_id(7u, kArbitraryToken);
-  SurfaceId root_surface_id(root_factory.frame_sink_id(),
+  SurfaceId root_surface_id(root_support->frame_sink_id(),
                             root_local_surface_id);
   LocalSurfaceId middle_local_surface_id(8u, kArbitraryToken);
-  SurfaceId middle_surface_id(middle_factory.frame_sink_id(),
+  SurfaceId middle_surface_id(middle_support->frame_sink_id(),
                               middle_local_surface_id);
   LocalSurfaceId child_local_surface_id(9u, kArbitraryToken);
-  SurfaceId child_surface_id(child_factory.frame_sink_id(),
+  SurfaceId child_surface_id(child_support->frame_sink_id(),
                              child_local_surface_id);
 
   ResourceId ids[] = {14, 15, 16};
   SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
-                                     &child_factory, child_surface_id);
+                                     child_support.get(), child_surface_id);
 
   ResourceId ids2[] = {17, 18, 19};
   SubmitCompositorFrameWithResources(ids2, arraysize(ids2), false,
-                                     child_surface_id, &middle_factory,
+                                     child_surface_id, middle_support.get(),
                                      middle_surface_id);
 
   ResourceId ids3[] = {20, 21, 22};
   SubmitCompositorFrameWithResources(ids3, arraysize(ids3), true,
-                                     middle_surface_id, &root_factory,
+                                     middle_surface_id, root_support.get(),
                                      root_surface_id);
 
   CompositorFrame frame;
@@ -2151,7 +2167,7 @@
   EXPECT_EQ(1u, pass_list->back()->shared_quad_state_list.size());
   EXPECT_EQ(3u, pass_list->back()->quad_list.size());
   SubmitCompositorFrameWithResources(ids2, arraysize(ids), true,
-                                     child_surface_id, &middle_factory,
+                                     child_surface_id, middle_support.get(),
                                      middle_surface_id);
 
   frame = aggregator_->Aggregate(root_surface_id);
@@ -2161,24 +2177,29 @@
   EXPECT_EQ(3u, pass_list->back()->shared_quad_state_list.size());
   EXPECT_EQ(9u, pass_list->back()->quad_list.size());
 
-  root_factory.EvictSurface();
-  middle_factory.EvictSurface();
-  child_factory.EvictSurface();
+  root_support->EvictFrame();
+  middle_support->EvictFrame();
+  child_support->EvictFrame();
 }
 
 TEST_F(SurfaceAggregatorWithResourcesTest, SecureOutputTexture) {
-  ResourceTrackingSurfaceFactoryClient client;
-  SurfaceFactory factory1(FrameSinkId(1, 1), &manager_, &client);
-  SurfaceFactory factory2(FrameSinkId(2, 2), &manager_, &client);
+  std::unique_ptr<CompositorFrameSinkSupport> support1 =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, FrameSinkId(1, 1), kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> support2 =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, FrameSinkId(2, 2), kChildIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId local_frame1_id(7u, base::UnguessableToken::Create());
-  SurfaceId surface1_id(factory1.frame_sink_id(), local_frame1_id);
+  SurfaceId surface1_id(support1->frame_sink_id(), local_frame1_id);
 
   LocalSurfaceId local_frame2_id(8u, base::UnguessableToken::Create());
-  SurfaceId surface2_id(factory2.frame_sink_id(), local_frame2_id);
+  SurfaceId surface2_id(support2->frame_sink_id(), local_frame2_id);
 
   ResourceId ids[] = {11, 12, 13};
   SubmitCompositorFrameWithResources(ids, arraysize(ids), true, SurfaceId(),
-                                     &factory1, surface1_id);
+                                     support1.get(), surface1_id);
 
   CompositorFrame frame = aggregator_->Aggregate(surface1_id);
 
@@ -2201,8 +2222,7 @@
     CompositorFrame frame;
     frame.render_pass_list.push_back(std::move(pass));
 
-    factory2.SubmitCompositorFrame(local_frame2_id, std::move(frame),
-                                   SurfaceFactory::DrawCallback());
+    support2->SubmitCompositorFrame(local_frame2_id, std::move(frame));
   }
 
   frame = aggregator_->Aggregate(surface2_id);
@@ -2228,8 +2248,8 @@
   // Output is insecure, so texture should be drawn.
   EXPECT_EQ(DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
 
-  factory1.EvictSurface();
-  factory2.EvictSurface();
+  support1->EvictFrame();
+  support2->EvictFrame();
 }
 
 // Ensure that the render passes have correct color spaces.
@@ -2244,10 +2264,10 @@
   gfx::ColorSpace color_space2 = gfx::ColorSpace::CreateSRGB();
   gfx::ColorSpace color_space3 = gfx::ColorSpace::CreateSCRGBLinear();
 
-  SubmitCompositorFrame(&factory_, passes, arraysize(passes),
+  SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
                         root_local_surface_id_);
 
-  SurfaceId surface_id(factory_.frame_sink_id(), root_local_surface_id_);
+  SurfaceId surface_id(support_->frame_sink_id(), root_local_surface_id_);
 
   CompositorFrame aggregated_frame;
   aggregator_.SetOutputColorSpace(color_space1, color_space1);
diff --git a/cc/surfaces/surface_hittest_unittest.cc b/cc/surfaces/surface_hittest_unittest.cc
index fc27635c..312a7ae 100644
--- a/cc/surfaces/surface_hittest_unittest.cc
+++ b/cc/surfaces/surface_hittest_unittest.cc
@@ -5,10 +5,9 @@
 #include <stddef.h>
 
 #include "cc/output/compositor_frame.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
 #include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_hittest.h"
 #include "cc/surfaces/surface_manager.h"
 #include "cc/test/surface_hittest_test_helpers.h"
@@ -20,7 +19,11 @@
 
 namespace {
 
-static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
+constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
+constexpr bool kIsRoot = true;
+constexpr bool kIsChildRoot = false;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = true;
 
 struct TestCase {
   SurfaceId input_surface_id;
@@ -62,9 +65,11 @@
 // not crash.
 TEST(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) {
   SurfaceManager manager;
-  EmptySurfaceFactoryClient client;
   FrameSinkId root_frame_sink_id(kArbitraryFrameSinkId);
-  SurfaceFactory root_factory(root_frame_sink_id, &manager, &client);
+  std::unique_ptr<CompositorFrameSinkSupport> root_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, kArbitraryFrameSinkId, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Creates a root surface.
   gfx::Rect root_rect(300, 300);
@@ -86,9 +91,8 @@
   LocalSurfaceIdAllocator root_allocator;
   LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
   SurfaceId root_surface_id(root_frame_sink_id, root_local_surface_id);
-  root_factory.SubmitCompositorFrame(root_local_surface_id,
-                                     std::move(root_frame),
-                                     SurfaceFactory::DrawCallback());
+  root_support->SubmitCompositorFrame(root_local_surface_id,
+                                      std::move(root_frame));
 
   {
     SurfaceHittest hittest(nullptr, &manager);
@@ -99,16 +103,18 @@
                   root_surface_id, gfx::Point(100, 100), &transform));
   }
 
-  root_factory.EvictSurface();
+  root_support->EvictFrame();
 }
 
 TEST(SurfaceHittestTest, Hittest_SingleSurface) {
   SurfaceManager manager;
 
   // Set up root FrameSink.
-  EmptySurfaceFactoryClient root_client;
   FrameSinkId root_frame_sink_id(1, 1);
-  SurfaceFactory root_factory(root_frame_sink_id, &manager, &root_client);
+  std::unique_ptr<CompositorFrameSinkSupport> root_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, root_frame_sink_id, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Creates a root surface.
   gfx::Rect root_rect(300, 300);
@@ -119,9 +125,8 @@
   LocalSurfaceIdAllocator root_allocator;
   LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
   SurfaceId root_surface_id(root_frame_sink_id, root_local_surface_id);
-  root_factory.SubmitCompositorFrame(root_local_surface_id,
-                                     std::move(root_frame),
-                                     SurfaceFactory::DrawCallback());
+  root_support->SubmitCompositorFrame(root_local_surface_id,
+                                      std::move(root_frame));
   TestCase tests[] = {
     {
       root_surface_id,
@@ -133,21 +138,25 @@
 
   RunTests(nullptr, &manager, tests, arraysize(tests));
 
-  root_factory.EvictSurface();
+  root_support->EvictFrame();
 }
 
 TEST(SurfaceHittestTest, Hittest_ChildSurface) {
   SurfaceManager manager;
 
   // Set up root FrameSink.
-  EmptySurfaceFactoryClient root_client;
   FrameSinkId root_frame_sink_id(1, 1);
-  SurfaceFactory root_factory(root_frame_sink_id, &manager, &root_client);
+  std::unique_ptr<CompositorFrameSinkSupport> root_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, root_frame_sink_id, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Set up child FrameSink.
-  EmptySurfaceFactoryClient child_client;
   FrameSinkId child_frame_sink_id(2, 2);
-  SurfaceFactory child_factory(child_frame_sink_id, &manager, &child_client);
+  std::unique_ptr<CompositorFrameSinkSupport> child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, child_frame_sink_id, kIsChildRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Creates a root surface.
   gfx::Rect root_rect(300, 300);
@@ -172,9 +181,8 @@
   LocalSurfaceIdAllocator root_allocator;
   LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
   SurfaceId root_surface_id(root_frame_sink_id, root_local_surface_id);
-  root_factory.SubmitCompositorFrame(root_local_surface_id,
-                                     std::move(root_frame),
-                                     SurfaceFactory::DrawCallback());
+  root_support->SubmitCompositorFrame(root_local_surface_id,
+                                      std::move(root_frame));
 
   // Creates a child surface.
   RenderPass* child_pass = nullptr;
@@ -191,9 +199,8 @@
       root_rect, child_solid_quad_rect);
 
   // Submit the frame.
-  child_factory.SubmitCompositorFrame(child_local_surface_id,
-                                      std::move(child_frame),
-                                      SurfaceFactory::DrawCallback());
+  child_support->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
 
   TestCase tests[] = {
     {
@@ -246,9 +253,8 @@
                         root_rect,
                         child_rect,
                         child_surface_id);
-  root_factory.SubmitCompositorFrame(root_local_surface_id,
-                                     std::move(root_frame),
-                                     SurfaceFactory::DrawCallback());
+  root_support->SubmitCompositorFrame(root_local_surface_id,
+                                      std::move(root_frame));
 
   // Verify that point (100, 100) no longer falls on the child surface.
   // Verify that the transform to the child surface's space has also shifted.
@@ -272,8 +278,8 @@
     EXPECT_EQ(gfx::Point(25, 25), point_in_target_space);
   }
 
-  root_factory.EvictSurface();
-  child_factory.EvictSurface();
+  root_support->EvictFrame();
+  child_support->EvictFrame();
 }
 
 // This test verifies that hit testing will progress to the next quad if it
@@ -282,14 +288,18 @@
   SurfaceManager manager;
 
   // Set up root FrameSink.
-  EmptySurfaceFactoryClient root_client;
   FrameSinkId root_frame_sink_id(1, 1);
-  SurfaceFactory root_factory(root_frame_sink_id, &manager, &root_client);
+  std::unique_ptr<CompositorFrameSinkSupport> root_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, root_frame_sink_id, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Set up child FrameSink.
-  EmptySurfaceFactoryClient child_client;
   FrameSinkId child_frame_sink_id(2, 2);
-  SurfaceFactory child_factory(child_frame_sink_id, &manager, &child_client);
+  std::unique_ptr<CompositorFrameSinkSupport> child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, child_frame_sink_id, kIsChildRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Creates a root surface.
   gfx::Rect root_rect(300, 300);
@@ -319,9 +329,8 @@
   LocalSurfaceIdAllocator root_allocator;
   LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
   SurfaceId root_surface_id(root_frame_sink_id, root_local_surface_id);
-  root_factory.SubmitCompositorFrame(root_local_surface_id,
-                                     std::move(root_frame),
-                                     SurfaceFactory::DrawCallback());
+  root_support->SubmitCompositorFrame(root_local_surface_id,
+                                      std::move(root_frame));
 
   // Creates a child surface.
   RenderPass* child_pass = nullptr;
@@ -338,9 +347,8 @@
                            child_solid_quad_rect);
 
   // Submit the frame.
-  child_factory.SubmitCompositorFrame(child_local_surface_id,
-                                      std::move(child_frame),
-                                      SurfaceFactory::DrawCallback());
+  child_support->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
 
   TestCase tests[] = {
     {
@@ -383,15 +391,17 @@
 
   RunTests(nullptr, &manager, tests, arraysize(tests));
 
-  root_factory.EvictSurface();
-  child_factory.EvictSurface();
+  root_support->EvictFrame();
+  child_support->EvictFrame();
 }
 
 TEST(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
   SurfaceManager manager;
-  EmptySurfaceFactoryClient client;
   FrameSinkId root_frame_sink_id(kArbitraryFrameSinkId);
-  SurfaceFactory factory(root_frame_sink_id, &manager, &client);
+  std::unique_ptr<CompositorFrameSinkSupport> support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, root_frame_sink_id, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Create a CompostiorFrame with two RenderPasses.
   gfx::Rect root_rect(300, 300);
@@ -437,8 +447,7 @@
   LocalSurfaceIdAllocator root_allocator;
   LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
   SurfaceId root_surface_id(root_frame_sink_id, root_local_surface_id);
-  factory.SubmitCompositorFrame(root_local_surface_id, std::move(root_frame),
-                                SurfaceFactory::DrawCallback());
+  support->SubmitCompositorFrame(root_local_surface_id, std::move(root_frame));
 
   TestCase tests[] = {
     // These tests just miss the RenderPassDrawQuad.
@@ -486,21 +495,25 @@
 
   RunTests(nullptr, &manager, tests, arraysize(tests));
 
-  factory.EvictSurface();
+  support->EvictFrame();
 }
 
 TEST(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
   SurfaceManager manager;
 
   // Set up root FrameSink.
-  EmptySurfaceFactoryClient root_client;
   FrameSinkId root_frame_sink_id(1, 1);
-  SurfaceFactory root_factory(root_frame_sink_id, &manager, &root_client);
+  std::unique_ptr<CompositorFrameSinkSupport> root_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, root_frame_sink_id, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Set up child FrameSink.
-  EmptySurfaceFactoryClient child_client;
   FrameSinkId child_frame_sink_id(2, 2);
-  SurfaceFactory child_factory(child_frame_sink_id, &manager, &child_client);
+  std::unique_ptr<CompositorFrameSinkSupport> child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, child_frame_sink_id, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   // Creates a root surface.
   gfx::Rect root_rect(300, 300);
@@ -524,9 +537,8 @@
   LocalSurfaceIdAllocator root_allocator;
   LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
   SurfaceId root_surface_id(root_frame_sink_id, root_local_surface_id);
-  root_factory.SubmitCompositorFrame(root_local_surface_id,
-                                     std::move(root_frame),
-                                     SurfaceFactory::DrawCallback());
+  root_support->SubmitCompositorFrame(root_local_surface_id,
+                                      std::move(root_frame));
 
   // Creates a child surface.
   RenderPass* child_pass = nullptr;
@@ -541,9 +553,8 @@
       root_rect, child_solid_quad_rect);
 
   // Submit the frame.
-  child_factory.SubmitCompositorFrame(child_local_surface_id,
-                                      std::move(child_frame),
-                                      SurfaceFactory::DrawCallback());
+  child_support->SubmitCompositorFrame(child_local_surface_id,
+                                       std::move(child_frame));
 
   TestCase test_expectations_without_insets[] = {
       {root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5)},
@@ -622,8 +633,8 @@
   EXPECT_EQ(0, accept_delegate.reject_target_overrides());
   EXPECT_EQ(2, accept_delegate.accept_target_overrides());
 
-  root_factory.EvictSurface();
-  child_factory.EvictSurface();
+  root_support->EvictFrame();
+  child_support->EvictFrame();
 }
 
 }  // namespace cc
diff --git a/cc/surfaces/surface_manager_ref_unittest.cc b/cc/surfaces/surface_manager_ref_unittest.cc
index fb21ce3..eb678f8 100644
--- a/cc/surfaces/surface_manager_ref_unittest.cc
+++ b/cc/surfaces/surface_manager_ref_unittest.cc
@@ -8,9 +8,8 @@
 #include <vector>
 
 #include "base/memory/ptr_util.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/surface.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surface_manager.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -29,12 +28,6 @@
 constexpr FrameSinkId kFrameSink2(2, 0);
 constexpr FrameSinkId kFrameSink3(3, 0);
 
-class StubSurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  void ReturnResources(const ReturnedResourceArray& resources) override {}
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {}
-};
-
 }  // namespace
 
 // Tests for reference tracking in SurfaceManager.
@@ -43,27 +36,38 @@
   SurfaceManager& manager() { return *manager_; }
 
   // Creates a new Surface with the provided |frame_sink_id| and |local_id|.
-  // Will first create a SurfaceFactory for |frame_sink_id| if necessary.
+  // Will first create a Surfacesupport for |frame_sink_id| if necessary.
   SurfaceId CreateSurface(const FrameSinkId& frame_sink_id, uint32_t local_id) {
     LocalSurfaceId local_surface_id(local_id,
                                     base::UnguessableToken::Deserialize(0, 1u));
-    GetFactory(frame_sink_id)
-        .SubmitCompositorFrame(local_surface_id, CompositorFrame(),
-                               SurfaceFactory::DrawCallback());
+    GetCompositorFrameSinkSupport(frame_sink_id)
+        .SubmitCompositorFrame(local_surface_id, CompositorFrame());
     return SurfaceId(frame_sink_id, local_surface_id);
   }
 
   // Destroy Surface with |surface_id|.
   void DestroySurface(const SurfaceId& surface_id) {
-    GetFactory(surface_id.frame_sink_id()).EvictSurface();
+    GetCompositorFrameSinkSupport(surface_id.frame_sink_id()).EvictFrame();
   }
 
-  SurfaceFactory& GetFactory(const FrameSinkId& frame_sink_id) {
-    auto& factory_ptr = factories_[frame_sink_id];
-    if (!factory_ptr)
-      factory_ptr = base::MakeUnique<SurfaceFactory>(frame_sink_id,
-                                                     manager_.get(), &client_);
-    return *factory_ptr;
+  CompositorFrameSinkSupport& GetCompositorFrameSinkSupport(
+      const FrameSinkId& frame_sink_id) {
+    auto& support_ptr = supports_[frame_sink_id];
+    if (!support_ptr) {
+      constexpr bool is_root = false;
+      constexpr bool handles_frame_sink_id_invalidation = true;
+      constexpr bool needs_sync_points = true;
+      support_ptr = CompositorFrameSinkSupport::Create(
+          nullptr, manager_.get(), frame_sink_id, is_root,
+          handles_frame_sink_id_invalidation, needs_sync_points);
+    }
+    return *support_ptr;
+  }
+
+  void DestroyCompositorFrameSinkSupport(const FrameSinkId& frame_sink_id) {
+    auto support_ptr = supports_.find(frame_sink_id);
+    ASSERT_NE(support_ptr, supports_.end());
+    supports_.erase(support_ptr);
   }
 
   void RemoveSurfaceReference(const SurfaceId& parent_id,
@@ -105,18 +109,17 @@
         SurfaceManager::LifetimeType::REFERENCES);
   }
   void TearDown() override {
-    for (auto& factory : factories_)
-      factory.second->EvictSurface();
-    factories_.clear();
+    for (auto& support : supports_)
+      support.second->EvictFrame();
+    supports_.clear();
     manager_.reset();
   }
 
   std::unordered_map<FrameSinkId,
-                     std::unique_ptr<SurfaceFactory>,
+                     std::unique_ptr<CompositorFrameSinkSupport>,
                      FrameSinkIdHash>
-      factories_;
+      supports_;
   std::unique_ptr<SurfaceManager> manager_;
-  StubSurfaceFactoryClient client_;
 };
 
 TEST_F(SurfaceManagerRefTest, AddReference) {
@@ -464,7 +467,7 @@
 
   // When |kFrameSink1| is invalidated it shouldn't change the surface
   // references.
-  manager().InvalidateFrameSinkId(kFrameSink1);
+  DestroyCompositorFrameSinkSupport(kFrameSink1);
   ASSERT_THAT(GetReferencesFor(id1), UnorderedElementsAre(parent_id));
 }
 
@@ -499,7 +502,7 @@
   // If the parent client crashes then the CompositorFrameSink connection will
   // be closed and the FrameSinkId invalidated. The temporary reference
   // |kFrameSink1| owns to |id2a| will be removed.
-  manager().InvalidateFrameSinkId(kFrameSink1);
+  DestroyCompositorFrameSinkSupport(kFrameSink1);
   ASSERT_THAT(GetAllTempReferences(), UnorderedElementsAre(id1b));
 
   // If the parent has crashed then the window server will have already removed
diff --git a/cc/surfaces/surface_unittest.cc b/cc/surfaces/surface_unittest.cc
index c20f313d..e40cc05 100644
--- a/cc/surfaces/surface_unittest.cc
+++ b/cc/surfaces/surface_unittest.cc
@@ -5,10 +5,9 @@
 #include "cc/surfaces/surface.h"
 #include "base/memory/ptr_util.h"
 #include "cc/output/copy_output_result.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
 #include "cc/surfaces/surface_dependency_tracker.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_manager.h"
 #include "cc/test/begin_frame_args_test.h"
 #include "cc/test/fake_external_begin_frame_source.h"
@@ -19,36 +18,23 @@
 namespace cc {
 namespace {
 
-static constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
-
-class FakeSurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  FakeSurfaceFactoryClient() : begin_frame_source_(nullptr) {}
-
-  void ReturnResources(const ReturnedResourceArray& resources) override {}
-
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {
-    begin_frame_source_ = begin_frame_source;
-  }
-
-  BeginFrameSource* begin_frame_source() { return begin_frame_source_; }
-
- private:
-  BeginFrameSource* begin_frame_source_;
-};
+constexpr FrameSinkId kArbitraryFrameSinkId(1, 1);
+constexpr bool kIsRoot = true;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = true;
 
 TEST(SurfaceTest, SurfaceLifetime) {
   SurfaceManager manager;
-  FakeSurfaceFactoryClient surface_factory_client;
-  SurfaceFactory factory(kArbitraryFrameSinkId, &manager,
-                         &surface_factory_client);
+  std::unique_ptr<CompositorFrameSinkSupport> support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, kArbitraryFrameSinkId, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
   SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
-  factory.SubmitCompositorFrame(local_surface_id, CompositorFrame(),
-                                SurfaceFactory::DrawCallback());
+  support->SubmitCompositorFrame(local_surface_id, CompositorFrame());
   EXPECT_TRUE(manager.GetSurfaceForId(surface_id));
-  factory.EvictSurface();
+  support->EvictFrame();
 
   EXPECT_EQ(NULL, manager.GetSurfaceForId(surface_id));
 }
@@ -71,21 +57,21 @@
 // aggregated on the next frame.
 TEST(SurfaceTest, CopyRequestLifetime) {
   SurfaceManager manager;
-  FakeSurfaceFactoryClient surface_factory_client;
-  SurfaceFactory factory(kArbitraryFrameSinkId, &manager,
-                         &surface_factory_client);
+  std::unique_ptr<CompositorFrameSinkSupport> support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager, kArbitraryFrameSinkId, kIsRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
 
   LocalSurfaceId local_surface_id(6, base::UnguessableToken::Create());
   SurfaceId surface_id(kArbitraryFrameSinkId, local_surface_id);
   CompositorFrame frame;
   frame.render_pass_list.push_back(RenderPass::Create());
-  factory.SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                SurfaceFactory::DrawCallback());
+  support->SubmitCompositorFrame(local_surface_id, std::move(frame));
   Surface* surface = manager.GetSurfaceForId(surface_id);
   ASSERT_TRUE(!!surface);
 
   bool copy_called = false;
-  factory.RequestCopyOfSurface(CopyOutputRequest::CreateRequest(
+  support->RequestCopyOfSurface(CopyOutputRequest::CreateRequest(
       base::Bind(&TestCopyResultCallback, &copy_called)));
   EXPECT_TRUE(manager.GetSurfaceForId(surface_id));
   EXPECT_FALSE(copy_called);
@@ -99,8 +85,7 @@
     frame.render_pass_list.back()->id = i * 3 + start_id + 1;
     frame.render_pass_list.push_back(RenderPass::Create());
     frame.render_pass_list.back()->id = i * 3 + start_id + 2;
-    factory.SubmitCompositorFrame(local_surface_id, std::move(frame),
-                                  SurfaceFactory::DrawCallback());
+    support->SubmitCompositorFrame(local_surface_id, std::move(frame));
   }
 
   int last_pass_id = (max_frame - 1) * 3 + start_id + 2;
@@ -120,7 +105,7 @@
   copy_requests.find(last_pass_id)->second->SendEmptyResult();
   EXPECT_TRUE(copy_called);
 
-  factory.EvictSurface();
+  support->EvictFrame();
 }
 
 }  // namespace
diff --git a/cc/surfaces/surfaces_pixeltest.cc b/cc/surfaces/surfaces_pixeltest.cc
index b980980..0b81474c 100644
--- a/cc/surfaces/surfaces_pixeltest.cc
+++ b/cc/surfaces/surfaces_pixeltest.cc
@@ -6,11 +6,10 @@
 #include "cc/quads/render_pass.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
+#include "cc/surfaces/compositor_frame_sink_support.h"
 #include "cc/surfaces/local_surface_id_allocator.h"
 #include "cc/surfaces/surface.h"
 #include "cc/surfaces/surface_aggregator.h"
-#include "cc/surfaces/surface_factory.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_manager.h"
 #include "cc/test/pixel_comparator.h"
 #include "cc/test/pixel_test.h"
@@ -21,28 +20,31 @@
 namespace cc {
 namespace {
 
-static constexpr FrameSinkId kArbitraryRootFrameSinkId(1, 1);
-static constexpr FrameSinkId kArbitraryChildFrameSinkId(2, 2);
-static constexpr FrameSinkId kArbitraryLeftFrameSinkId(3, 3);
-static constexpr FrameSinkId kArbitraryRightFrameSinkId(4, 4);
-
-class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  void ReturnResources(const ReturnedResourceArray& resources) override {}
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {}
-};
+constexpr FrameSinkId kArbitraryRootFrameSinkId(1, 1);
+constexpr FrameSinkId kArbitraryChildFrameSinkId(2, 2);
+constexpr FrameSinkId kArbitraryLeftFrameSinkId(3, 3);
+constexpr FrameSinkId kArbitraryRightFrameSinkId(4, 4);
+constexpr bool kIsRoot = true;
+constexpr bool kIsChildRoot = false;
+constexpr bool kHandlesFrameSinkIdInvalidation = true;
+constexpr bool kNeedsSyncPoints = true;
 
 class SurfacesPixelTest : public RendererPixelTest<GLRenderer> {
  public:
   SurfacesPixelTest()
-      : factory_(kArbitraryRootFrameSinkId, &manager_, &client_) {}
-  ~SurfacesPixelTest() override { factory_.EvictSurface(); }
+      : support_(
+            CompositorFrameSinkSupport::Create(nullptr,
+                                               &manager_,
+                                               kArbitraryRootFrameSinkId,
+                                               kIsRoot,
+                                               kHandlesFrameSinkIdInvalidation,
+                                               kNeedsSyncPoints)) {}
+  ~SurfacesPixelTest() override { support_->EvictFrame(); }
 
  protected:
   SurfaceManager manager_;
   LocalSurfaceIdAllocator allocator_;
-  EmptySurfaceFactoryClient client_;
-  SurfaceFactory factory_;
+  std::unique_ptr<CompositorFrameSinkSupport> support_;
 };
 
 SharedQuadState* CreateAndAppendTestSharedQuadState(
@@ -85,9 +87,8 @@
   root_frame.render_pass_list.push_back(std::move(pass));
 
   LocalSurfaceId root_local_surface_id = allocator_.GenerateId();
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id);
-  factory_.SubmitCompositorFrame(root_local_surface_id, std::move(root_frame),
-                                 SurfaceFactory::DrawCallback());
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id);
+  support_->SubmitCompositorFrame(root_local_surface_id, std::move(root_frame));
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get(), true);
   CompositorFrame aggregated_frame = aggregator.Aggregate(root_surface_id);
@@ -103,12 +104,16 @@
 // Draws a frame with simple surface embedding.
 TEST_F(SurfacesPixelTest, DrawSimpleAggregatedFrame) {
   gfx::Size child_size(200, 100);
-  SurfaceFactory child_factory(kArbitraryChildFrameSinkId, &manager_, &client_);
+  std::unique_ptr<CompositorFrameSinkSupport> child_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryChildFrameSinkId, kIsChildRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+
   LocalSurfaceId child_local_surface_id = allocator_.GenerateId();
-  SurfaceId child_surface_id(child_factory.frame_sink_id(),
+  SurfaceId child_surface_id(child_support->frame_sink_id(),
                              child_local_surface_id);
   LocalSurfaceId root_local_surface_id = allocator_.GenerateId();
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id);
 
   {
     gfx::Rect rect(device_viewport_size_);
@@ -138,8 +143,8 @@
     CompositorFrame root_frame;
     root_frame.render_pass_list.push_back(std::move(pass));
 
-    factory_.SubmitCompositorFrame(root_local_surface_id, std::move(root_frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(root_local_surface_id,
+                                    std::move(root_frame));
   }
 
   {
@@ -163,9 +168,8 @@
     CompositorFrame child_frame;
     child_frame.render_pass_list.push_back(std::move(pass));
 
-    child_factory.SubmitCompositorFrame(child_local_surface_id,
-                                        std::move(child_frame),
-                                        SurfaceFactory::DrawCallback());
+    child_support->SubmitCompositorFrame(child_local_surface_id,
+                                         std::move(child_frame));
   }
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get(), true);
@@ -178,7 +182,7 @@
                            base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")),
                            pixel_comparator));
 
-  child_factory.EvictSurface();
+  child_support->EvictFrame();
 }
 
 // Tests a surface quad that has a non-identity transform into its pass.
@@ -192,14 +196,21 @@
   //                 bottom_blue_quad (100x100 @ 0x100)
   //   right_child -> top_blue_quad (100x100 @ 0x0),
   //                  bottom_green_quad (100x100 @ 0x100)
-  SurfaceFactory left_factory(kArbitraryLeftFrameSinkId, &manager_, &client_);
-  SurfaceFactory right_factory(kArbitraryRightFrameSinkId, &manager_, &client_);
+  std::unique_ptr<CompositorFrameSinkSupport> left_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryLeftFrameSinkId, kIsChildRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
+  std::unique_ptr<CompositorFrameSinkSupport> right_support =
+      CompositorFrameSinkSupport::Create(
+          nullptr, &manager_, kArbitraryRightFrameSinkId, kIsChildRoot,
+          kHandlesFrameSinkIdInvalidation, kNeedsSyncPoints);
   LocalSurfaceId left_child_local_id = allocator_.GenerateId();
-  SurfaceId left_child_id(left_factory.frame_sink_id(), left_child_local_id);
+  SurfaceId left_child_id(left_support->frame_sink_id(), left_child_local_id);
   LocalSurfaceId right_child_local_id = allocator_.GenerateId();
-  SurfaceId right_child_id(right_factory.frame_sink_id(), right_child_local_id);
+  SurfaceId right_child_id(right_support->frame_sink_id(),
+                           right_child_local_id);
   LocalSurfaceId root_local_surface_id = allocator_.GenerateId();
-  SurfaceId root_surface_id(factory_.frame_sink_id(), root_local_surface_id);
+  SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id);
 
   {
     gfx::Rect rect(device_viewport_size_);
@@ -232,8 +243,8 @@
     CompositorFrame root_frame;
     root_frame.render_pass_list.push_back(std::move(pass));
 
-    factory_.SubmitCompositorFrame(root_local_surface_id, std::move(root_frame),
-                                   SurfaceFactory::DrawCallback());
+    support_->SubmitCompositorFrame(root_local_surface_id,
+                                    std::move(root_frame));
   }
 
   {
@@ -265,9 +276,8 @@
     CompositorFrame child_frame;
     child_frame.render_pass_list.push_back(std::move(pass));
 
-    left_factory.SubmitCompositorFrame(left_child_local_id,
-                                       std::move(child_frame),
-                                       SurfaceFactory::DrawCallback());
+    left_support->SubmitCompositorFrame(left_child_local_id,
+                                        std::move(child_frame));
   }
 
   {
@@ -299,9 +309,8 @@
     CompositorFrame child_frame;
     child_frame.render_pass_list.push_back(std::move(pass));
 
-    right_factory.SubmitCompositorFrame(right_child_local_id,
-                                        std::move(child_frame),
-                                        SurfaceFactory::DrawCallback());
+    right_support->SubmitCompositorFrame(right_child_local_id,
+                                         std::move(child_frame));
   }
 
   SurfaceAggregator aggregator(&manager_, resource_provider_.get(), true);
@@ -315,8 +324,8 @@
       base::FilePath(FILE_PATH_LITERAL("four_blue_green_checkers.png")),
       pixel_comparator));
 
-  left_factory.EvictSurface();
-  right_factory.EvictSurface();
+  left_support->EvictFrame();
+  right_support->EvictFrame();
 }
 
 }  // namespace
diff --git a/cc/test/fake_compositor_frame_sink_support_client.cc b/cc/test/fake_compositor_frame_sink_support_client.cc
new file mode 100644
index 0000000..ab502e8
--- /dev/null
+++ b/cc/test/fake_compositor_frame_sink_support_client.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/fake_compositor_frame_sink_support_client.h"
+
+#include "cc/surfaces/surface_manager.h"
+
+namespace cc {
+
+FakeCompositorFrameSinkSupportClient::FakeCompositorFrameSinkSupportClient() =
+    default;
+FakeCompositorFrameSinkSupportClient::~FakeCompositorFrameSinkSupportClient() =
+    default;
+
+void FakeCompositorFrameSinkSupportClient::DidReceiveCompositorFrameAck(
+    const ReturnedResourceArray& resources) {
+  returned_resources_ = resources;
+}
+
+void FakeCompositorFrameSinkSupportClient::OnBeginFrame(
+    const BeginFrameArgs& args) {}
+
+void FakeCompositorFrameSinkSupportClient::ReclaimResources(
+    const ReturnedResourceArray& resources) {
+  returned_resources_ = resources;
+}
+
+void FakeCompositorFrameSinkSupportClient::WillDrawSurface(
+    const LocalSurfaceId& local_surface_id,
+    const gfx::Rect& damage_rect) {
+  last_local_surface_id_ = local_surface_id;
+  last_damage_rect_ = damage_rect;
+}
+
+};  // namespace cc
diff --git a/cc/test/fake_compositor_frame_sink_support_client.h b/cc/test/fake_compositor_frame_sink_support_client.h
new file mode 100644
index 0000000..444315f
--- /dev/null
+++ b/cc/test/fake_compositor_frame_sink_support_client.h
@@ -0,0 +1,46 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_FAKE_COMPOSITOR_FRAME_SINK_SUPPORT_CLIENT_H_
+#define CC_TEST_FAKE_COMPOSITOR_FRAME_SINK_SUPPORT_CLIENT_H_
+
+#include "cc/surfaces/compositor_frame_sink_support_client.h"
+#include "cc/surfaces/local_surface_id.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace cc {
+
+class FakeCompositorFrameSinkSupportClient
+    : public CompositorFrameSinkSupportClient {
+ public:
+  FakeCompositorFrameSinkSupportClient();
+  ~FakeCompositorFrameSinkSupportClient() override;
+
+  // CompositorFrameSinkSupportClient implementation.
+  void DidReceiveCompositorFrameAck(
+      const ReturnedResourceArray& resources) override;
+  void OnBeginFrame(const BeginFrameArgs& args) override;
+  void ReclaimResources(const ReturnedResourceArray& resources) override;
+  void WillDrawSurface(const LocalSurfaceId& local_surface_id,
+                       const gfx::Rect& damage_rect) override;
+
+  const gfx::Rect& last_damage_rect() const { return last_damage_rect_; }
+  const LocalSurfaceId& last_local_surface_id() const {
+    return last_local_surface_id_;
+  }
+  const ReturnedResourceArray& returned_resources() const {
+    return returned_resources_;
+  }
+
+ private:
+  gfx::Rect last_damage_rect_;
+  LocalSurfaceId last_local_surface_id_;
+  ReturnedResourceArray returned_resources_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSinkSupportClient);
+};
+
+}  // namespace cc
+
+#endif  // CC_TEST_FAKE_COMPOSITOR_FRAME_SINK_SUPPORT_CLIENT_H_
diff --git a/cc/test/surface_hittest_test_helpers.h b/cc/test/surface_hittest_test_helpers.h
index 2a5b754..6ec3c36c3 100644
--- a/cc/test/surface_hittest_test_helpers.h
+++ b/cc/test/surface_hittest_test_helpers.h
@@ -10,7 +10,6 @@
 
 #include "base/macros.h"
 #include "cc/quads/render_pass.h"
-#include "cc/surfaces/surface_factory_client.h"
 #include "cc/surfaces/surface_hittest_delegate.h"
 #include "cc/surfaces/surface_id.h"
 #include "ui/gfx/geometry/insets.h"
@@ -25,12 +24,6 @@
 
 namespace test {
 
-class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
- public:
-  void ReturnResources(const ReturnedResourceArray& resources) override {}
-  void SetBeginFrameSource(BeginFrameSource* begin_frame_source) override {}
-};
-
 void CreateSharedQuadState(RenderPass* pass,
                            const gfx::Transform& transform,
                            const gfx::Rect& root_rect);
diff --git a/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml b/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml
index 592602e..4a6ad76d 100644
--- a/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml
+++ b/chrome/android/java/res/layout/data_reduction_old_stats_layout.xml
@@ -21,15 +21,14 @@
 
     <include layout="@layout/data_usage_chart" />
 
-    <LinearLayout
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content" >
 
         <TextView
             android:id="@+id/data_reduction_start_date"
-            android:layout_width="0dp"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_weight="1"
             android:textAppearance="@style/PreferenceSummary"
             android:textSize="14sp" />
 
@@ -40,7 +39,7 @@
             android:textAppearance="@style/PreferenceSummary"
             android:textSize="14sp" />
 
-    </LinearLayout>
+    </FrameLayout>
 
     <LinearLayout
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res/layout/data_reduction_stats_layout.xml b/chrome/android/java/res/layout/data_reduction_stats_layout.xml
index 2b9eedd..58d2097 100644
--- a/chrome/android/java/res/layout/data_reduction_stats_layout.xml
+++ b/chrome/android/java/res/layout/data_reduction_stats_layout.xml
@@ -82,15 +82,14 @@
 
     <include layout="@layout/data_usage_chart" />
 
-    <LinearLayout
+    <FrameLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content" >
 
         <TextView
             android:id="@+id/data_reduction_start_date"
-            android:layout_width="0dp"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_weight="1"
             android:textAppearance="@style/PreferenceSummary"
             android:textSize="14sp" />
 
@@ -101,7 +100,7 @@
             android:textAppearance="@style/PreferenceSummary"
             android:textSize="14sp" />
 
-    </LinearLayout>
+    </FrameLayout>
 
     <TextView
         android:id="@+id/data_reduction_proxy_unreachable"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java
index 96b6acee..7c562fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/CastNotificationControl.java
@@ -83,6 +83,8 @@
         }
         mPosterBitmap = posterBitmap;
         if (mNotificationBuilder == null || mMediaRouteController == null) return;
+
+        updateNotificationBuilderIfPosterIsGoodEnough();
         mNotificationBuilder.setNotificationLargeIcon(mMediaRouteController.getPoster());
         updateNotification();
     }
@@ -108,10 +110,11 @@
                 .setPrivate(false)
                 .setNotificationSmallIcon(R.drawable.ic_notification_media_route)
                 .setContentIntent(contentIntent)
-                .setNotificationLargeIcon(mMediaRouteController.getPoster())
                 .setDefaultNotificationLargeIcon(R.drawable.cast_playing_square)
                 .setId(R.id.remote_notification)
                 .setListener(this);
+
+        updateNotificationBuilderIfPosterIsGoodEnough();
         mState = initialState;
         updateNotification();
         mIsShowing = true;
@@ -145,7 +148,7 @@
     // poster changes.
     public void onPosterBitmapChanged() {
         if (mNotificationBuilder == null || mMediaRouteController == null) return;
-        mNotificationBuilder.setNotificationLargeIcon(mMediaRouteController.getPoster());
+        updateNotificationBuilderIfPosterIsGoodEnough();
         updateNotification();
     }
 
@@ -235,4 +238,12 @@
     boolean isShowingForTests() {
         return mIsShowing;
     }
+
+    private void updateNotificationBuilderIfPosterIsGoodEnough() {
+        Bitmap poster = mMediaRouteController.getPoster();
+        if (MediaNotificationManager.isBitmapSuitableAsMediaImage(poster)) {
+            mNotificationBuilder.setNotificationLargeIcon(poster);
+            mNotificationBuilder.setMediaSessionImage(poster);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
index 17ba5e0..8aaa7bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaNotificationManager.java
@@ -60,6 +60,8 @@
 public class MediaNotificationManager {
     private static final String TAG = "MediaNotification";
 
+    static final int MINIMAL_MEDIA_IMAGE_SIZE_PX = 114;
+
     @VisibleForTesting
     static final int CUSTOM_MEDIA_SESSION_ACTION_STOP = MediaSessionAction.LAST + 1;
 
@@ -540,6 +542,15 @@
         return HIGH_IMAGE_SIZE_PX;
     }
 
+    /**
+     * @returns Whether |icon| is suitable as the media image, i.e. bigger than the minimal size.
+     * @param icon The icon to be checked.
+     */
+    public static boolean isBitmapSuitableAsMediaImage(Bitmap icon) {
+        return icon != null && icon.getWidth() >= MINIMAL_MEDIA_IMAGE_SIZE_PX
+                && icon.getHeight() >= MINIMAL_MEDIA_IMAGE_SIZE_PX;
+    }
+
     private static MediaNotificationManager getManager(int notificationId) {
         return sManagers.get(notificationId);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
index e7667418..f1b70d1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
@@ -41,7 +41,6 @@
     private static final String TAG = "MediaSession";
 
     private static final String UNICODE_PLAY_CHARACTER = "\u25B6";
-    private static final int MINIMAL_FAVICON_SIZE = 114;
     private static final int HIDE_NOTIFICATION_DELAY_MILLIS = 1000;
 
     private Tab mTab;
@@ -352,8 +351,9 @@
     private MediaSessionTabHelper(Tab tab) {
         mTab = tab;
         mTab.addObserver(mTabObserver);
-        mMediaImageManager = new MediaImageManager(
-                MINIMAL_FAVICON_SIZE, MediaNotificationManager.getIdealMediaImageSize());
+        mMediaImageManager =
+                new MediaImageManager(MediaNotificationManager.MINIMAL_MEDIA_IMAGE_SIZE_PX,
+                        MediaNotificationManager.getIdealMediaImageSize());
         if (mTab.getWebContents() != null) setWebContents(tab.getWebContents());
 
         Activity activity = getActivityFromTab(mTab);
@@ -417,9 +417,7 @@
     private boolean updateFavicon(Bitmap icon) {
         if (icon == null) return false;
 
-        if (icon.getWidth() < MINIMAL_FAVICON_SIZE || icon.getHeight() < MINIMAL_FAVICON_SIZE) {
-            return false;
-        }
+        if (!MediaNotificationManager.isBitmapSuitableAsMediaImage(icon)) return false;
         if (mFavicon != null && (icon.getWidth() < mFavicon.getWidth()
                                         || icon.getHeight() < mFavicon.getHeight())) {
             return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
index 4c3f177..77cfb84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/datareduction/DataReductionStatsPreference.java
@@ -15,9 +15,11 @@
 import android.text.format.DateUtils;
 import android.text.format.Formatter;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.Button;
+import android.widget.FrameLayout;
 import android.widget.TextView;
 
 import org.chromium.base.Callback;
@@ -127,6 +129,15 @@
     }
 
     /**
+     * Keep the graph labels LTR oriented. In RTL languages, numbers and plots remain LTR.
+     */
+    @SuppressLint("RtlHardcoded")
+    private void forceLayoutGravityOfGraphLabels() {
+        ((FrameLayout.LayoutParams) mStartDateTextView.getLayoutParams()).gravity = Gravity.LEFT;
+        ((FrameLayout.LayoutParams) mEndDateTextView.getLayoutParams()).gravity = Gravity.RIGHT;
+    }
+
+    /**
      * Sets up a data usage chart and text views containing data reduction statistics.
      * @param view The current view.
      */
@@ -142,6 +153,7 @@
         mEndDateTextView = (TextView) view.findViewById(R.id.data_reduction_end_date);
         mDataReductionBreakdownView =
                 (DataReductionSiteBreakdownView) view.findViewById(R.id.breakdown);
+        forceLayoutGravityOfGraphLabels();
         updateReductionStatistics();
         setDetailText();
 
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index cde0de6..deb2dbe 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -483,7 +483,7 @@
         Search and site suggestions
       </message>
       <message name="IDS_SEARCH_SITE_SUGGESTIONS_SUMMARY" desc="Summary for search and site suggestions.">
-        Use a prediction service to show related queries and websites as you browse
+        Use prediction services to suggest searches and websites
       </message>
       <message name="IDS_SAFE_BROWSING_EXTENDED_REPORTING_TITLE" desc="Title for checkbox that controls whether details of possible security incidents will be sent to Google.">
         Security incidents
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 2ee6b3d..eabe276 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10406,19 +10406,6 @@
         </message>
       </if>
 
-      <!-- Media throttle infobar -->
-      <if expr="is_android">
-        <message name="IDS_MEDIA_THROTTLE_INFOBAR_TEXT" desc="Text to display on the info bar whenever user wants to playback a video after being throttled.">
-          Android is having trouble playing media.
-        </message>
-        <message name="IDS_MEDIA_THROTTLE_INFOBAR_BLOCK_BUTTON" desc="Label for choosing 'Block' on media throttle infobar.[CHAR-LIMIT=32]">
-          Wait
-        </message>
-        <message name="IDS_MEDIA_THROTTLE_INFOBAR_ALLOW_BUTTON" desc="Label for choosing 'Allow' on media throttle infobar. [CHAR-LIMIT=32]">
-          Try again
-        </message>
-      </if>
-
       <message name="IDS_MANAGE_PASSWORDS_CONFIRM_GENERATED_TITLE" desc="The title text that is used in the manage passwords bubble when the user has generated a password.">
         Password saved
       </message>
diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index e857c970..a50a807 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -243,11 +243,13 @@
 
   // Ping services that we know we want to launch on startup (UI service,
   // window manager, quick launch app).
-  context.connector()->Connect(ui::mojom::kServiceName);
-  context.connector()->Connect(content::mojom::kPackagedServicesServiceName);
+  context.connector()->StartService(ui::mojom::kServiceName);
+  context.connector()->StartService(
+      content::mojom::kPackagedServicesServiceName);
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kMash)) {
-    context.connector()->Connect(mash::common::GetWindowManagerServiceName());
-    context.connector()->Connect(mash::quick_launch::mojom::kServiceName);
+    context.connector()->StartService(
+        mash::common::GetWindowManagerServiceName());
+    context.connector()->StartService(mash::quick_launch::mojom::kServiceName);
   }
 
   run_loop.Run();
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 164d131..97f28975 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2830,8 +2830,6 @@
       "android/logo_bridge.h",
       "android/logo_service.cc",
       "android/logo_service.h",
-      "android/media/media_throttle_infobar_delegate.cc",
-      "android/media/media_throttle_infobar_delegate.h",
       "android/metrics/launch_metrics.cc",
       "android/metrics/launch_metrics.h",
       "android/metrics/uma_session_stats.cc",
diff --git a/chrome/browser/android/media/media_throttle_infobar_delegate.cc b/chrome/browser/android/media/media_throttle_infobar_delegate.cc
deleted file mode 100644
index 10e46cf..0000000
--- a/chrome/browser/android/media/media_throttle_infobar_delegate.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/android/media/media_throttle_infobar_delegate.h"
-
-#include <stddef.h>
-#include <utility>
-
-#include "base/metrics/histogram_macros.h"
-#include "chrome/browser/android/android_theme_resources.h"
-#include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
-#include "components/infobars/core/infobar.h"
-#include "components/strings/grit/components_strings.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "url/gurl.h"
-
-// static
-void MediaThrottleInfoBarDelegate::Create(
-    content::WebContents* web_contents,
-    const DecodeRequestGrantedCallback& callback) {
-  InfoBarService* infobar_service =
-      InfoBarService::FromWebContents(web_contents);
-  std::unique_ptr<infobars::InfoBar> new_infobar(
-      infobar_service->CreateConfirmInfoBar(
-          std::unique_ptr<ConfirmInfoBarDelegate>(
-              new MediaThrottleInfoBarDelegate(callback))));
-
-  for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
-    infobars::InfoBar* old_infobar = infobar_service->infobar_at(i);
-    MediaThrottleInfoBarDelegate* delegate =
-        old_infobar->delegate()->AsMediaThrottleInfoBarDelegate();
-    if (delegate != nullptr) {
-      infobar_service->ReplaceInfoBar(old_infobar, std::move(new_infobar));
-      return;
-    }
-  }
-
-  infobar_service->AddInfoBar(std::move(new_infobar));
-}
-
-MediaThrottleInfoBarDelegate::MediaThrottleInfoBarDelegate(
-    const DecodeRequestGrantedCallback& callback)
-    : infobar_response_(UMA_THROTTLE_INFOBAR_NO_RESPONSE),
-      decode_granted_callback_(callback) {
-}
-
-MediaThrottleInfoBarDelegate::~MediaThrottleInfoBarDelegate() {
-  UMA_HISTOGRAM_ENUMERATION("Media.Android.ThrottleInfobarResponse",
-                            infobar_response_,
-                            UMA_THROTTLE_INFOBAR_RESPONSE_COUNT);
-}
-
-infobars::InfoBarDelegate::InfoBarIdentifier
-MediaThrottleInfoBarDelegate::GetIdentifier() const {
-  return MEDIA_THROTTLE_INFOBAR_DELEGATE;
-}
-
-MediaThrottleInfoBarDelegate*
-    MediaThrottleInfoBarDelegate::AsMediaThrottleInfoBarDelegate() {
-  return this;
-}
-
-base::string16 MediaThrottleInfoBarDelegate::GetMessageText() const {
-  return l10n_util::GetStringUTF16(IDS_MEDIA_THROTTLE_INFOBAR_TEXT);
-}
-
-int MediaThrottleInfoBarDelegate::GetIconId() const {
-  return IDR_ANDROID_INFOBAR_WARNING;
-}
-
-base::string16 MediaThrottleInfoBarDelegate::GetButtonLabel(
-    InfoBarButton button) const {
-  return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
-      IDS_MEDIA_THROTTLE_INFOBAR_BLOCK_BUTTON :
-      IDS_MEDIA_THROTTLE_INFOBAR_ALLOW_BUTTON);
-}
-
-bool MediaThrottleInfoBarDelegate::Accept() {
-  infobar_response_ = UMA_THROTTLE_INFOBAR_WAIT;
-  decode_granted_callback_.Run(false);
-  return true;
-}
-
-bool MediaThrottleInfoBarDelegate::Cancel() {
-  infobar_response_ = UMA_THROTTLE_INFOBAR_TRY_AGAIN;
-  decode_granted_callback_.Run(true);
-  return true;
-}
-
-void MediaThrottleInfoBarDelegate::InfoBarDismissed() {
-  infobar_response_ = UMA_THROTTLE_INFOBAR_DISMISSED;
-  decode_granted_callback_.Run(false);
-}
diff --git a/chrome/browser/android/media/media_throttle_infobar_delegate.h b/chrome/browser/android/media/media_throttle_infobar_delegate.h
deleted file mode 100644
index 621f16a..0000000
--- a/chrome/browser/android/media/media_throttle_infobar_delegate.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_ANDROID_MEDIA_MEDIA_THROTTLE_INFOBAR_DELEGATE_H_
-#define CHROME_BROWSER_ANDROID_MEDIA_MEDIA_THROTTLE_INFOBAR_DELEGATE_H_
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "components/infobars/core/confirm_infobar_delegate.h"
-
-namespace content {
-class WebContents;
-}
-
-enum UMAThrottleInfobarResponse {
-  UMA_THROTTLE_INFOBAR_NO_RESPONSE,
-  UMA_THROTTLE_INFOBAR_TRY_AGAIN,
-  UMA_THROTTLE_INFOBAR_WAIT,
-  UMA_THROTTLE_INFOBAR_DISMISSED,
-  // NOTE: Add responses only immediately above this line. Make sure to
-  // update the enum list in tools/metrics/histograms/histograms.xml
-  // accordingly.
-  UMA_THROTTLE_INFOBAR_RESPONSE_COUNT
-};
-
-class MediaThrottleInfoBarDelegate : public ConfirmInfoBarDelegate {
- public:
-  typedef base::Callback<void(bool)> DecodeRequestGrantedCallback;
-  ~MediaThrottleInfoBarDelegate() override;
-
-  // Static method to create the object
-  static void Create(
-      content::WebContents* web_contents,
-      const DecodeRequestGrantedCallback& callback);
-
- private:
-  explicit MediaThrottleInfoBarDelegate(
-      const DecodeRequestGrantedCallback& callback);
-
-  // ConfirmInfoBarDelegate:
-  infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
-  MediaThrottleInfoBarDelegate* AsMediaThrottleInfoBarDelegate() override;
-  base::string16 GetMessageText() const override;
-  int GetIconId() const override;
-  base::string16 GetButtonLabel(InfoBarButton button) const override;
-  bool Accept() override;
-  bool Cancel() override;
-  void InfoBarDismissed() override;
-
-  UMAThrottleInfobarResponse infobar_response_;
-
-  DecodeRequestGrantedCallback decode_granted_callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(MediaThrottleInfoBarDelegate);
-};
-
-#endif  // CHROME_BROWSER_ANDROID_MEDIA_MEDIA_THROTTLE_INFOBAR_DELEGATE_H_
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index deccbc6..fa26ef6c 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/android/banners/app_banner_manager_android.h"
 #include "chrome/browser/android/feature_utilities.h"
 #include "chrome/browser/android/hung_renderer_infobar_delegate.h"
-#include "chrome/browser/android/media/media_throttle_infobar_delegate.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/file_select_helper.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -275,12 +274,6 @@
       ->CheckMediaAccessPermission(web_contents, security_origin, type);
 }
 
-void TabWebContentsDelegateAndroid::RequestMediaDecodePermission(
-    content::WebContents* web_contents,
-    const base::Callback<void(bool)>& callback) {
-  MediaThrottleInfoBarDelegate::Create(web_contents, callback);
-}
-
 bool TabWebContentsDelegateAndroid::RequestPpapiBrokerPermission(
     WebContents* web_contents,
     const GURL& url,
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h
index 3f557591..1d85597 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.h
+++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -67,9 +67,6 @@
   bool CheckMediaAccessPermission(content::WebContents* web_contents,
                                   const GURL& security_origin,
                                   content::MediaStreamType type) override;
-  void RequestMediaDecodePermission(
-      content::WebContents* web_contents,
-      const base::Callback<void(bool)>& callback) override;
   bool RequestPpapiBrokerPermission(
       content::WebContents* web_contents,
       const GURL& url,
diff --git a/chrome/browser/browsing_data/browsing_data_remover.h b/chrome/browser/browsing_data/browsing_data_remover.h
index 4edae603..757d8a8 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.h
+++ b/chrome/browser/browsing_data/browsing_data_remover.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include "base/callback_forward.h"
+#include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/browsing_data_remover_delegate.h"
@@ -179,6 +180,14 @@
   virtual void AddObserver(Observer* observer) = 0;
   virtual void RemoveObserver(Observer* observer) = 0;
 
+  // A |callback| that will be called just before a deletion task is completed
+  // and observers are notified. The receiver must respond by calling
+  // |continue_to_completion| to finish the task. Used in tests to artificially
+  // prolong execution.
+  virtual void SetWouldCompleteCallbackForTesting(
+      const base::Callback<void(const base::Closure& continue_to_completion)>&
+          callback) = 0;
+
   // Parameters of the last call are exposed to be used by tests. Removal and
   // origin type masks equal to -1 mean that no removal has ever been executed.
   // TODO(msramek): If other consumers than tests are interested in this,
diff --git a/chrome/browser/browsing_data/browsing_data_remover_impl.cc b/chrome/browser/browsing_data/browsing_data_remover_impl.cc
index dee3c1a..d9df6f1 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_impl.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_impl.cc
@@ -139,9 +139,6 @@
 
 }  // namespace
 
-BrowsingDataRemoverImpl::CompletionInhibitor*
-    BrowsingDataRemoverImpl::completion_inhibitor_ = nullptr;
-
 BrowsingDataRemoverImpl::SubTask::SubTask(const base::Closure& forward_callback)
     : is_pending_(false),
       forward_callback_(forward_callback),
@@ -184,6 +181,7 @@
       clear_channel_ids_(sub_task_forward_callback_),
       clear_http_auth_cache_(sub_task_forward_callback_),
       clear_storage_partition_data_(sub_task_forward_callback_),
+      storage_partition_for_testing_(nullptr),
       weak_ptr_factory_(this) {
   DCHECK(browser_context_);
 }
@@ -565,6 +563,12 @@
   observer_list_.RemoveObserver(observer);
 }
 
+void BrowsingDataRemoverImpl::SetWouldCompleteCallbackForTesting(
+    const base::Callback<void(const base::Closure& continue_to_completion)>&
+        callback) {
+  would_complete_callback_ = callback;
+}
+
 void BrowsingDataRemoverImpl::OverrideStoragePartitionForTesting(
     content::StoragePartition* storage_partition) {
   storage_partition_for_testing_ = storage_partition;
@@ -655,9 +659,9 @@
   if (!AllDone())
     return;
 
-  if (completion_inhibitor_) {
-    completion_inhibitor_->OnBrowsingDataRemoverWouldComplete(
-        this, base::Bind(&BrowsingDataRemoverImpl::Notify, GetWeakPtr()));
+  if (!would_complete_callback_.is_null()) {
+    would_complete_callback_.Run(
+        base::Bind(&BrowsingDataRemoverImpl::Notify, GetWeakPtr()));
     return;
   }
 
diff --git a/chrome/browser/browsing_data/browsing_data_remover_impl.h b/chrome/browser/browsing_data/browsing_data_remover_impl.h
index 41281c14..3e87fa4 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_impl.h
+++ b/chrome/browser/browsing_data/browsing_data_remover_impl.h
@@ -12,7 +12,6 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/synchronization/waitable_event_watcher.h"
 #include "base/time/time.h"
@@ -33,22 +32,6 @@
 
 class BrowsingDataRemoverImpl : public BrowsingDataRemover {
  public:
-  // The completion inhibitor can artificially delay completion of the browsing
-  // data removal process. It is used during testing to simulate scenarios in
-  // which the deletion stalls or takes a very long time.
-  class CompletionInhibitor {
-   public:
-    // Invoked when a |remover| is just about to complete clearing browser data,
-    // and will be prevented from completing until after the callback
-    // |continue_to_completion| is run.
-    virtual void OnBrowsingDataRemoverWouldComplete(
-        BrowsingDataRemoverImpl* remover,
-        const base::Closure& continue_to_completion) = 0;
-
-   protected:
-    virtual ~CompletionInhibitor() {}
-  };
-
   // Used to track the deletion of a single data storage backend.
   class SubTask {
    public:
@@ -78,15 +61,6 @@
   // Is the BrowsingDataRemoverImpl currently in the process of removing data?
   bool is_removing() { return is_removing_; }
 
-  // Sets a CompletionInhibitor, which will be notified each time an instance is
-  // about to complete a browsing data removal process, and will be able to
-  // artificially delay the completion.
-  // TODO(crbug.com/483528): Make this non-static.
-  static void set_completion_inhibitor_for_testing(
-      CompletionInhibitor* inhibitor) {
-    completion_inhibitor_ = inhibitor;
-  }
-
   // BrowsingDataRemover implementation:
   void SetEmbedderDelegate(
       std::unique_ptr<BrowsingDataRemoverDelegate> embedder_delegate) override;
@@ -122,6 +96,10 @@
   void AddObserver(Observer* observer) override;
   void RemoveObserver(Observer* observer) override;
 
+  void SetWouldCompleteCallbackForTesting(
+      const base::Callback<void(const base::Closure& continue_to_completion)>&
+          callback) override;
+
   const base::Time& GetLastUsedBeginTime() override;
   const base::Time& GetLastUsedEndTime() override;
   int GetLastUsedRemovalMask() override;
@@ -205,7 +183,8 @@
   // Returns true if we're all done.
   bool AllDone();
 
-  // Retrieve a UI thread-bound weak pointer to this BrowsingDataRemoverImpl.
+  // Like GetWeakPtr(), but returns a weak pointer to BrowsingDataRemoverImpl
+  // for internal purposes.
   base::WeakPtr<BrowsingDataRemoverImpl> GetWeakPtr();
 
   // The browser context we're to remove from.
@@ -232,10 +211,11 @@
   // Removal tasks to be processed.
   std::queue<RemovalTask> task_queue_;
 
-  // If non-NULL, the |completion_inhibitor_| is notified each time an instance
+  // If non-null, the |would_complete_callback_| is called each time an instance
   // is about to complete a browsing data removal process, and has the ability
   // to artificially delay completion. Used for testing.
-  static CompletionInhibitor* completion_inhibitor_;
+  base::Callback<void(const base::Closure& continue_to_completion)>
+      would_complete_callback_;
 
   // A callback to NotifyIfDone() used by SubTasks instances.
   const base::Closure sub_task_forward_callback_;
@@ -253,7 +233,7 @@
   base::ObserverList<Observer, true> observer_list_;
 
   // We do not own this.
-  content::StoragePartition* storage_partition_for_testing_ = nullptr;
+  content::StoragePartition* storage_partition_for_testing_;
 
   base::WeakPtrFactory<BrowsingDataRemoverImpl> weak_ptr_factory_;
 
diff --git a/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.cc b/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.cc
index 53518b5..0c34444 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_impl_unittest.cc
@@ -1438,12 +1438,12 @@
 };
 
 TEST_F(BrowsingDataRemoverImplTest, CompletionInhibition) {
-  // The |completion_inhibitor| on the stack should prevent removal sessions
-  // from completing until after ContinueToCompletion() is called.
-  BrowsingDataRemoverCompletionInhibitor completion_inhibitor;
-
   BrowsingDataRemoverImpl* remover = static_cast<BrowsingDataRemoverImpl*>(
       BrowsingDataRemoverFactory::GetForBrowserContext(GetBrowserContext()));
+
+  // The |completion_inhibitor| on the stack should prevent removal sessions
+  // from completing until after ContinueToCompletion() is called.
+  BrowsingDataRemoverCompletionInhibitor completion_inhibitor(remover);
   InspectableCompletionObserver completion_observer(remover);
   remover->RemoveAndReply(
       base::Time(), base::Time::Max(), BrowsingDataRemover::DATA_TYPE_COOKIES,
@@ -1473,12 +1473,13 @@
   BrowsingDataRemoverImpl* remover = static_cast<BrowsingDataRemoverImpl*>(
       BrowsingDataRemoverFactory::GetForBrowserContext(GetBrowserContext()));
   InspectableCompletionObserver completion_observer(remover);
-  BrowsingDataRemoverCompletionInhibitor completion_inhibitor;
+  BrowsingDataRemoverCompletionInhibitor completion_inhibitor(remover);
   remover->RemoveAndReply(
       base::Time(), base::Time::Max(), BrowsingDataRemover::DATA_TYPE_COOKIES,
       BrowsingDataRemover::ORIGIN_TYPE_UNPROTECTED_WEB, &completion_observer);
 
   completion_inhibitor.BlockUntilNearCompletion();
+  completion_inhibitor.Reset();
 
   // Verify that the deletion has not yet been completed and the observer has
   // not been called.
@@ -1590,7 +1591,7 @@
   filter_builder_2->AddRegisterableDomain("example.com");
 
   MultipleTasksObserver observer(remover);
-  BrowsingDataRemoverCompletionInhibitor completion_inhibitor;
+  BrowsingDataRemoverCompletionInhibitor completion_inhibitor(remover);
 
   // Test several tasks with various configuration of masks, filters, and target
   // observers.
diff --git a/chrome/browser/browsing_data/browsing_data_remover_test_util.cc b/chrome/browser/browsing_data/browsing_data_remover_test_util.cc
index 9bdc5a3..6677ff7d 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_test_util.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover_test_util.cc
@@ -22,14 +22,27 @@
   message_loop_runner_->Quit();
 }
 
-BrowsingDataRemoverCompletionInhibitor::BrowsingDataRemoverCompletionInhibitor()
-    : message_loop_runner_(new content::MessageLoopRunner) {
-  BrowsingDataRemoverImpl::set_completion_inhibitor_for_testing(this);
+BrowsingDataRemoverCompletionInhibitor::BrowsingDataRemoverCompletionInhibitor(
+    BrowsingDataRemover* remover)
+    : remover_(remover), message_loop_runner_(new content::MessageLoopRunner) {
+  DCHECK(remover);
+  remover_->SetWouldCompleteCallbackForTesting(
+      base::Bind(&BrowsingDataRemoverCompletionInhibitor::
+                     OnBrowsingDataRemoverWouldComplete,
+                 base::Unretained(this)));
 }
 
 BrowsingDataRemoverCompletionInhibitor::
     ~BrowsingDataRemoverCompletionInhibitor() {
-  BrowsingDataRemoverImpl::set_completion_inhibitor_for_testing(nullptr);
+  Reset();
+}
+
+void BrowsingDataRemoverCompletionInhibitor::Reset() {
+  if (!remover_)
+    return;
+  remover_->SetWouldCompleteCallbackForTesting(
+      base::Callback<void(const base::Closure&)>());
+  remover_ = nullptr;
 }
 
 void BrowsingDataRemoverCompletionInhibitor::BlockUntilNearCompletion() {
@@ -44,7 +57,6 @@
 }
 
 void BrowsingDataRemoverCompletionInhibitor::OnBrowsingDataRemoverWouldComplete(
-    BrowsingDataRemoverImpl* remover,
     const base::Closure& continue_to_completion) {
   DCHECK(continue_to_completion_callback_.is_null());
   continue_to_completion_callback_ = continue_to_completion;
diff --git a/chrome/browser/browsing_data/browsing_data_remover_test_util.h b/chrome/browser/browsing_data/browsing_data_remover_test_util.h
index c0c7dd4d..bb0847c 100644
--- a/chrome/browser/browsing_data/browsing_data_remover_test_util.h
+++ b/chrome/browser/browsing_data/browsing_data_remover_test_util.h
@@ -9,7 +9,6 @@
 #include "base/memory/ref_counted.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/browsing_data/browsing_data_remover.h"
-#include "chrome/browser/browsing_data/browsing_data_remover_impl.h"
 #include "content/public/test/test_utils.h"
 
 // This class can be used to wait for a BrowsingDataRemover to complete
@@ -33,22 +32,32 @@
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionObserver);
 };
 
-class BrowsingDataRemoverCompletionInhibitor
-    : public BrowsingDataRemoverImpl::CompletionInhibitor {
+// The completion inhibitor can artificially delay completion of the browsing
+// data removal process. It is used during testing to simulate scenarios in
+// which the deletion stalls or takes a very long time.
+//
+// This class will detach itself from |remover| upon its destruction.
+// If |remover| is destroyed during a test (e.g. in profile shutdown tests),
+// users must call Reset() to detach it in advance.
+class BrowsingDataRemoverCompletionInhibitor {
  public:
-  BrowsingDataRemoverCompletionInhibitor();
-  ~BrowsingDataRemoverCompletionInhibitor() override;
+  explicit BrowsingDataRemoverCompletionInhibitor(BrowsingDataRemover* remover);
+  virtual ~BrowsingDataRemoverCompletionInhibitor();
+
+  void Reset();
 
   void BlockUntilNearCompletion();
   void ContinueToCompletion();
 
  protected:
-  // BrowsingDataRemoverImpl::CompletionInhibitor:
-  void OnBrowsingDataRemoverWouldComplete(
-      BrowsingDataRemoverImpl* remover,
-      const base::Closure& continue_to_completion) override;
+  virtual void OnBrowsingDataRemoverWouldComplete(
+      const base::Closure& continue_to_completion);
 
  private:
+  // Not owned by this class. If the pointer becomes invalid, the owner of
+  // this class is responsible for calling Reset().
+  BrowsingDataRemover* remover_;
+
   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
   base::Closure continue_to_completion_callback_;
 
diff --git a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
index 5d0d29c0..5da1aaf 100644
--- a/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_screen_policy_browsertest.cc
@@ -6,6 +6,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
 #include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
 #include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
@@ -16,6 +17,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/settings/cros_settings_names.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/notification_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
@@ -75,6 +77,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(LoginScreenPolicyTest, RestrictInputMethods) {
+  content::WindowedNotificationObserver(
+      chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+      content::NotificationService::AllSources())
+      .Wait();
+
   input_method::InputMethodManager* imm =
       input_method::InputMethodManager::Get();
   ASSERT_TRUE(imm);
diff --git a/chrome/browser/component_updater/cros_component_installer.cc b/chrome/browser/component_updater/cros_component_installer.cc
index 0881d90..22fc25f 100644
--- a/chrome/browser/component_updater/cros_component_installer.cc
+++ b/chrome/browser/component_updater/cros_component_installer.cc
@@ -21,28 +21,6 @@
 namespace component_updater {
 
 #if defined(OS_CHROMEOS)
-void LogLoadResult(chromeos::DBusMethodCallStatus call_status,
-                   const std::string& result) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
-    DVLOG(1) << "Call to imageloader service failed.";
-    return;
-  }
-  if (result.empty()) {
-    DVLOG(1) << "Component load failed";
-    return;
-  }
-}
-void ImageLoaderLoad(const std::string& name) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  chromeos::ImageLoaderClient* loader =
-      chromeos::DBusThreadManager::Get()->GetImageLoaderClient();
-  if (loader) {
-    loader->LoadComponent(name, base::Bind(&LogLoadResult));
-  } else {
-    DVLOG(1) << "Failed to get ImageLoaderClient object.";
-  }
-}
 void LogRegistrationResult(const std::string& name,
                            chromeos::DBusMethodCallStatus call_status,
                            bool result) {
@@ -55,8 +33,8 @@
     DVLOG(1) << "Component registration failed";
     return;
   }
-  ImageLoaderLoad(name);
 }
+
 void ImageLoaderRegistration(const std::string& version,
                              const base::FilePath& install_dir,
                              const std::string& name) {
@@ -71,6 +49,7 @@
     DVLOG(1) << "Failed to get ImageLoaderClient object.";
   }
 }
+
 ComponentConfig::ComponentConfig(const std::string& name,
                                  const std::string& dir,
                                  const std::string& sha2hashstr)
@@ -201,6 +180,34 @@
                  install_callback));
   return true;
 }
+
+void MountResult(const base::Callback<void(const std::string&)>& mount_callback,
+                 chromeos::DBusMethodCallStatus call_status,
+                 const std::string& result) {
+  if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
+    DVLOG(1) << "Call to imageloader service failed.";
+    base::PostTask(FROM_HERE, base::Bind(mount_callback, ""));
+    return;
+  }
+  if (result.empty()) {
+    DVLOG(1) << "Component load failed";
+    base::PostTask(FROM_HERE, base::Bind(mount_callback, ""));
+    return;
+  }
+  base::PostTask(FROM_HERE, base::Bind(mount_callback, result));
+}
+
+void CrOSComponent::LoadCrOSComponent(
+    const std::string& name,
+    const base::Callback<void(const std::string&)>& mount_callback) {
+  chromeos::ImageLoaderClient* loader =
+      chromeos::DBusThreadManager::Get()->GetImageLoaderClient();
+  if (loader) {
+    loader->LoadComponent(name, base::Bind(&MountResult, mount_callback));
+  } else {
+    DVLOG(1) << "Failed to get ImageLoaderClient object.";
+  }
+}
 #endif  // defined(OS_CHROMEOS
 
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/cros_component_installer.h b/chrome/browser/component_updater/cros_component_installer.h
index fa9b9859..2a55c84 100644
--- a/chrome/browser/component_updater/cros_component_installer.h
+++ b/chrome/browser/component_updater/cros_component_installer.h
@@ -66,19 +66,12 @@
   //
   //  example:
   //  ...
-  //  void PerformOperations(chromeos::DBusMethodCallStatus call_status,
-  //                         const std::string& version){
-  //    if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
-  //      DVLOG(1) << "Call to imageloader service failed.";
+  //  void load_callback(const std::string& result){
+  //    if (result.empty) {
+  //      // component is not mounted.
   //      return;
   //    }
-  //    if (version.empty()) {
-  //      DVLOG(1) << "[PerformOperations] Component is not installed";
-  //      return;
-  //    }
-  //    // [mounted compnent path: /run/imageloader/[component name]/[version]]
-  //    //
-  //    // [component is ready to do your work]
+  //    // [component mount point: result]
   //  }
   //  void install_callback(update_client::Error error){
   //    // switch(error){
@@ -86,7 +79,7 @@
   //    //     // component is installed
   //    //     break;
   //    //   case update_client::Error::INVALID_ARGUMENT:
-  //    //     // your install failed due of your wrong parameters.
+  //    //     // your install failed due to your wrong parameters.
   //    //     break;
   //    //   default:
   //    //     // your install failed due to system failure.
@@ -95,13 +88,7 @@
   //    // Even when error code other than NONE returned (your install failed),
   //    // component might has already being installed previously.
   //    // Plus, if you want to know current version of component.
-  //    chromeos::ImageLoaderClient* loader =
-  //              chromeos::DBusThreadManager::Get()->GetImageLoaderClient();
-  //    if (loader) {
-  //      loader->GetComponentVersion("escpr", base::Bind(&PerformOperations));
-  //    } else {
-  //      VLOG(0) << "Failed to get ImageLoaderClient object.";
-  //    }
+  //    component_updater:CrOSComponent::LoadCrOSComponent(name, load_callback);
   //  }
   //  ...
   //    component_updater::CrOSComponent::InstallCrOSComponent(
@@ -112,6 +99,10 @@
       const std::string& name,
       const update_client::Callback& install_callback);
 
+  static void LoadCrOSComponent(
+      const std::string& name,
+      const base::Callback<void(const std::string&)>& mount_callback);
+
  private:
   CrOSComponent() {}
   // Register a component.
diff --git a/chrome/browser/extensions/external_loader.h b/chrome/browser/extensions/external_loader.h
index ecc11d68..83948db 100644
--- a/chrome/browser/extensions/external_loader.h
+++ b/chrome/browser/extensions/external_loader.h
@@ -69,6 +69,8 @@
   // this task should invoke |LoadFinished| with a PostTask. This scheme of
   // posting tasks will avoid concurrent access and imply the necessary memory
   // barriers.
+  // TODO(lazyboy): To avoid |prefs_| getting unexpectedly overwritten before it
+  // is consumed, consider passing the prefs directly in LoadFinished().
   std::unique_ptr<base::DictionaryValue> prefs_;
 
  private:
diff --git a/chrome/browser/extensions/external_registry_loader_win.cc b/chrome/browser/extensions/external_registry_loader_win.cc
index 0c10884..6f331080 100644
--- a/chrome/browser/extensions/external_registry_loader_win.cc
+++ b/chrome/browser/extensions/external_registry_loader_win.cc
@@ -190,17 +190,20 @@
 
 void ExternalRegistryLoader::LoadOnFileThread() {
   base::TimeTicks start_time = base::TimeTicks::Now();
-  prefs_ = LoadPrefsOnFileThread();
+  std::unique_ptr<base::DictionaryValue> prefs = LoadPrefsOnFileThread();
   LOCAL_HISTOGRAM_TIMES("Extensions.ExternalRegistryLoaderWin",
                         base::TimeTicks::Now() - start_time);
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::Bind(&ExternalRegistryLoader::CompleteLoadAndStartWatchingRegistry,
-                 this));
+                 this, base::Passed(&prefs)));
 }
 
-void ExternalRegistryLoader::CompleteLoadAndStartWatchingRegistry() {
+void ExternalRegistryLoader::CompleteLoadAndStartWatchingRegistry(
+    std::unique_ptr<base::DictionaryValue> prefs) {
   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+  DCHECK(prefs);
+  prefs_ = std::move(prefs);
   LoadFinished();
 
   // Attempt to watch registry if we haven't already.
diff --git a/chrome/browser/extensions/external_registry_loader_win.h b/chrome/browser/extensions/external_registry_loader_win.h
index 9b93cec..f596d2d 100644
--- a/chrome/browser/extensions/external_registry_loader_win.h
+++ b/chrome/browser/extensions/external_registry_loader_win.h
@@ -21,12 +21,15 @@
 
   void StartLoading() override;
 
+  // Overridden to mock registry reading in unit tests.
+  virtual std::unique_ptr<base::DictionaryValue> LoadPrefsOnFileThread();
+
  private:
   friend class base::RefCountedThreadSafe<ExternalLoader>;
 
-  std::unique_ptr<base::DictionaryValue> LoadPrefsOnFileThread();
   void LoadOnFileThread();
-  void CompleteLoadAndStartWatchingRegistry();
+  void CompleteLoadAndStartWatchingRegistry(
+      std::unique_ptr<base::DictionaryValue> prefs);
   void UpdatePrefsOnFileThread();
   void OnRegistryKeyChanged(base::win::RegKey* key);
 
diff --git a/chrome/browser/extensions/external_registry_loader_win_unittest.cc b/chrome/browser/extensions/external_registry_loader_win_unittest.cc
index cc83b7c..059b4d2 100644
--- a/chrome/browser/extensions/external_registry_loader_win_unittest.cc
+++ b/chrome/browser/extensions/external_registry_loader_win_unittest.cc
@@ -8,13 +8,17 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "base/values.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "extensions/common/value_builder.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
 
 namespace {
 
+const char kDummyRegistryKey[] = "dummyId";
+
 class TestExternalRegistryLoader : public ExternalRegistryLoader {
  public:
   TestExternalRegistryLoader() {}
@@ -26,19 +30,32 @@
     run_loop_.Run();
   }
 
+  std::vector<int> GetPrefsTestIds() { return prefs_test_ids_; }
+
  private:
   ~TestExternalRegistryLoader() override {}
 
+  std::unique_ptr<base::DictionaryValue> LoadPrefsOnFileThread() override {
+    return DictionaryBuilder().Set(kDummyRegistryKey, id_++).Build();
+  }
   void LoadFinished() override {
     ExternalRegistryLoader::LoadFinished();
     ++load_finished_count_;
     ASSERT_LE(load_finished_count_, 2);
+
+    ASSERT_TRUE(prefs_);
+    int prefs_test_id = -1;
+    EXPECT_TRUE(prefs_->GetInteger(kDummyRegistryKey, &prefs_test_id));
+    prefs_test_ids_.push_back(prefs_test_id);
+
     if (load_finished_count_ == 2)
       run_loop_.Quit();
   }
 
   base::RunLoop run_loop_;
   int load_finished_count_ = 0;
+  int id_ = 0;
+  std::vector<int> prefs_test_ids_;
 
   DISALLOW_COPY_AND_ASSIGN(TestExternalRegistryLoader);
 };
@@ -71,4 +88,26 @@
   base::RunLoop().RunUntilIdle();
 }
 
+// Tests that calling StartLoading() twice does not overwrite previous prefs
+// before LoadFinished consumes it.
+// Regression test for https://crbug.com/709304: if two StartLoading() schedules
+// two LoadPrefsOnFileThread, then the second LoadPrefsOnFileThread could
+// overwrite the first one's prefs.
+TEST_F(ExternalRegistryLoaderUnittest, TwoStartLoadingDoesNotOverwritePrefs) {
+  scoped_refptr<TestExternalRegistryLoader> test_loader =
+      make_scoped_refptr(new TestExternalRegistryLoader());
+
+  test_loader->StartLoading();
+  test_loader->StartLoading();
+
+  test_loader->WaitForTwoLoadsToFinished();
+  // Let registry watcher code complete.
+  base::RunLoop().RunUntilIdle();
+
+  std::vector<int> prefs_test_ids = test_loader->GetPrefsTestIds();
+  ASSERT_EQ(2u, prefs_test_ids.size());
+  EXPECT_EQ(0, prefs_test_ids[0]);
+  EXPECT_EQ(1, prefs_test_ids[1]);
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/profiles/profile_manager_browsertest.cc b/chrome/browser/profiles/profile_manager_browsertest.cc
index 2d2fea24..b9eb5d539 100644
--- a/chrome/browser/profiles/profile_manager_browsertest.cc
+++ b/chrome/browser/profiles/profile_manager_browsertest.cc
@@ -5,13 +5,15 @@
 #include <stddef.h>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/browser/browsing_data/browsing_data_remover_impl.h"
+#include "chrome/browser/browsing_data/browsing_data_remover.h"
+#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
 #include "chrome/browser/lifetime/keep_alive_types.h"
 #include "chrome/browser/lifetime/scoped_keep_alive.h"
 #include "chrome/browser/password_manager/password_store_factory.h"
@@ -68,23 +70,31 @@
 // deleted. It also create ScopedKeepAlive object to prevent browser shutdown
 // started in case browser has become windowless.
 class MultipleProfileDeletionObserver
-    : public BrowsingDataRemoverImpl::CompletionInhibitor,
-      public ProfileAttributesStorage::Observer {
+    : public ProfileAttributesStorage::Observer {
  public:
   explicit MultipleProfileDeletionObserver(size_t expected_count)
       : expected_count_(expected_count),
         profiles_created_count_(0),
         profiles_data_removed_count_(0) {
     EXPECT_GT(expected_count_, 0u);
-    g_browser_process->profile_manager()->GetProfileAttributesStorage().
-        AddObserver(this);
-    BrowsingDataRemoverImpl::set_completion_inhibitor_for_testing(this);
+    ProfileManager* profile_manager = g_browser_process->profile_manager();
+    profile_manager->GetProfileAttributesStorage().AddObserver(this);
+
+    base::Callback<void(const base::Closure&)> would_complete_callback =
+        base::Bind(&MultipleProfileDeletionObserver::
+                       OnBrowsingDataRemoverWouldComplete,
+                   base::Unretained(this));
+    for (Profile* profile : profile_manager->GetLoadedProfiles()) {
+      BrowsingDataRemoverFactory::GetForBrowserContext(profile)
+          ->SetWouldCompleteCallbackForTesting(would_complete_callback);
+    }
   }
+
   ~MultipleProfileDeletionObserver() override {
     g_browser_process->profile_manager()->GetProfileAttributesStorage().
         RemoveObserver(this);
-    BrowsingDataRemoverImpl::set_completion_inhibitor_for_testing(nullptr);
   }
+
   void Wait() {
     keep_alive_ = base::MakeUnique<ScopedKeepAlive>(
         KeepAliveOrigin::PROFILE_HELPER, KeepAliveRestartOption::DISABLED);
@@ -99,8 +109,7 @@
 
   // TODO(https://crbug.com/704601): remove this code when bug is fixed.
   void OnBrowsingDataRemoverWouldComplete(
-      BrowsingDataRemoverImpl* remover,
-      const base::Closure& continue_to_completion) override {
+      const base::Closure& continue_to_completion) {
     continue_to_completion.Run();
     profiles_data_removed_count_++;
     MaybeQuit();
diff --git a/chrome/browser/resources/chromeos/chromevox/braille/braille_translator_manager.js b/chrome/browser/resources/chromeos/chromevox/braille/braille_translator_manager.js
index c1d472b..31ad8476 100644
--- a/chrome/browser/resources/chromeos/chromevox/braille/braille_translator_manager.js
+++ b/chrome/browser/resources/chromeos/chromevox/braille/braille_translator_manager.js
@@ -192,7 +192,7 @@
       this.tables_ = tables;
 
       // Initial refresh; set options from user preferences.
-      this.refresh(localStorage['brailleTable'], localStorage['brailleTable8']);
+      this.refresh(localStorage['brailleTable']);
     }.bind(this));
   },
 
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
index ed218b0..c08ebdc 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
@@ -726,6 +726,15 @@
       }
     },
     {
+      "command": "toggleBrailleTable",
+      "sequence": {
+        "cvoxModifier": true,
+        "keys": {
+          "keyCode": [65, 71]
+        }
+      }
+    },
+    {
       "command": "viewGraphicAsBraille",
       "sequence": {
         "cvoxModifier": true,
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/prefs.js b/chrome/browser/resources/chromeos/chromevox/chromevox/background/prefs.js
index de8b7ef..9073bcd 100644
--- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/prefs.js
+++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/prefs.js
@@ -64,6 +64,9 @@
   'autoRead': false,
   'brailleCaptions': false,
   'brailleSideBySide': true,
+  'brailleTableType': 'brailleTable8',
+  'brailleTable6': 'en-UEB-g2',
+  'brailleTable8': 'en-US-comp8',
   // TODO(dtseng): Leaking state about multiple key maps here until we have a
   // class to manage multiple key maps. Also, this doesn't belong as a pref;
   // should just store in local storage.
diff --git a/chrome/browser/resources/chromeos/chromevox/common/command_store.js b/chrome/browser/resources/chromeos/chromevox/common/command_store.js
index 18da1ead..6a54a38 100644
--- a/chrome/browser/resources/chromeos/chromevox/common/command_store.js
+++ b/chrome/browser/resources/chromeos/chromevox/common/command_store.js
@@ -352,7 +352,12 @@
   'darkenScreen': {
     msgId: 'darken_screen',
     category: 'help_commands'
-},
+  },
+
+  'toggleBrailleTable': {
+    msgId: 'toggle_braille_table',
+    category: 'help_commands'
+  },
 
   'toggleKeyboardHelp': {announce: false,
                          disallowContinuation: true,
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
index 2208f0bb..717e78e 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/automation_predicate.js
@@ -313,7 +313,8 @@
     Role.WINDOW,
     Role.EMBEDDED_OBJECT,
     Role.IFRAME,
-    Role.IFRAME_PRESENTATIONAL]);
+    Role.IFRAME_PRESENTATIONAL,
+    Role.UNKNOWN]);
 
 /**
  * Returns whether the given node should not be crossed when performing
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/braille_command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/braille_command_handler.js
index 1abce1a..9469ee7 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/braille_command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/braille_command_handler.js
@@ -141,6 +141,9 @@
 
   // s.
   map([2, 3, 4], 'toggleSpeechOnOrOff');
+
+  // g.
+  map([1, 2, 4, 5], 'toggleBrailleTable');
 };
 
 BrailleCommandHandler.init_();
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
index fd27489..ad04393 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/command_handler.js
@@ -178,6 +178,27 @@
       cvox.BrailleCaptionsBackground.setActive(
           !cvox.BrailleCaptionsBackground.isEnabled());
       return false;
+    case 'toggleBrailleTable':
+      var brailleTableType = localStorage['brailleTableType'];
+      var output = '';
+      if (brailleTableType == 'brailleTable6') {
+        brailleTableType = 'brailleTable8';
+
+        // This label reads "switch to 8 dot braille".
+        output = '@OPTIONS_BRAILLE_TABLE_TYPE_6';
+      } else {
+        brailleTableType = 'brailleTable6';
+
+        // This label reads "switch to 6 dot braille".
+        output = '@OPTIONS_BRAILLE_TABLE_TYPE_8';
+      }
+
+      localStorage['brailleTable'] = localStorage[brailleTableType];
+      localStorage['brailleTableType'] = brailleTableType;
+      cvox.BrailleBackground.getInstance().getTranslatorManager().refresh(
+          localStorage[brailleTableType]);
+      new Output().format(output).go();
+      return false;
     case 'toggleChromeVoxVersion':
       if (!ChromeVoxState.instance.toggleNext())
         return false;
diff --git a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
index 57b49979..2761bda 100644
--- a/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
+++ b/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd
@@ -2727,6 +2727,9 @@
       <message desc="Description of a command that toggles text to speech feedback on or off." name="IDS_CHROMEVOX_SPEECH_ON_OFF_DESCRIPTION">
         Toggle speech on or off
       </message>
+      <message desc="Description of a command that toggles between 6 and 8 dot braille." name="IDS_CHROMEVOX_TOGGLE_BRAILLE_TABLE">
+        Toggle between 6 and 8 dot braille
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access.js b/chrome/browser/resources/chromeos/switch_access/switch_access.js
index 0adc858..58bcb3a 100644
--- a/chrome/browser/resources/chromeos/switch_access/switch_access.js
+++ b/chrome/browser/resources/chromeos/switch_access/switch_access.js
@@ -107,14 +107,6 @@
     if (!this.node_)
       return;
 
-    let state = this.node_.state;
-    if (state && state.focusable)
-      console.log('Node was focusable, doing default on it')
-    else if (state)
-      console.log('Node was not focusable, but still doing default');
-    else
-      console.log('Node has no state, still doing default');
-    console.log('\n');
     this.node_.doDefault();
   },
 
@@ -170,6 +162,7 @@
     if (node) {
       console.log('Name = ' + node.name);
       console.log('Role = ' + node.role);
+      console.log('Root role = ' + node.root.role);
       if (!node.parent)
         console.log('At index ' + node.indexInParent + ', has no parent');
       else {
diff --git a/chrome/browser/resources/chromeos/switch_access/tree_walker.js b/chrome/browser/resources/chromeos/switch_access/tree_walker.js
index ce8237d7..5fc9f1f1 100644
--- a/chrome/browser/resources/chromeos/switch_access/tree_walker.js
+++ b/chrome/browser/resources/chromeos/switch_access/tree_walker.js
@@ -116,11 +116,32 @@
    * Returns true if |node| is interesting.
    *
    * @param {!chrome.automation.AutomationNode} node
-   * @return {boolean|undefined}
+   * @return {boolean}
    * @private
    */
   isInteresting_: function(node) {
-    return node.state && node.state.focusable;
+    let loc = node.location;
+    let parent = node.parent;
+    let root = node.root;
+    let role = node.role;
+    let state = node.state;
+
+    // Skip things that are offscreen
+    if (state[chrome.automation.StateType.OFFSCREEN]
+        || loc.top < 0 || loc.left < 0)
+      return false;
+
+    if (parent) {
+      // crbug.com/710559
+      // Work around for browser tabs
+      if (role === chrome.automation.RoleType.TAB
+          && parent.role === chrome.automation.RoleType.TAB_LIST
+          && root.role === chrome.automation.RoleType.DESKTOP)
+        return true;
+    }
+
+    // The general rule that applies to everything.
+    return state[chrome.automation.StateType.FOCUSABLE] === true;
   },
 
   /**
diff --git a/chrome/browser/resources/chromeos/switch_access/tree_walker_unittest.gtestjs b/chrome/browser/resources/chromeos/switch_access/tree_walker_unittest.gtestjs
index 52782ee..380f2d5 100644
--- a/chrome/browser/resources/chromeos/switch_access/tree_walker_unittest.gtestjs
+++ b/chrome/browser/resources/chromeos/switch_access/tree_walker_unittest.gtestjs
@@ -23,6 +23,7 @@
   browsePreload: DUMMY_URL,
 
   getSampleTree: function() {
+    let loc = {left: 0, top: 0, width: 0, height: 0};
     // root
     //   middle1
     //     leaf1
@@ -31,14 +32,14 @@
     //   middle2
     //     leaf4
     //     leaf5
-    let root = {};
-    let middle1 = {};
-    let middle2 = {};
-    let leaf1 = {};
-    let leaf2 = {};
-    let leaf3 = {};
-    let leaf4 = {};
-    let leaf5 = {};
+    let root = {location: loc, state: {}};
+    let middle1 = {location: loc, state: {}};
+    let middle2 = {location: loc, state: {}};
+    let leaf1 = {location: loc, state: {}};
+    let leaf2 = {location: loc, state: {}};
+    let leaf3 = {location: loc, state: {}};
+    let leaf4 = {location: loc, state: {}};
+    let leaf5 = {location: loc, state: {}};
 
     root.firstChild = middle1;
     root.lastChild = middle2;
@@ -79,6 +80,11 @@
 };
 
 TEST_F('AutomationTreeWalkerUnitTest', 'MoveToNode', function() {
+  chrome.automation = {
+    RoleType: {DESKTOP: 'desktop', TAB: 'tab', TAB_LIST: 'tabList'},
+    StateType: {FOCUSABLE: 'focusable', OFFSCREEN: 'offscreen'}
+  };
+
   let t = this.getSampleTree();
   let treeWalker = new AutomationTreeWalker();
 
@@ -154,14 +160,36 @@
 });
 
 TEST_F('AutomationTreeWalkerUnitTest', 'IsInteresting', function() {
-  let node1 = {};
-  let node2 = {state: {}};
-  let node3 = {state: {focusable: false}};
-  let node4 = {state: {focusable: true}};
+  chrome.automation = {
+    RoleType: {DESKTOP: 'desktop', TAB: 'tab', TAB_LIST: 'tabList'},
+    StateType: {FOCUSABLE: 'focusable', OFFSCREEN: 'offscreen'}
+  };
+
   let treeWalker = new AutomationTreeWalker();
 
-  assertTrue(treeWalker.isInteresting_(node1) === undefined);
-  assertTrue(treeWalker.isInteresting_(node2) === undefined);
-  assertFalse(treeWalker.isInteresting_(node3));
-  assertTrue(treeWalker.isInteresting_(node4));
+  // Testing focusable.
+  let loc1 = {left: 0, top: 0, width: 0, height: 0};
+  let node1 = {location: loc1, state: {}};
+  let node2 = {location: loc1, state: {focusable: false}};
+  let node3 = {location: loc1, state: {focusable: true}};
+  assertFalse(treeWalker.isInteresting_(node1));
+  assertFalse(treeWalker.isInteresting_(node2));
+  assertTrue(treeWalker.isInteresting_(node3));
+
+  // Testing onscreen.
+  let loc2 = {left: -1, top: 0, width: 0, height: 0};
+  let loc3 = {left: 0, top: -1, width: 0, height: 0};
+  let node4 = {location: loc2, state: {focusable: true}};
+  let node5 = {location: loc3, state: {focusable: true}};
+  assertFalse(treeWalker.isInteresting_(node4));
+  assertFalse(treeWalker.isInteresting_(node5));
+
+  // Testing if tab.
+  let node6 = {location: loc1, role: 'desktop', state: {}};
+  let node7 = {location: loc1, role: 'tabList', state: {}};
+  let node8 =
+      {location: loc1, parent: node7, root: node6, role: 'tab', state: {}};
+  assertFalse(treeWalker.isInteresting_(node6));
+  assertFalse(treeWalker.isInteresting_(node7));
+  assertTrue(treeWalker.isInteresting_(node8));
 });
diff --git a/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js b/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js
index 6e46140..7a5f37e 100644
--- a/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js
+++ b/chrome/browser/resources/options/chromeos/quick_unlock_configure_overlay.js
@@ -74,9 +74,11 @@
       var screenLockDiv = lockScreen.root.querySelector('#screenLockDiv');
       screenLockDiv.hidden = true;
 
-      // The fingerprint settings on options is always hidden.
+      // The fingerprint settings and easy unlock on options is always hidden.
       var fingerprintDiv = lockScreen.root.querySelector('#fingerprintDiv');
       fingerprintDiv.hidden = true;
+      var easyUnlockDiv = lockScreen.root.querySelector('#easyUnlock');
+      easyUnlockDiv.hidden = true;
 
       var passwordPrompt = lockScreen.root.
           querySelector('settings-password-prompt-dialog');
diff --git a/chrome/browser/resources/options/compiled_resources.gyp b/chrome/browser/resources/options/compiled_resources.gyp
index 4ec0fcd..269ab04 100644
--- a/chrome/browser/resources/options/compiled_resources.gyp
+++ b/chrome/browser/resources/options/compiled_resources.gyp
@@ -44,7 +44,9 @@
           '../../../../ui/webui/resources/js/util.js',
           '../../../../chrome/browser/resources/chromeos/keyboard/keyboard_utils.js',
           '../../../../ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+          '../../../../ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
           '../settings/compiled_resources2.gyp:route',
+          '../settings/people_page/compiled_resources2.gyp:easy_unlock_browser_proxy',
           '../settings/people_page/compiled_resources2.gyp:fingerprint_browser_proxy',
           '../settings/people_page/compiled_resources2.gyp:lock_screen_constants',
           '../settings/people_page/compiled_resources2.gyp:lock_state_behavior',
diff --git a/chrome/browser/resources/options_resources.grd b/chrome/browser/resources/options_resources.grd
index 40f031ce..4ddc0f1 100644
--- a/chrome/browser/resources/options_resources.grd
+++ b/chrome/browser/resources/options_resources.grd
@@ -54,6 +54,18 @@
         <structure name="IDR_OPTIONS_SETUP_PIN_DIALOG_HTML"
                    file="settings/people_page/setup_pin_dialog.html"
                    type="chrome_html" />
+        <structure name="IDR_OPTIONS_EASY_UNLOCK_BROWSER_PROXY_JS"
+                   file="settings/people_page/easy_unlock_browser_proxy.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_EASY_UNLOCK_BROWSER_PROXY_HTML"
+                   file="settings/people_page/easy_unlock_browser_proxy.html"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_EASY_UNLOCK_TURN_OFF_DIALOG_JS"
+                   file="settings/people_page/easy_unlock_turn_off_dialog.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_EASY_UNLOCK_TURN_OFF_DIALOG_HTML"
+                   file="settings/people_page/easy_unlock_turn_off_dialog.html"
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_FINGERPRINT_LIST_JS"
                    file="settings/people_page/fingerprint_list.js"
                    type="chrome_html" />
diff --git a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
index 41543e0..3eb9053 100644
--- a/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/people_page/compiled_resources2.gyp
@@ -86,6 +86,38 @@
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
     {
+      'target_name': 'lock_screen',
+      'dependencies': [
+        '../compiled_resources2.gyp:route',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
+        'easy_unlock_browser_proxy',
+        'easy_unlock_turn_off_dialog',
+        'fingerprint_browser_proxy',
+        'lock_screen_constants',
+        'lock_state_behavior',
+        'password_prompt_dialog',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'lock_screen_constants',
+      'dependencies': [
+        '<(DEPTH)/ui/webui/resources/cr_elements/cr_profile_avatar_selector/compiled_resources2.gyp:cr_profile_avatar_selector',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
+      'target_name': 'lock_state_behavior',
+      'dependencies': [
+        '../compiled_resources2.gyp:route',
+        '<(EXTERNS_GYP):quick_unlock_private',
+      ],
+      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
+    },
+    {
       'target_name': 'manage_profile',
       'dependencies': [
         '../compiled_resources2.gyp:route',
@@ -122,10 +154,8 @@
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior',
-        'easy_unlock_browser_proxy',
-        'easy_unlock_turn_off_dialog',
+	'lock_screen',
         'lock_screen_constants',
         'lock_state_behavior',
         'profile_info_browser_proxy',
@@ -141,33 +171,6 @@
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
     {
-      'target_name': 'lock_state_behavior',
-      'dependencies': [
-        '../compiled_resources2.gyp:route',
-        '<(EXTERNS_GYP):quick_unlock_private',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'lock_screen_constants',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
-      'target_name': 'lock_screen',
-      'dependencies': [
-        '../compiled_resources2.gyp:route',
-        'fingerprint_browser_proxy',
-        'lock_screen_constants',
-        'lock_state_behavior',
-        'password_prompt_dialog',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
-      ],
-      'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
-    {
       'target_name': 'setup_fingerprint_dialog',
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
@@ -181,9 +184,9 @@
       'target_name': 'setup_pin_dialog',
       'dependencies': [
         '../compiled_resources2.gyp:route',
+        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         'lock_screen_constants',
         'password_prompt_dialog',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
       ],
       'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.html b/chrome/browser/resources/settings/people_page/lock_screen.html
index 6064de3..4fcf66d0 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.html
+++ b/chrome/browser/resources/settings/people_page/lock_screen.html
@@ -2,9 +2,12 @@
 <link rel="import" href="chrome://resources/html/action_link.html">
 <link rel="import" href="chrome://resources/html/action_link_css.html">
 <link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html">
 <link rel="import" href="../controls/settings_toggle_button.html">
+<link rel="import" href="easy_unlock_browser_proxy.html">
+<link rel="import" href="easy_unlock_turn_off_dialog.html">
 <link rel="import" href="fingerprint_browser_proxy.html">
 <link rel="import" href="lock_screen_constants.html">
 <link rel="import" href="lock_state_behavior.html">
@@ -19,6 +22,13 @@
 <dom-module id="settings-lock-screen">
   <template>
     <style include="settings-shared action-link">
+      #easyUnlock .start {
+        /* When the easy unlock toggle is shown, the easy unlock section's
+         * content becomes squashed to the top and bottom edges. Use padding to
+         * ensure the easy unlock content looks correct. */
+        padding: 11px 0;
+      }
+
       .radio-indent {
         -webkit-margin-start: 36px;
       }
@@ -75,12 +85,56 @@
         </div>
       </template>
 
+      <template is="dom-if" if="[[easyUnlockAllowed_]]">
+        <div id="easyUnlock" class="settings-box two-line">
+          <div class="start">
+            <div>$i18n{easyUnlockSectionTitle}</div>
+            <div class="secondary">
+              [[getEasyUnlockDescription_(easyUnlockEnabled_,
+                  '$i18nPolymer{easyUnlockDescription}',
+                  '$i18nPolymer{easyUnlockSetupIntro}')]]
+              <a target="_blank" href="$i18n{easyUnlockLearnMoreURL}">
+                $i18n{learnMore}
+              </a>
+              <template is="dom-if" if="[[getShowEasyUnlockToggle_(
+                  easyUnlockEnabled_, easyUnlockProximityDetectionAllowed_)]]">
+                <settings-toggle-button
+                    pref="{{prefs.easy_unlock.proximity_required}}"
+                    label="$i18n{easyUnlockRequireProximityLabel}">
+                </settings-toggle-button>
+              </template>
+            </div>
+          </div>
+          <div class="secondary-action">
+            <template is="dom-if" if="[[!easyUnlockEnabled_]]">
+              <paper-button id="easyUnlockSetup" class="secondary-button"
+                  on-tap="onEasyUnlockSetupTap_">
+                $i18n{easyUnlockSetupButton}
+              </paper-button>
+            </template>
+            <template is="dom-if" if="[[easyUnlockEnabled_]]">
+              <paper-button id="easyUnlockTurnOff" class="secondary-button"
+                  on-tap="onEasyUnlockTurnOffTap_">
+                $i18n{easyUnlockTurnOffButton}
+              </paper-button>
+            </template>
+          </div>
+        </div>
+      </template>
+
       <settings-password-prompt-dialog id="passwordPrompt"
           on-close="onPasswordClosed_" set-modes="{{setModes_}}">
       </settings-password-prompt-dialog>
+
       <settings-setup-pin-dialog id="setupPin" on-done="onPinSetupDone_"
           set-modes="[[setModes_]]">
       </settings-setup-pin-dialog>
+
+      <template is="dom-if" if="[[showEasyUnlockTurnOffDialog_]]">
+        <easy-unlock-turn-off-dialog id="easyUnlockTurnOffDialog"
+            on-close="onEasyUnlockTurnOffDialogClose_">
+        </easy-unlock-turn-off-dialog>
+      </template>
     </div>
   </template>
 
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index 419671a..0699ef1 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -17,13 +17,16 @@
 Polymer({
   is: 'settings-lock-screen',
 
-  behaviors: [I18nBehavior, LockStateBehavior, settings.RouteObserverBehavior],
+  behaviors: [
+    I18nBehavior,
+    LockStateBehavior,
+    WebUIListenerBehavior,
+    settings.RouteObserverBehavior,
+  ],
 
   properties: {
     /** Preferences state. */
-    prefs: {
-      type: Object
-    },
+    prefs: {type: Object},
 
     /**
      * setModes_ is a partially applied function that stores the previously
@@ -35,7 +38,7 @@
      */
     setModes_: {
       type: Object,
-      observer: 'onSetModesChanged_'
+      observer: 'onSetModesChanged_',
     },
 
     /**
@@ -47,7 +50,9 @@
      */
     writeUma_: {
       type: Object,
-      value: function() { return settings.recordLockScreenProgress; }
+      value: function() {
+        return settings.recordLockScreenProgress;
+      },
     },
 
     /**
@@ -79,10 +84,52 @@
       type: Number,
       value: 0,
     },
+
+    /**
+     * True if Easy Unlock is allowed on this machine.
+     */
+    easyUnlockAllowed_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('easyUnlockAllowed');
+      },
+      readOnly: true,
+    },
+
+    /**
+     * True if Easy Unlock is enabled.
+     */
+    easyUnlockEnabled_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('easyUnlockEnabled');
+      },
+    },
+
+    /**
+     * True if Easy Unlock's proximity detection feature is allowed.
+     */
+    easyUnlockProximityDetectionAllowed_: {
+      type: Boolean,
+      value: function() {
+        return loadTimeData.getBoolean('easyUnlockAllowed') &&
+            loadTimeData.getBoolean('easyUnlockProximityDetectionAllowed');
+      },
+      readOnly: true,
+    },
+
+    /** @private */
+    showEasyUnlockTurnOffDialog_: {
+      type: Boolean,
+      value: false,
+    },
   },
 
+  /** @private {?settings.EasyUnlockBrowserProxy} */
+  easyUnlockBrowserProxy_: null,
+
   /** @private {?settings.FingerprintBrowserProxy} */
-  browserProxy_: null,
+  fingerprintBrowserProxy_: null,
 
   /** selectedUnlockType is defined in LockStateBehavior. */
   observers: ['selectedUnlockTypeChanged_(selectedUnlockType)'],
@@ -91,7 +138,19 @@
   attached: function() {
     if (this.shouldAskForPassword_(settings.getCurrentRoute()))
       this.$.passwordPrompt.open();
-    this.browserProxy_ = settings.FingerprintBrowserProxyImpl.getInstance();
+
+    this.easyUnlockBrowserProxy_ =
+        settings.EasyUnlockBrowserProxyImpl.getInstance();
+    this.fingerprintBrowserProxy_ =
+        settings.FingerprintBrowserProxyImpl.getInstance();
+
+    if (this.easyUnlockAllowed_) {
+      this.addWebUIListener(
+          'easy-unlock-enabled-status',
+          this.handleEasyUnlockEnabledStatusChanged_.bind(this));
+      this.easyUnlockBrowserProxy_.getEnabledStatus().then(
+          this.handleEasyUnlockEnabledStatusChanged_.bind(this));
+    }
   },
 
   /**
@@ -102,9 +161,8 @@
    */
   currentRouteChanged: function(newRoute, oldRoute) {
     if (newRoute == settings.Route.LOCK_SCREEN &&
-        this.fingerprintUnlockEnabled_ &&
-        this.browserProxy_) {
-      this.browserProxy_.getNumFingerprints().then(
+        this.fingerprintUnlockEnabled_ && this.fingerprintBrowserProxy_) {
+      this.fingerprintBrowserProxy_.getNumFingerprints().then(
           function(numFingerprints) {
             this.numFingerprints_ = numFingerprints;
           }.bind(this));
@@ -206,4 +264,59 @@
   shouldAskForPassword_: function(route) {
     return route == settings.Route.LOCK_SCREEN && !this.setModes_;
   },
+
+  /**
+   * Handler for when the Easy Unlock enabled status has changed.
+   * @private
+   */
+  handleEasyUnlockEnabledStatusChanged_: function(easyUnlockEnabled) {
+    this.easyUnlockEnabled_ = easyUnlockEnabled;
+    this.showEasyUnlockTurnOffDialog_ =
+        easyUnlockEnabled && this.showEasyUnlockTurnOffDialog_;
+  },
+
+  /** @private */
+  onEasyUnlockSetupTap_: function() {
+    this.easyUnlockBrowserProxy_.startTurnOnFlow();
+  },
+
+  /**
+   * @param {!Event} e
+   * @private
+   */
+  onEasyUnlockTurnOffTap_: function(e) {
+    // Prevent the end of the tap event from focusing what is underneath the
+    // button.
+    e.preventDefault();
+    this.showEasyUnlockTurnOffDialog_ = true;
+  },
+
+  /** @private */
+  onEasyUnlockTurnOffDialogClose_: function() {
+    this.showEasyUnlockTurnOffDialog_ = false;
+
+    // Restores focus on close to either the turn-off or set-up button,
+    // whichever is being displayed.
+    this.$$('.secondary-button').focus();
+  },
+
+  /**
+   * @param {boolean} enabled
+   * @param {!string} enabledStr
+   * @param {!string} disabledStr
+   * @private
+   */
+  getEasyUnlockDescription_: function(enabled, enabledStr, disabledStr) {
+    return enabled ? enabledStr : disabledStr;
+  },
+
+  /**
+   * @param {boolean} easyUnlockEnabled
+   * @param {boolean} proximityDetectionAllowed
+   * @private
+   */
+  getShowEasyUnlockToggle_: function(
+      easyUnlockEnabled, proximityDetectionAllowed) {
+    return easyUnlockEnabled && proximityDetectionAllowed;
+  },
 });
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 4d8794c5..9e488b3 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -22,8 +22,6 @@
 
 <if expr="chromeos">
 <link rel="import" href="change_picture.html">
-<link rel="import" href="easy_unlock_browser_proxy.html">
-<link rel="import" href="easy_unlock_turn_off_dialog.html">
 <link rel="import" href="fingerprint_list.html">
 <link rel="import" href="lock_screen.html">
 <link rel="import" href="lock_state_behavior.html">
@@ -72,11 +70,6 @@
         color: var(--settings-error-color);
       }
 
-      #easy-unlock .start {
-        /* Use padding to ensure taller content looks correct. */
-        padding: 11px 0;
-      }
-
       .icon-container {
         display: flex;
         flex-shrink: 0;
@@ -219,50 +212,6 @@
                 aria-describedby="lockScrenSecondary"></button>
           </div>
         </template>
-
-        <template is="dom-if" if="[[easyUnlockAllowed_]]">
-          <div id="easy-unlock" class="settings-box two-line">
-            <div class="start">
-              <div>$i18n{easyUnlockSectionTitle}</div>
-              <div class="secondary">
-                <template is="dom-if" if="[[!easyUnlockEnabled_]]">
-                  $i18n{easyUnlockSetupIntro}
-                </template>
-                <template is="dom-if" if="[[easyUnlockEnabled_]]">
-                  $i18n{easyUnlockDescription}
-                </template>
-                <a target="_blank" href="$i18n{easyUnlockLearnMoreURL}">
-                  $i18n{learnMore}
-                </a>
-                <!-- TODO(dbeam): this should be 1 dom-if with a method instead
-                     of 2 nested dom-ifs. -->
-                <template is="dom-if" if="[[easyUnlockEnabled_]]">
-                  <template is="dom-if"
-                      if="[[easyUnlockProximityDetectionAllowed_]]">
-                    <settings-toggle-button
-                        pref="{{prefs.easy_unlock.proximity_required}}"
-                        label="$i18n{easyUnlockRequireProximityLabel}">
-                    </settings-toggle-button>
-                  </template>
-                </template>
-              </div>
-            </div>
-            <div class="secondary-action">
-              <template is="dom-if" if="[[!easyUnlockEnabled_]]">
-                <paper-button id="easyUnlockSetup" class="secondary-button"
-                    on-tap="onEasyUnlockSetupTap_">
-                  $i18n{easyUnlockSetupButton}
-                </paper-button>
-              </template>
-              <template is="dom-if" if="[[easyUnlockEnabled_]]">
-                <paper-button id="easyUnlockTurnOff" class="secondary-button"
-                    on-tap="onEasyUnlockTurnOffTap_">
-                  $i18n{easyUnlockTurnOffButton}
-                </paper-button>
-              </template>
-            </div>
-          </div>
-        </template>
 </if>
 
         <div id="manage-other-people-subpage-trigger"
@@ -286,8 +235,7 @@
               on-tap="onManageSupervisedUsers_" actionable>
             <div class="start">$i18n{manageSupervisedUsers}</div>
             <button class="icon-external" is="paper-icon-button-light"
-                aria-label="$i18n{manageSupervisedUsers}"
-                aria-describedby="manageSupervisedUsersSecondary"></button>
+                aria-label="$i18n{manageSupervisedUsers}"></button>
           </div>
         </template>
       </neon-animatable>
@@ -396,13 +344,6 @@
       </settings-import-data-dialog>
     </template>
 
-<if expr="chromeos">
-    <template is="dom-if" if="[[showEasyUnlockTurnOffDialog_]]">
-      <easy-unlock-turn-off-dialog id="easyUnlockTurnOffDialog"
-          on-close="onEasyUnlockTurnOffDialogClose_">
-      </easy-unlock-turn-off-dialog>
-    </template>
-</if>
   </template>
   <script src="people_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index e222cc4..b90834a 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -97,53 +97,6 @@
       },
       readOnly: true,
     },
-
-    /** @private {!settings.EasyUnlockBrowserProxy} */
-    easyUnlockBrowserProxy_: {
-      type: Object,
-      value: function() {
-        return settings.EasyUnlockBrowserProxyImpl.getInstance();
-      },
-    },
-
-    /**
-     * True if Easy Unlock is allowed on this machine.
-     */
-    easyUnlockAllowed_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('easyUnlockAllowed');
-      },
-      readOnly: true,
-    },
-
-    /**
-     * True if Easy Unlock is enabled.
-     */
-    easyUnlockEnabled_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('easyUnlockEnabled');
-      },
-    },
-
-    /**
-     * True if Easy Unlock's proximity detection feature is allowed.
-     */
-    easyUnlockProximityDetectionAllowed_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('easyUnlockAllowed') &&
-            loadTimeData.getBoolean('easyUnlockProximityDetectionAllowed');
-      },
-      readOnly: true,
-    },
-
-    /** @private */
-    showEasyUnlockTurnOffDialog_: {
-      type: Boolean,
-      value: false,
-    },
 // </if>
 
     /** @private {!Map<string, string>} */
@@ -192,16 +145,6 @@
         this.handleSyncStatus_.bind(this));
     this.addWebUIListener('sync-status-changed',
                           this.handleSyncStatus_.bind(this));
-
-// <if expr="chromeos">
-    if (this.easyUnlockAllowed_) {
-      this.addWebUIListener(
-          'easy-unlock-enabled-status',
-          this.handleEasyUnlockEnabledStatusChanged_.bind(this));
-      this.easyUnlockBrowserProxy_.getEnabledStatus().then(
-          this.handleEasyUnlockEnabledStatusChanged_.bind(this));
-    }
-// </if>
   },
 
   /** @protected */
@@ -292,18 +235,6 @@
     this.syncStatus = syncStatus;
   },
 
-// <if expr="chromeos">
-  /**
-   * Handler for when the Easy Unlock enabled status has changed.
-   * @private
-   */
-  handleEasyUnlockEnabledStatusChanged_: function(easyUnlockEnabled) {
-    this.easyUnlockEnabled_ = easyUnlockEnabled;
-    this.showEasyUnlockTurnOffDialog_ =
-        easyUnlockEnabled && this.showEasyUnlockTurnOffDialog_;
-  },
-// </if>
-
   /** @private */
   onPictureTap_: function() {
 // <if expr="chromeos">
@@ -404,25 +335,6 @@
   onConfigureLockTap_: function() {
     settings.navigateTo(settings.Route.LOCK_SCREEN);
   },
-
-  /** @private */
-  onEasyUnlockSetupTap_: function() {
-    this.easyUnlockBrowserProxy_.startTurnOnFlow();
-  },
-
-  /**
-   * @param {!Event} e
-   * @private
-   */
-  onEasyUnlockTurnOffTap_: function(e) {
-    e.preventDefault();
-    this.showEasyUnlockTurnOffDialog_ = true;
-  },
-
-  /** @private */
-  onEasyUnlockTurnOffDialogClose_: function() {
-    this.showEasyUnlockTurnOffDialog_ = false;
-  },
 // </if>
 
   /** @private */
diff --git a/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc b/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
index c74e1da..9631966 100644
--- a/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
+++ b/chrome/browser/ui/ash/app_list/app_list_interactive_uitest.cc
@@ -14,6 +14,7 @@
 #include "base/run_loop.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "ui/app_list/presenter/app_list.h"
+#include "ui/aura/window.h"
 #include "ui/events/test/event_generator.h"
 
 using AppListTest = InProcessBrowserTest;
@@ -25,29 +26,28 @@
   ash::ShelfWidget* shelf_widget = shelf->shelf_widget();
   ash::AppListButton* app_list_button = shelf_widget->GetAppListButton();
 
-  ash::WmWindow* root_window =
-      ash::WmWindow::Get(ash::wm::GetActiveWindow())->GetRootWindow();
-  ash::WmWindow* app_list_container = root_window->GetChildByShellWindowId(
-      ash::kShellWindowId_AppListContainer);
+  aura::Window* root_window = ash::wm::GetActiveWindow()->GetRootWindow();
+  aura::Window* app_list_container =
+      root_window->GetChildById(ash::kShellWindowId_AppListContainer);
   ui::test::EventGenerator generator(shelf_widget->GetNativeWindow());
 
   // Click the app list button to show the app list.
   ash::Shell* shell = ash::Shell::Get();
   EXPECT_FALSE(shell->app_list()->GetTargetVisibility());
-  EXPECT_EQ(0u, app_list_container->GetChildren().size());
+  EXPECT_EQ(0u, app_list_container->children().size());
   EXPECT_FALSE(app_list_button->is_showing_app_list());
   generator.set_current_location(
       app_list_button->GetBoundsInScreen().CenterPoint());
   generator.ClickLeftButton();
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(shell->app_list()->GetTargetVisibility());
-  EXPECT_EQ(1u, app_list_container->GetChildren().size());
+  EXPECT_EQ(1u, app_list_container->children().size());
   EXPECT_TRUE(app_list_button->is_showing_app_list());
 
   // Click the button again to dismiss the app list; the window animates closed.
   generator.ClickLeftButton();
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(shell->app_list()->GetTargetVisibility());
-  EXPECT_EQ(1u, app_list_container->GetChildren().size());
+  EXPECT_EQ(1u, app_list_container->children().size());
   EXPECT_FALSE(app_list_button->is_showing_app_list());
 }
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
index 577fed7..74adde50 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views_linux.cc
@@ -62,7 +62,8 @@
 
 ChromeBrowserMainExtraPartsViewsLinux::
     ~ChromeBrowserMainExtraPartsViewsLinux() {
-  views::X11DesktopHandler::get()->RemoveObserver(this);
+  if (views::X11DesktopHandler::get_dont_create())
+    views::X11DesktopHandler::get_dont_create()->RemoveObserver(this);
 }
 
 void ChromeBrowserMainExtraPartsViewsLinux::PreEarlyInitialization() {
diff --git a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
index e45d1b2a..f6d22b31 100644
--- a/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_payment_response_browsertest.cc
@@ -152,7 +152,7 @@
   ExpectBodyContains(std::vector<base::string16>{
       base::UTF8ToUTF16("\"payerName\": \"John H. Doe\""),
       base::UTF8ToUTF16("\"payerEmail\": \"johndoe@hades.com\""),
-      base::UTF8ToUTF16("\"payerPhone\": \"16502111111\"")});
+      base::UTF8ToUTF16("\"payerPhone\": \"+16502111111\"")});
 }
 
 class PaymentRequestPaymentResponseOneContactDetailTest
diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
index f7a7ddd..db8dec1d 100644
--- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc
@@ -877,8 +877,13 @@
     SigninScreenHandler::SetUserInputMethod(populated_email_,
                                             gaia_ime_state.get());
   } else {
-    std::vector<std::string> input_methods =
-        imm->GetInputMethodUtil()->GetHardwareLoginInputMethodIds();
+    std::vector<std::string> input_methods;
+    if (gaia_ime_state->GetAllowedInputMethods().empty()) {
+      input_methods =
+          imm->GetInputMethodUtil()->GetHardwareLoginInputMethodIds();
+    } else {
+      input_methods = gaia_ime_state->GetAllowedInputMethods();
+    }
     const std::string owner_im = SigninScreenHandler::GetUserLastInputMethod(
         user_manager::UserManager::Get()->GetOwnerAccountId().GetUserEmail());
     const std::string system_im = g_browser_process->local_state()->GetString(
diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
index bcb26d6..c67657c9 100644
--- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc
@@ -329,7 +329,6 @@
       chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
   if (keyboard)
     keyboard->AddObserver(this);
-  OnAllowedInputMethodsChanged();
   allowed_input_methods_subscription_ =
       chromeos::CrosSettings::Get()->AddSettingsObserver(
           chromeos::kDeviceLoginScreenInputMethods,
@@ -1377,6 +1376,7 @@
   webui_visible_ = true;
   if (preferences_changed_delayed_)
     OnPreferencesChanged();
+  OnAllowedInputMethodsChanged();
 }
 
 void SigninScreenHandler::HandleCancelPasswordChangedFlow(
@@ -1603,6 +1603,7 @@
 
 void SigninScreenHandler::OnShowAddUser() {
   is_account_picker_showing_first_time_ = false;
+  EnforcePolicyInputMethods(std::string());
   gaia_screen_handler_->ShowGaiaAsync();
 }
 
@@ -1624,6 +1625,9 @@
 }
 
 void SigninScreenHandler::OnAllowedInputMethodsChanged() {
+  if (!webui_visible_)
+    return;
+
   if (focused_pod_account_id_) {
     std::string user_input_method =
         GetUserLastInputMethod(focused_pod_account_id_->GetUserEmail());
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_browsertest.cc b/chrome/browser/ui/webui/options/clear_browser_data_browsertest.cc
index 700d0b4..6d49702 100644
--- a/chrome/browser/ui/webui/options/clear_browser_data_browsertest.cc
+++ b/chrome/browser/ui/webui/options/clear_browser_data_browsertest.cc
@@ -6,6 +6,8 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "chrome/browser/browsing_data/browsing_data_remover.h"
+#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
 #include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -57,7 +59,8 @@
 IN_PROC_BROWSER_TEST_F(ClearBrowserDataBrowserTest,
                        MAYBE_CommitButtonDisabledWhileDeletionInProgress) {
   const char kCommitButtonId[] = "#clear-browser-data-commit";
-  BrowsingDataRemoverCompletionInhibitor completion_inhibitor;
+  BrowsingDataRemoverCompletionInhibitor completion_inhibitor(
+      BrowsingDataRemoverFactory::GetForBrowserContext(browser()->profile()));
 
   // Navigate to the Clear Browsing Data dialog to ensure that the commit button
   // is initially enabled, usable, and gets disabled after having been pressed.
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index f82ca20..4fea4576 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -139,6 +139,14 @@
 constexpr char kLockScreenJSPath[] = "people_page/lock_screen.js";
 constexpr char kSetupPinHTMLPath[] = "people_page/setup_pin_dialog.html";
 constexpr char kSetupPinJSPath[] = "people_page/setup_pin_dialog.js";
+constexpr char kEasyUnlockBrowserProxyHTMLPath[] =
+    "people_page/easy_unlock_browser_proxy.html";
+constexpr char kEasyUnlockBrowserProxyJSPath[] =
+    "people_page/easy_unlock_browser_proxy.js";
+constexpr char kEasyUnlockTurnOffDialogHTMLPath[] =
+    "people_page/easy_unlock_turn_off_dialog.html";
+constexpr char kEasyUnlockTurnOffDialogJSPath[] =
+    "people_page/easy_unlock_turn_off_dialog.js";
 constexpr char kFingerprintListHTMLPath[] = "people_page/fingerprint_list.html";
 constexpr char kFingerprintListJSPath[] = "people_page/fingerprint_list.js";
 constexpr char kSetupFingerprintHTMLPath[] =
@@ -311,6 +319,14 @@
       IDR_OPTIONS_LOCK_STATE_BEHAVIOR_JS;
   path_to_idr_map_[kLockScreenHTMLPath] = IDR_OPTIONS_LOCK_SCREEN_HTML;
   path_to_idr_map_[kLockScreenJSPath] = IDR_OPTIONS_LOCK_SCREEN_JS;
+  path_to_idr_map_[kEasyUnlockBrowserProxyHTMLPath] =
+      IDR_OPTIONS_EASY_UNLOCK_BROWSER_PROXY_HTML;
+  path_to_idr_map_[kEasyUnlockBrowserProxyJSPath] =
+      IDR_OPTIONS_EASY_UNLOCK_BROWSER_PROXY_JS;
+  path_to_idr_map_[kEasyUnlockTurnOffDialogHTMLPath] =
+      IDR_OPTIONS_EASY_UNLOCK_TURN_OFF_DIALOG_HTML;
+  path_to_idr_map_[kEasyUnlockTurnOffDialogJSPath] =
+      IDR_OPTIONS_EASY_UNLOCK_TURN_OFF_DIALOG_JS;
   path_to_idr_map_[kSetupPinHTMLPath] = IDR_OPTIONS_SETUP_PIN_DIALOG_HTML;
   path_to_idr_map_[kSetupPinJSPath] = IDR_OPTIONS_SETUP_PIN_DIALOG_JS;
   path_to_idr_map_[kFingerprintListHTMLPath] =
diff --git a/chrome/browser/ui/webui/profile_helper_browsertest.cc b/chrome/browser/ui/webui/profile_helper_browsertest.cc
index 5b09006..ae889fc 100644
--- a/chrome/browser/ui/webui/profile_helper_browsertest.cc
+++ b/chrome/browser/ui/webui/profile_helper_browsertest.cc
@@ -6,7 +6,9 @@
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/browsing_data/browsing_data_remover_impl.h"
+#include "chrome/browser/browsing_data/browsing_data_remover.h"
+#include "chrome/browser/browsing_data/browsing_data_remover_factory.h"
+#include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -66,29 +68,6 @@
   ScopedObserver<BrowserList, chrome::BrowserListObserver> scoped_observer_;
 };
 
-// TODO(bug 704601): remove it when bug is fixed.
-class BrowsingDataRemoverObserver
-    : public BrowsingDataRemoverImpl::CompletionInhibitor {
- public:
-  explicit BrowsingDataRemoverObserver(const base::Closure& callback)
-      : callback_(callback) {
-    BrowsingDataRemoverImpl::set_completion_inhibitor_for_testing(this);
-  }
-  ~BrowsingDataRemoverObserver() override {
-    BrowsingDataRemoverImpl::set_completion_inhibitor_for_testing(nullptr);
-  }
-
- private:
-  void OnBrowsingDataRemoverWouldComplete(
-      BrowsingDataRemoverImpl* remover,
-      const base::Closure& continue_to_completion) override {
-    continue_to_completion.Run();
-    callback_.Run();
-  }
-
-  const base::Closure callback_;
-};
-
 }  // namespace
 
 using ProfileHelperTest = InProcessBrowserTest;
@@ -205,11 +184,12 @@
   Profile* additional_profile = CreateProfile();
   EXPECT_EQ(2u, storage.GetNumberOfProfiles());
 
-  base::RunLoop loop;
-  BrowsingDataRemoverObserver observer(loop.QuitClosure());
+  BrowsingDataRemoverCompletionInhibitor inhibitor(
+      BrowsingDataRemoverFactory::GetForBrowserContext(additional_profile));
   webui::DeleteProfileAtPath(additional_profile->GetPath(), &web_ui,
                              ProfileMetrics::DELETE_PROFILE_SETTINGS);
-  loop.Run();
+  inhibitor.BlockUntilNearCompletion();
+  inhibitor.ContinueToCompletion();
 
   EXPECT_EQ(1u, browser_list->size());
   EXPECT_TRUE(base::ContainsValue(*browser_list, original_browser));
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index 40e20be..0ee7196 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -596,7 +596,14 @@
 
   ContentSettingsPattern pattern =
       ContentSettingsPattern::FromString(pattern_string);
-  ResolveJavascriptCallback(*callback_id, base::Value(pattern.IsValid()));
+  bool valid = pattern.IsValid();
+
+  // If the input is just '*' don't allow it, even though it's a valid pattern.
+  // This changes the default setting.
+  if (pattern == ContentSettingsPattern::Wildcard())
+    valid = false;
+
+  ResolveJavascriptCallback(*callback_id, base::Value(valid));
 }
 
 void SiteSettingsHandler::HandleUpdateIncognitoStatus(
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
index 070d4ca..a156676 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -353,6 +353,16 @@
   invalid.AppendString(bad_pattern);
   handler()->HandleIsPatternValid(&invalid);
   ValidatePattern(false, 2U);
+
+  // The wildcard pattern ('*') is a valid pattern, but not allowed to be
+  // entered in site settings as it changes the default setting.
+  // (crbug.com/709539).
+  base::ListValue invalid_wildcard;
+  std::string bad_pattern_wildcard("*");
+  invalid_wildcard.AppendString(kCallbackId);
+  invalid_wildcard.AppendString(bad_pattern_wildcard);
+  handler()->HandleIsPatternValid(&invalid_wildcard);
+  ValidatePattern(false, 3U);
 }
 
 TEST_F(SiteSettingsHandlerTest, Incognito) {
diff --git a/chrome/test/base/mash_browser_tests_main.cc b/chrome/test/base/mash_browser_tests_main.cc
index bc097e1..d5ea89c 100644
--- a/chrome/test/base/mash_browser_tests_main.cc
+++ b/chrome/test/base/mash_browser_tests_main.cc
@@ -44,7 +44,7 @@
     FILE_PATH_LITERAL("mash_browser_tests_catalog.json");
 
 void ConnectToDefaultApps(service_manager::Connector* connector) {
-  connector->Connect(mash::session::mojom::kServiceName);
+  connector->StartService(mash::session::mojom::kServiceName);
 }
 
 class MashTestSuite : public ChromeTestSuite {
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 2659015..b9b1a1ae 100644
--- a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
@@ -37,7 +37,7 @@
 GEN('#define MAYBE_EasyUnlock EasyUnlock');
 GEN('#endif');
 
-// Runs change picture tests.
+// Runs easy unlock tests.
 TEST_F('SettingsEasyUnlockBrowserTest', 'MAYBE_EasyUnlock', function() {
   /**
    * A test version of EasyUnlockBrowserProxy. Provides helper methods
@@ -99,20 +99,14 @@
     },
   };
 
-  /** @type {?SettingsPeoplePageElement} */
-  var page = null;
+  /** @type {?SettingsLockScreenElement} */
+  var lockScreen = null;
 
   /** @type {?TestEasyUnlockBrowserProxy} */
   var browserProxy = null;
 
-  /** @type {?CrSettingsPrefs} */
-  var prefs = null;
-
-  var self = this;
-
   suite('SettingsEasyUnlock', function() {
     suiteSetup(function() {
-      self.basicPage.set('pageVisibility.people', true);
       Polymer.dom.flush();
 
       // These overrides are necessary for this test to function on ChromeOS
@@ -131,10 +125,6 @@
         easyUnlockTurnOffDescription: '',
         easyUnlockTurnOffButton: '',
       });
-
-      // Before clearing the body, save a copy of the real prefs so we can
-      // cleanly re-create the People page element.
-      prefs = document.querySelector('settings-ui').$$('settings-prefs').prefs;
     });
 
     setup(function() {
@@ -142,25 +132,19 @@
       settings.EasyUnlockBrowserProxyImpl.instance_ = browserProxy;
 
       PolymerTest.clearBody();
-      page = document.createElement('settings-people-page');
-      page.currentRoute = {
-        page: 'basic',
-        section: '',
-        subpage: [],
-      };
-      page.prefs = prefs;
+      lockScreen = document.createElement('settings-lock-screen');
     });
 
     test('setup button', function() {
-      document.body.appendChild(page);
+      document.body.appendChild(lockScreen);
 
       return browserProxy.whenCalled('getEnabledStatus').then(function() {
-        assertTrue(page.easyUnlockAllowed_);
-        expectFalse(page.easyUnlockEnabled_);
+        assertTrue(lockScreen.easyUnlockAllowed_);
+        expectFalse(lockScreen.easyUnlockEnabled_);
 
         Polymer.dom.flush();
 
-        var setupButton = page.$$('#easyUnlockSetup');
+        var setupButton = lockScreen.$$('#easyUnlockSetup');
         assertTrue(!!setupButton);
         expectFalse(setupButton.hidden);
 
@@ -171,70 +155,77 @@
 
     test('turn off dialog', function() {
       browserProxy.setEnabledStatus(true);
-      document.body.appendChild(page);
+      document.body.appendChild(lockScreen);
 
       var turnOffDialog = null;
 
-      return browserProxy.whenCalled('getEnabledStatus').then(function() {
-        assertTrue(page.easyUnlockAllowed_);
-        expectTrue(page.easyUnlockEnabled_);
+      return browserProxy.whenCalled('getEnabledStatus')
+          .then(function() {
+            assertTrue(lockScreen.easyUnlockAllowed_);
+            expectTrue(lockScreen.easyUnlockEnabled_);
 
-        Polymer.dom.flush();
+            Polymer.dom.flush();
 
-        var turnOffButton = page.$$('#easyUnlockTurnOff');
-        assertTrue(!!turnOffButton);
-        expectFalse(turnOffButton.hidden)
+            var turnOffButton = lockScreen.$$('#easyUnlockTurnOff');
+            assertTrue(!!turnOffButton);
+            expectFalse(turnOffButton.hidden)
 
-        MockInteractions.tap(turnOffButton);
-        return browserProxy.whenCalled('getTurnOffFlowStatus');
-      }).then(function() {
-        Polymer.dom.flush();
+            MockInteractions.tap(turnOffButton);
+            return browserProxy.whenCalled('getTurnOffFlowStatus');
+          })
+          .then(function() {
+            Polymer.dom.flush();
 
-        turnOffDialog = page.$$('#easyUnlockTurnOffDialog');
-        assertTrue(!!turnOffDialog);
+            turnOffDialog = lockScreen.$$('#easyUnlockTurnOffDialog');
+            assertTrue(!!turnOffDialog);
 
-        // Verify that elements on the turn off dialog are hidden or active
-        // according to the easy unlock turn off status.
-        var turnOffDialogButtonContainer =
-            turnOffDialog.$$('.button-container');
-        var turnOffDialogButtonSpinner = turnOffDialog.$$('paper-spinner');
-        var turnOffDialogConfirmButton = turnOffDialog.$$('#turnOff');
-        var turnOffDialogCancelButton = turnOffDialog.$$('.cancel-button');
-        assertTrue(!!turnOffDialogButtonContainer);
-        assertTrue(!!turnOffDialogButtonSpinner);
-        assertTrue(!!turnOffDialogConfirmButton);
-        assertTrue(!!turnOffDialogCancelButton);
+            // Verify that elements on the turn off dialog are hidden or active
+            // according to the easy unlock turn off status.
+            var turnOffDialogButtonContainer =
+                turnOffDialog.$$('.button-container');
+            var turnOffDialogButtonSpinner = turnOffDialog.$$('paper-spinner');
+            var turnOffDialogConfirmButton = turnOffDialog.$$('#turnOff');
+            var turnOffDialogCancelButton = turnOffDialog.$$('.cancel-button');
+            assertTrue(!!turnOffDialogButtonContainer);
+            assertTrue(!!turnOffDialogButtonSpinner);
+            assertTrue(!!turnOffDialogConfirmButton);
+            assertTrue(!!turnOffDialogCancelButton);
 
-        cr.webUIListenerCallback('easy-unlock-turn-off-flow-status', 'offline');
-        expectTrue(turnOffDialogButtonContainer.hidden);
-        expectFalse(turnOffDialogButtonSpinner.active);
+            cr.webUIListenerCallback(
+                'easy-unlock-turn-off-flow-status', 'offline');
+            expectTrue(turnOffDialogButtonContainer.hidden);
+            expectFalse(turnOffDialogButtonSpinner.active);
 
-        cr.webUIListenerCallback('easy-unlock-turn-off-flow-status', 'pending');
-        expectFalse(turnOffDialogButtonContainer.hidden);
-        expectTrue(turnOffDialogButtonSpinner.active);
+            cr.webUIListenerCallback(
+                'easy-unlock-turn-off-flow-status', 'pending');
+            expectFalse(turnOffDialogButtonContainer.hidden);
+            expectTrue(turnOffDialogButtonSpinner.active);
 
-        cr.webUIListenerCallback('easy-unlock-turn-off-flow-status',
-            'server-error');
-        expectFalse(turnOffDialogButtonContainer.hidden);
-        expectTrue(turnOffDialogCancelButton.hidden);
+            cr.webUIListenerCallback(
+                'easy-unlock-turn-off-flow-status', 'server-error');
+            expectFalse(turnOffDialogButtonContainer.hidden);
+            expectTrue(turnOffDialogCancelButton.hidden);
 
-        cr.webUIListenerCallback('easy-unlock-turn-off-flow-status', 'idle');
-        expectFalse(turnOffDialogConfirmButton.hidden);
+            cr.webUIListenerCallback(
+                'easy-unlock-turn-off-flow-status', 'idle');
+            expectFalse(turnOffDialogConfirmButton.hidden);
 
-        MockInteractions.tap(turnOffDialogConfirmButton);
+            MockInteractions.tap(turnOffDialogConfirmButton);
 
-        return browserProxy.whenCalled('startTurnOffFlow');
-      }).then(function() {
-        // To signal successful turnoff, the enabled status is broadcast
-        // as false. At that point, the dialog should close and cancel
-        // any in-progress turnoff flow. The cancellation should be
-        // a no-op assuming the turnoff originated from this tab.
-        cr.webUIListenerCallback('easy-unlock-enabled-status', false);
-        return browserProxy.whenCalled('cancelTurnOffFlow');
-      }).then(function() {
-        Polymer.dom.flush();
-        expectFalse(turnOffDialog.$.dialog.open);
-      });
+            return browserProxy.whenCalled('startTurnOffFlow');
+          })
+          .then(function() {
+            // To signal successful turnoff, the enabled status is broadcast
+            // as false. At that point, the dialog should close and cancel
+            // any in-progress turnoff flow. The cancellation should be
+            // a no-op assuming the turnoff originated from this tab.
+            cr.webUIListenerCallback('easy-unlock-enabled-status', false);
+            return browserProxy.whenCalled('cancelTurnOffFlow');
+          })
+          .then(function() {
+            Polymer.dom.flush();
+            expectFalse(turnOffDialog.$.dialog.open);
+          });
     });
   });
 
diff --git a/components/error_page/common/localized_error.cc b/components/error_page/common/localized_error.cc
index 9047cdc..32cb9e9 100644
--- a/components/error_page/common/localized_error.cc
+++ b/components/error_page/common/localized_error.cc
@@ -248,6 +248,12 @@
    SUGGEST_CONTACT_ADMINISTRATOR,
    SHOW_NO_BUTTONS,
   },
+  {net::ERR_SSL_VERSION_INTERFERENCE,
+   IDS_ERRORPAGES_HEADING_NOT_AVAILABLE,
+   IDS_ERRORPAGES_SUMMARY_CONNECTION_FAILED,
+   SUGGEST_CHECK_CONNECTION | SUGGEST_FIREWALL_CONFIG | SUGGEST_PROXY_CONFIG,
+   SHOW_BUTTON_RELOAD,
+  },
   {net::ERR_SSL_WEAK_SERVER_EPHEMERAL_DH_KEY,
    IDS_ERRORPAGES_HEADING_INSECURE_CONNECTION,
    IDS_ERRORPAGES_SUMMARY_SSL_SECURITY_ERROR,
diff --git a/components/exo/shell_surface.cc b/components/exo/shell_surface.cc
index 7b05e9a..7fe5345 100644
--- a/components/exo/shell_surface.cc
+++ b/components/exo/shell_surface.cc
@@ -845,6 +845,21 @@
   return title_;
 }
 
+void ShellSurface::SaveWindowPlacement(const gfx::Rect& bounds,
+                                       ui::WindowShowState show_state) {
+  if (bounds_mode_ != BoundsMode::CLIENT)
+    WidgetDelegate::SaveWindowPlacement(bounds, show_state);
+}
+
+bool ShellSurface::GetSavedWindowPlacement(
+    const views::Widget* widget,
+    gfx::Rect* bounds,
+    ui::WindowShowState* show_state) const {
+  if (bounds_mode_ != BoundsMode::CLIENT)
+    return WidgetDelegate::GetSavedWindowPlacement(widget, bounds, show_state);
+  return false;
+}
+
 void ShellSurface::WindowClosing() {
   if (resizer_)
     EndDrag(true /* revert */);
diff --git a/components/exo/shell_surface.h b/components/exo/shell_surface.h
index 80c93ea..1356c9a 100644
--- a/components/exo/shell_surface.h
+++ b/components/exo/shell_surface.h
@@ -225,6 +225,11 @@
   bool CanMaximize() const override;
   bool CanMinimize() const override;
   base::string16 GetWindowTitle() const override;
+  void SaveWindowPlacement(const gfx::Rect& bounds,
+                           ui::WindowShowState show_state) override;
+  bool GetSavedWindowPlacement(const views::Widget* widget,
+                               gfx::Rect* bounds,
+                               ui::WindowShowState* show_state) const override;
   void WindowClosing() override;
   views::Widget* GetWidget() override;
   const views::Widget* GetWidget() const override;
diff --git a/components/feature_engagement_tracker/internal/BUILD.gn b/components/feature_engagement_tracker/internal/BUILD.gn
index fcdd0828..00badef3 100644
--- a/components/feature_engagement_tracker/internal/BUILD.gn
+++ b/components/feature_engagement_tracker/internal/BUILD.gn
@@ -38,6 +38,10 @@
     "store.h",
   ]
 
+  public_deps = [
+    "//components/feature_engagement_tracker/internal/proto",
+  ]
+
   deps = [
     "//base",
     "//components/feature_engagement_tracker/public",
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
index 4917161..daa58c3 100644
--- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
+++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl_unittest.cc
@@ -8,7 +8,9 @@
 
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/feature_engagement_tracker/internal/editable_configuration.h"
 #include "components/feature_engagement_tracker/internal/in_memory_store.h"
@@ -36,7 +38,7 @@
 
 class FeatureEngagementTrackerImplTest : public ::testing::Test {
  public:
-  void SetUp() override {
+  FeatureEngagementTrackerImplTest() {
     std::unique_ptr<Store> store = base::MakeUnique<InMemoryStore>();
     std::unique_ptr<EditableConfiguration> configuration =
         base::MakeUnique<EditableConfiguration>();
@@ -52,9 +54,12 @@
 
     tracker_.reset(new FeatureEngagementTrackerImpl(
         std::move(store), std::move(configuration), std::move(validator)));
+    // Ensure all initialization is finished.
+    base::RunLoop().RunUntilIdle();
   }
 
  protected:
+  base::MessageLoop message_loop_;
   std::unique_ptr<FeatureEngagementTrackerImpl> tracker_;
   base::test::ScopedFeatureList scoped_feature_list_;
 };
diff --git a/components/feature_engagement_tracker/internal/in_memory_store.cc b/components/feature_engagement_tracker/internal/in_memory_store.cc
index 113fa037..0c9fa6e4 100644
--- a/components/feature_engagement_tracker/internal/in_memory_store.cc
+++ b/components/feature_engagement_tracker/internal/in_memory_store.cc
@@ -4,22 +4,43 @@
 
 #include "components/feature_engagement_tracker/internal/in_memory_store.h"
 
+#include <vector>
+
+#include "base/bind.h"
 #include "base/feature_list.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/feature_engagement_tracker/internal/store.h"
 
 namespace feature_engagement_tracker {
 
-InMemoryStore::InMemoryStore() : Store(), ready_(false) {}
+InMemoryStore::InMemoryStore(std::unique_ptr<std::vector<Event>> events)
+    : Store(), events_(std::move(events)), ready_(false) {}
+
+InMemoryStore::InMemoryStore()
+    : InMemoryStore(base::MakeUnique<std::vector<Event>>()) {}
 
 InMemoryStore::~InMemoryStore() = default;
 
 void InMemoryStore::Load(const OnLoadedCallback& callback) {
-  // TODO(nyquist): Post result back to callback.
-  ready_ = true;
+  HandleLoadResult(callback, true);
 }
 
 bool InMemoryStore::IsReady() const {
   return ready_;
 }
 
+void InMemoryStore::WriteEvent(const Event& event) {
+  // Intentionally ignore all writes.
+}
+
+void InMemoryStore::HandleLoadResult(const OnLoadedCallback& callback,
+                                     bool success) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, success, base::Passed(&events_)));
+  ready_ = success;
+}
+
 }  // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/in_memory_store.h b/components/feature_engagement_tracker/internal/in_memory_store.h
index 536c353..939037c 100644
--- a/components/feature_engagement_tracker/internal/in_memory_store.h
+++ b/components/feature_engagement_tracker/internal/in_memory_store.h
@@ -5,22 +5,36 @@
 #ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
 #define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_IN_MEMORY_STORE_H_
 
+#include <vector>
+
 #include "base/macros.h"
 #include "components/feature_engagement_tracker/internal/store.h"
 
 namespace feature_engagement_tracker {
-
 // An InMemoryStore provides a DB layer that stores all data in-memory.
+// All data is made available to this class during construction, and can be
+// loaded once by a caller. All calls to WriteEvent(...) are ignored.
 class InMemoryStore : public Store {
  public:
+  explicit InMemoryStore(std::unique_ptr<std::vector<Event>> events);
   InMemoryStore();
   ~InMemoryStore() override;
 
   // Store implementation.
   void Load(const OnLoadedCallback& callback) override;
   bool IsReady() const override;
+  void WriteEvent(const Event& event) override;
+
+ protected:
+  // Posts the result of loading and sets up the ready state.
+  // Protected and virtual for testing.
+  virtual void HandleLoadResult(const OnLoadedCallback& callback, bool success);
 
  private:
+  // All events that this in-memory store was constructed with. This will be
+  // reset when Load(...) is called.
+  std::unique_ptr<std::vector<Event>> events_;
+
   // Whether the store is ready or not. It is true after Load(...) has been
   // invoked.
   bool ready_;
diff --git a/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc b/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc
index 0b1d880..be3f0ad 100644
--- a/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc
+++ b/components/feature_engagement_tracker/internal/in_memory_store_unittest.cc
@@ -4,22 +4,66 @@
 
 #include "components/feature_engagement_tracker/internal/in_memory_store.h"
 
+#include <memory>
+#include <vector>
+
 #include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace feature_engagement_tracker {
 
 namespace {
-void NoOpCallback(bool success) {}
 
-class InMemoryStoreTest : public ::testing::Test {};
+class InMemoryStoreTest : public ::testing::Test {
+ public:
+  InMemoryStoreTest()
+      : load_callback_has_been_invoked_(false), last_result_(false) {}
+
+  void LoadCallback(bool success, std::unique_ptr<std::vector<Event>> events) {
+    load_callback_has_been_invoked_ = true;
+    last_result_ = success;
+    loaded_events_.reset(events.release());
+  }
+
+ protected:
+  bool load_callback_has_been_invoked_;
+  bool last_result_;
+  std::unique_ptr<std::vector<Event>> loaded_events_;
+  base::MessageLoop message_loop_;
+};
 }  // namespace
 
-TEST_F(InMemoryStoreTest, LoadShouldMakeReady) {
-  InMemoryStore store;
+TEST_F(InMemoryStoreTest, LoadShouldProvideEventsAsCallback) {
+  std::unique_ptr<std::vector<Event>> events =
+      base::MakeUnique<std::vector<Event>>();
+  Event foo;
+  Event bar;
+  events->push_back(foo);
+  events->push_back(bar);
+
+  // Create a new store and verify it's not ready yet.
+  InMemoryStore store(std::move(events));
   EXPECT_FALSE(store.IsReady());
-  store.Load(base::Bind(&NoOpCallback));
+
+  // Load the data and ensure the callback is not immediately invoked, since the
+  // result should be posted.
+  store.Load(
+      base::Bind(&InMemoryStoreTest::LoadCallback, base::Unretained(this)));
+  EXPECT_FALSE(load_callback_has_been_invoked_);
+
+  // Run the message loop until it's idle to finish to ensure the result is
+  // available.
+  base::RunLoop().RunUntilIdle();
+
+  // The two events should have been loaded, and the store should be ready.
+  EXPECT_TRUE(load_callback_has_been_invoked_);
   EXPECT_TRUE(store.IsReady());
+  EXPECT_EQ(2u, loaded_events_->size());
+  EXPECT_TRUE(last_result_);
 }
 
 }  // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/model.h b/components/feature_engagement_tracker/internal/model.h
index 966fa2d..30110663 100644
--- a/components/feature_engagement_tracker/internal/model.h
+++ b/components/feature_engagement_tracker/internal/model.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_H_
 
 #include <map>
+#include <string>
 
 #include "base/callback.h"
 #include "base/macros.h"
@@ -16,6 +17,7 @@
 }  // namespace base
 
 namespace feature_engagement_tracker {
+class Event;
 
 // A Model provides all necessary runtime state.
 class Model {
@@ -44,6 +46,15 @@
   // Returns whether any in-product help is currently showing.
   virtual bool IsCurrentlyShowing() const = 0;
 
+  // Retrieves the Event object for the event with the given name. If the event
+  // is not found, an empty event will be returned. Calling this before the
+  // Model has finished initializing will result in undefined behavior.
+  virtual const Event& GetEvent(const std::string& event_name) = 0;
+
+  // Increments the counter for today for how many times the event has happened.
+  // If the event has never happened before, the Event object will be created.
+  virtual void IncrementEvent(const std::string& event_name) = 0;
+
  protected:
   Model() = default;
 
diff --git a/components/feature_engagement_tracker/internal/model_impl.cc b/components/feature_engagement_tracker/internal/model_impl.cc
index f0d4196e..26d6e21f 100644
--- a/components/feature_engagement_tracker/internal/model_impl.cc
+++ b/components/feature_engagement_tracker/internal/model_impl.cc
@@ -6,7 +6,14 @@
 
 #include <map>
 #include <memory>
+#include <string>
+#include <vector>
 
+#include "base/bind.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "components/feature_engagement_tracker/internal/configuration.h"
 #include "components/feature_engagement_tracker/internal/model.h"
 #include "components/feature_engagement_tracker/internal/store.h"
@@ -19,14 +26,14 @@
       store_(std::move(store)),
       configuration_(std::move(configuration)),
       ready_(false),
-      currently_showing_(false) {}
+      currently_showing_(false),
+      weak_factory_(this) {}
 
 ModelImpl::~ModelImpl() = default;
 
 void ModelImpl::Initialize(const OnModelInitializationFinished& callback) {
-  // TODO(nyquist): Initialize Store and post result back to callback.
-  // Only set ready when Store has fully loaded.
-  ready_ = true;
+  store_->Load(base::Bind(&ModelImpl::OnStoreLoaded, weak_factory_.GetWeakPtr(),
+                          callback));
 }
 
 bool ModelImpl::IsReady() const {
@@ -46,4 +53,68 @@
   return currently_showing_;
 }
 
+const Event& ModelImpl::GetEvent(const std::string& event_name) {
+  return GetNonConstEvent(event_name);
+}
+
+void ModelImpl::IncrementEvent(const std::string& event_name) {
+  // TODO(nyquist): Add support for pending events, and also add UMA.
+  DCHECK(ready_);
+
+  Event& event = GetNonConstEvent(event_name);
+  uint32_t current_day = GetCurrentDay();
+  for (int i = 0; i < event.events_size(); ++i) {
+    Event_Count* event_count = event.mutable_events(i);
+    DCHECK(event_count->has_day());
+    DCHECK(event_count->has_count());
+    if (event_count->day() == current_day) {
+      event_count->set_count(event_count->count() + 1);
+      store_->WriteEvent(event);
+      return;
+    }
+  }
+
+  // Day not found for event, adding new day with a count of 1.
+  Event_Count* event_count = event.add_events();
+  event_count->set_day(current_day);
+  event_count->set_count(1u);
+  store_->WriteEvent(event);
+}
+
+uint32_t ModelImpl::GetCurrentDay() {
+  // TODO(nyquist): Implement this according to specification.
+  return 1u;
+}
+
+void ModelImpl::OnStoreLoaded(const OnModelInitializationFinished& callback,
+                              bool success,
+                              std::unique_ptr<std::vector<Event>> events) {
+  if (!success) {
+    base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                  base::Bind(callback, false));
+    return;
+  }
+
+  for (auto& event : *events) {
+    DCHECK_NE("", event.name());
+    events_[event.name()] = event;
+  }
+
+  // TODO(nyquist): Clear expired data.
+
+  ready_ = true;
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                base::Bind(callback, true));
+}
+
+Event& ModelImpl::GetNonConstEvent(const std::string& event_name) {
+  if (events_.find(event_name) == events_.end()) {
+    // Event does not exist yet, so create it.
+    events_[event_name].set_name(event_name);
+    store_->WriteEvent(events_[event_name]);
+  }
+  return events_[event_name];
+}
+
 }  // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/model_impl.h b/components/feature_engagement_tracker/internal/model_impl.h
index dcbefa29..ff456e13 100644
--- a/components/feature_engagement_tracker/internal/model_impl.h
+++ b/components/feature_engagement_tracker/internal/model_impl.h
@@ -5,11 +5,16 @@
 #ifndef COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
 #define COMPONENTS_FEATURE_ENGAGEMENT_TRACKER_INTERNAL_MODEL_IMPL_H_
 
+#include <map>
 #include <memory>
+#include <string>
+#include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "components/feature_engagement_tracker/internal/configuration.h"
 #include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
 
 namespace base {
 struct Feature;
@@ -32,20 +37,41 @@
       const base::Feature& feature) const override;
   void SetIsCurrentlyShowing(bool is_showing) override;
   bool IsCurrentlyShowing() const override;
+  const Event& GetEvent(const std::string& event_name) override;
+  void IncrementEvent(const std::string& event_name) override;
+
+ protected:
+  // Returns the number of days since epoch (1970-01-01) in the local timezone.
+  // Protected and virtual for testing.
+  virtual uint32_t GetCurrentDay();
 
  private:
+  // Callback for loading the underlying store.
+  void OnStoreLoaded(const OnModelInitializationFinished& callback,
+                     bool success,
+                     std::unique_ptr<std::vector<Event>> events);
+
+  // Internal version for getting the non-const version of a stored Event.
+  // Creates the event if it is not already stored.
+  Event& GetNonConstEvent(const std::string& event_name);
+
   // The underlying store for all events.
   std::unique_ptr<Store> store_;
 
   // The current configuration for all features.
   std::unique_ptr<Configuration> configuration_;
 
+  // An in-memory representation of all events.
+  std::map<std::string, Event> events_;
+
   // Whether the model has been fully initialized.
   bool ready_;
 
   // Whether the model is currently showing an in-product help.
   bool currently_showing_;
 
+  base::WeakPtrFactory<ModelImpl> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(ModelImpl);
 };
 
diff --git a/components/feature_engagement_tracker/internal/model_impl_unittest.cc b/components/feature_engagement_tracker/internal/model_impl_unittest.cc
index 3651b58..ef57d2a 100644
--- a/components/feature_engagement_tracker/internal/model_impl_unittest.cc
+++ b/components/feature_engagement_tracker/internal/model_impl_unittest.cc
@@ -7,12 +7,16 @@
 #include <memory>
 
 #include "base/bind.h"
+#include "base/callback.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/feature_engagement_tracker/internal/editable_configuration.h"
 #include "components/feature_engagement_tracker/internal/in_memory_store.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace feature_engagement_tracker {
@@ -23,8 +27,6 @@
 const base::Feature kTestFeatureBar{"test_bar",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
-void NoOpCallback(bool success) {}
-
 void RegisterFeatureConfig(EditableConfiguration* configuration,
                            const base::Feature& feature,
                            bool valid) {
@@ -34,10 +36,113 @@
   configuration->SetConfiguration(&feature, config);
 }
 
+void SetEventCountForDay(Event* event, uint32_t day, uint32_t count) {
+  Event_Count* event_count = event->add_events();
+  event_count->set_day(day);
+  event_count->set_count(count);
+}
+
+// Verifies that the given |event| contains a |day| with the correct |count|,
+// and that the day only exists a single time.
+void VerifyEventCount(const Event& event, uint32_t day, uint32_t count) {
+  bool found_day = false;
+  for (int i = 0; i < event.events_size(); ++i) {
+    Event_Count event_count = event.events(i);
+    if (event_count.day() == day) {
+      EXPECT_FALSE(found_day);
+      found_day = true;
+      EXPECT_EQ(count, event_count.count());
+    }
+  }
+  EXPECT_TRUE(found_day);
+}
+
+// Verifies that the event |a| and |b| contain the exact same data.
+void VerifyEqual(const Event& a, const Event& b) {
+  EXPECT_EQ(a.name(), b.name());
+  EXPECT_EQ(a.events_size(), b.events_size());
+  for (int i = 0; i < a.events_size(); ++i) {
+    VerifyEventCount(b, a.events(i).day(), a.events(i).count());
+  }
+}
+
+// A test-only implementation of InMemoryStore that tracks calls to
+// WriteEvent(...).
+class TestInMemoryStore : public InMemoryStore {
+ public:
+  explicit TestInMemoryStore(std::unique_ptr<std::vector<Event>> events,
+                             bool load_should_succeed)
+      : InMemoryStore(std::move(events)),
+        load_should_succeed_(load_should_succeed) {}
+
+  void Load(const OnLoadedCallback& callback) override {
+    HandleLoadResult(callback, load_should_succeed_);
+  }
+
+  void WriteEvent(const Event& event) override { last_written_event_ = event; }
+
+  Event GetLastWrittenEvent() { return last_written_event_; }
+
+ private:
+  // Temporary store the last written event.
+  Event last_written_event_;
+
+  // Denotes whether the call to Load(...) should succeed or not. This impacts
+  // both the ready-state and the result for the OnLoadedCallback.
+  bool load_should_succeed_;
+};
+
+// Creates a TestInMemoryStore containing three hard coded events.
+std::unique_ptr<TestInMemoryStore> CreatePrefilledStore() {
+  std::unique_ptr<std::vector<Event>> events =
+      base::MakeUnique<std::vector<Event>>();
+
+  Event foo;
+  foo.set_name("foo");
+  SetEventCountForDay(&foo, 1, 1);
+  events->push_back(foo);
+
+  Event bar;
+  bar.set_name("bar");
+  SetEventCountForDay(&bar, 1, 3);
+  SetEventCountForDay(&bar, 2, 3);
+  SetEventCountForDay(&bar, 5, 5);
+  events->push_back(bar);
+
+  Event qux;
+  qux.set_name("qux");
+  SetEventCountForDay(&qux, 1, 5);
+  SetEventCountForDay(&qux, 2, 1);
+  SetEventCountForDay(&qux, 3, 2);
+  events->push_back(qux);
+
+  return base::MakeUnique<TestInMemoryStore>(std::move(events), true);
+}
+
+// A test-only implementation of ModelImpl to be able to change the current
+// day while a test is running.
+class TestModelImpl : public ModelImpl {
+ public:
+  TestModelImpl(std::unique_ptr<Store> store,
+                std::unique_ptr<Configuration> configuration)
+      : ModelImpl(std::move(store), std::move(configuration)),
+        current_day_(0) {}
+  ~TestModelImpl() override {}
+
+  uint32_t GetCurrentDay() override { return current_day_; }
+
+  void SetCurrentDay(uint32_t current_day) { current_day_ = current_day; }
+
+ private:
+  uint32_t current_day_;
+};
+
 class ModelImplTest : public ::testing::Test {
  public:
+  ModelImplTest()
+      : got_initialize_callback_(false), initialize_callback_result_(false) {}
+
   void SetUp() override {
-    std::unique_ptr<Store> store = base::MakeUnique<InMemoryStore>();
     std::unique_ptr<EditableConfiguration> configuration =
         base::MakeUnique<EditableConfiguration>();
 
@@ -47,23 +152,213 @@
     scoped_feature_list_.InitWithFeatures({kTestFeatureFoo, kTestFeatureBar},
                                           {});
 
-    model_.reset(new ModelImpl(std::move(store), std::move(configuration)));
+    std::unique_ptr<TestInMemoryStore> store = CreateStore();
+    store_ = store.get();
+
+    model_.reset(new TestModelImpl(std::move(store), std::move(configuration)));
+  }
+
+  virtual std::unique_ptr<TestInMemoryStore> CreateStore() {
+    return CreatePrefilledStore();
+  }
+
+  void OnModelInitializationFinished(bool success) {
+    got_initialize_callback_ = true;
+    initialize_callback_result_ = success;
   }
 
  protected:
-  std::unique_ptr<ModelImpl> model_;
+  std::unique_ptr<TestModelImpl> model_;
+  TestInMemoryStore* store_;
+  bool got_initialize_callback_;
+  bool initialize_callback_result_;
+
+ private:
+  base::MessageLoop message_loop_;
   base::test::ScopedFeatureList scoped_feature_list_;
 };
+
+class LoadFailingModelImplTest : public ModelImplTest {
+ public:
+  LoadFailingModelImplTest() : ModelImplTest() {}
+
+  std::unique_ptr<TestInMemoryStore> CreateStore() override {
+    return base::MakeUnique<TestInMemoryStore>(
+        base::MakeUnique<std::vector<Event>>(), false);
+  }
+};
+
 }  // namespace
 
-TEST_F(ModelImplTest, InitializationShouldMakeReady) {
-  EXPECT_FALSE(model_->IsReady());
-  model_->Initialize(base::Bind(&NoOpCallback));
+TEST_F(ModelImplTest, InitializeShouldLoadEntries) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(model_->IsReady());
+  EXPECT_TRUE(got_initialize_callback_);
+  EXPECT_TRUE(initialize_callback_result_);
+
+  // Verify that all the data matches what was put into the store in
+  // CreateStore().
+  Event foo_event = model_->GetEvent("foo");
+  EXPECT_EQ("foo", foo_event.name());
+  EXPECT_EQ(1, foo_event.events_size());
+  VerifyEventCount(foo_event, 1u, 1u);
+
+  Event bar_event = model_->GetEvent("bar");
+  EXPECT_EQ("bar", bar_event.name());
+  EXPECT_EQ(3, bar_event.events_size());
+  VerifyEventCount(bar_event, 1u, 3u);
+  VerifyEventCount(bar_event, 2u, 3u);
+  VerifyEventCount(bar_event, 5u, 5u);
+
+  Event qux_event = model_->GetEvent("qux");
+  EXPECT_EQ("qux", qux_event.name());
+  EXPECT_EQ(3, qux_event.events_size());
+  VerifyEventCount(qux_event, 1u, 5u);
+  VerifyEventCount(qux_event, 2u, 1u);
+  VerifyEventCount(qux_event, 3u, 2u);
 }
 
-TEST_F(ModelImplTest, ShowingState) {
-  model_->Initialize(base::Bind(&NoOpCallback));
+TEST_F(ModelImplTest, RetrievingNewEventsShouldYieldEmpty) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  Event no_event = model_->GetEvent("no");
+  EXPECT_EQ("no", no_event.name());
+  EXPECT_EQ(0, no_event.events_size());
+  VerifyEqual(no_event, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingNonExistingEvent) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  model_->SetCurrentDay(1u);
+
+  // Incrementing the event should work even if it does not exist.
+  model_->IncrementEvent("nonexisting");
+  Event event1 = model_->GetEvent("nonexisting");
+  EXPECT_EQ("nonexisting", event1.name());
+  EXPECT_EQ(1, event1.events_size());
+  VerifyEventCount(event1, 1u, 1u);
+  VerifyEqual(event1, store_->GetLastWrittenEvent());
+
+  // Incrementing the event after it has been initialized to 1, it should now
+  // have a count of 2 for the given day.
+  model_->IncrementEvent("nonexisting");
+  Event event2 = model_->GetEvent("nonexisting");
+  Event_Count event2_count = event2.events(0);
+  EXPECT_EQ(1, event2.events_size());
+  VerifyEventCount(event2, 1u, 2u);
+  VerifyEqual(event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingNonExistingEventMultipleDays) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  model_->SetCurrentDay(1u);
+  model_->IncrementEvent("nonexisting");
+  model_->SetCurrentDay(2u);
+  model_->IncrementEvent("nonexisting");
+  model_->IncrementEvent("nonexisting");
+  model_->SetCurrentDay(3u);
+  model_->IncrementEvent("nonexisting");
+  Event event = model_->GetEvent("nonexisting");
+  EXPECT_EQ(3, event.events_size());
+  VerifyEventCount(event, 1u, 1u);
+  VerifyEventCount(event, 2u, 2u);
+  VerifyEventCount(event, 3u, 1u);
+  VerifyEqual(event, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingSingleDayExistingEvent) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  model_->SetCurrentDay(1u);
+
+  // |foo| is inserted into the store with a count of 1 at day 1.
+  Event foo_event = model_->GetEvent("foo");
+  EXPECT_EQ("foo", foo_event.name());
+  EXPECT_EQ(1, foo_event.events_size());
+  VerifyEventCount(foo_event, 1u, 1u);
+
+  // Incrementing |foo| should change count to 2.
+  model_->IncrementEvent("foo");
+  Event foo_event2 = model_->GetEvent("foo");
+  EXPECT_EQ(1, foo_event2.events_size());
+  VerifyEventCount(foo_event2, 1u, 2u);
+  VerifyEqual(foo_event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingSingleDayExistingEventTwice) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  model_->SetCurrentDay(1u);
+
+  // |foo| is inserted into the store with a count of 1 at day 1, so
+  // incrementing twice should lead to 3.
+  model_->IncrementEvent("foo");
+  model_->IncrementEvent("foo");
+  Event foo_event = model_->GetEvent("foo");
+  EXPECT_EQ(1, foo_event.events_size());
+  VerifyEventCount(foo_event, 1u, 3u);
+  VerifyEqual(foo_event, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingExistingMultiDayEvent) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  // |bar| is inserted into the store with a count of 3 at day 2. Incrementing
+  // that day should lead to a count of 4.
+  model_->SetCurrentDay(2u);
+  Event bar_event = model_->GetEvent("bar");
+  VerifyEventCount(bar_event, 2u, 3u);
+  model_->IncrementEvent("bar");
+  Event bar_event2 = model_->GetEvent("bar");
+  VerifyEventCount(bar_event2, 2u, 4u);
+  VerifyEqual(bar_event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, IncrementingExistingMultiDayEventNewDay) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(model_->IsReady());
+
+  // |bar| does not contain entries for day 10, so incrementing should create
+  // the day.
+  model_->SetCurrentDay(10u);
+  model_->IncrementEvent("bar");
+  Event bar_event = model_->GetEvent("bar");
+  VerifyEventCount(bar_event, 10u, 1u);
+  VerifyEqual(bar_event, store_->GetLastWrittenEvent());
+  model_->IncrementEvent("bar");
+  Event bar_event2 = model_->GetEvent("bar");
+  VerifyEventCount(bar_event2, 10u, 2u);
+  VerifyEqual(bar_event2, store_->GetLastWrittenEvent());
+}
+
+TEST_F(ModelImplTest, ShowState) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(model_->IsReady());
 
   EXPECT_FALSE(model_->IsCurrentlyShowing());
@@ -78,4 +373,13 @@
   EXPECT_FALSE(model_->IsCurrentlyShowing());
 }
 
+TEST_F(LoadFailingModelImplTest, FailedInitializeInformsCaller) {
+  model_->Initialize(base::Bind(&ModelImplTest::OnModelInitializationFinished,
+                                base::Unretained(this)));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(model_->IsReady());
+  EXPECT_TRUE(got_initialize_callback_);
+  EXPECT_FALSE(initialize_callback_result_);
+}
+
 }  // namespace feature_engagement_tracker
diff --git a/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc b/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc
index 4bcd08e..d39f122 100644
--- a/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc
+++ b/components/feature_engagement_tracker/internal/never_condition_validator_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/metrics/field_trial.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace feature_engagement_tracker {
@@ -40,8 +41,15 @@
 
   bool IsCurrentlyShowing() const override { return false; }
 
+  const Event& GetEvent(const std::string& event_name) override {
+    return empty_event_;
+  }
+
+  void IncrementEvent(const std::string& event_name) override {}
+
  private:
   FeatureConfig feature_config_;
+  Event empty_event_;
 
   DISALLOW_COPY_AND_ASSIGN(TestModel);
 };
diff --git a/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc b/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc
index c7c7598..c8ee8c7 100644
--- a/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc
+++ b/components/feature_engagement_tracker/internal/once_condition_validator_unittest.cc
@@ -4,11 +4,14 @@
 
 #include "components/feature_engagement_tracker/internal/once_condition_validator.h"
 
+#include <string>
+
 #include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/feature_engagement_tracker/internal/editable_configuration.h"
 #include "components/feature_engagement_tracker/internal/model.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace feature_engagement_tracker {
@@ -44,17 +47,22 @@
 
   EditableConfiguration& GetConfiguration() { return configuration_; }
 
+  const Event& GetEvent(const std::string& event_name) override {
+    return empty_event_;
+  }
+
+  void IncrementEvent(const std::string& event_name) override {}
+
  private:
   EditableConfiguration configuration_;
+  Event empty_event_;
   bool ready_;
   bool is_showing_;
 };
 
 class OnceConditionValidatorTest : public ::testing::Test {
  public:
-  OnceConditionValidatorTest() = default;
-
-  void SetUp() override {
+  OnceConditionValidatorTest() {
     // By default, model should be ready.
     model_.SetIsReady(true);
   }
diff --git a/components/feature_engagement_tracker/internal/proto/BUILD.gn b/components/feature_engagement_tracker/internal/proto/BUILD.gn
new file mode 100644
index 0000000..686f184
--- /dev/null
+++ b/components/feature_engagement_tracker/internal/proto/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/protobuf/proto_library.gni")
+
+proto_library("proto") {
+  sources = [
+    "event.proto",
+  ]
+}
diff --git a/components/feature_engagement_tracker/internal/proto/event.proto b/components/feature_engagement_tracker/internal/proto/event.proto
new file mode 100644
index 0000000..9b619a2
--- /dev/null
+++ b/components/feature_engagement_tracker/internal/proto/event.proto
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// FeatureEngagementTracker content.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+
+package feature_engagement_tracker;
+
+// Event stores state for a specific event a count per day it has happened.
+message Event {
+  // Count stores a pair of a day and how many times something happened that
+  // day.
+  message Count {
+    optional uint32 day = 1;
+    optional uint32 count = 2;
+  }
+
+  // The descriptive name of the event.
+  optional string name = 1;
+
+  // The number of this event that happened per day.
+  repeated Count events = 2;
+}
diff --git a/components/feature_engagement_tracker/internal/store.h b/components/feature_engagement_tracker/internal/store.h
index 9a1e2c9..cef9b460 100644
--- a/components/feature_engagement_tracker/internal/store.h
+++ b/components/feature_engagement_tracker/internal/store.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "components/feature_engagement_tracker/internal/proto/event.pb.h"
 
 namespace feature_engagement_tracker {
 
@@ -14,17 +15,23 @@
 class Store {
  public:
   // TODO(nyquist): Add vector of all events to result callback.
-  using OnLoadedCallback = base::Callback<void(bool success)>;
+  using OnLoadedCallback =
+      base::Callback<void(bool success, std::unique_ptr<std::vector<Event>>)>;
 
   virtual ~Store() = default;
 
-  // Loads the database from storage and asynchronously posts the result back.
+  // Loads the database from storage and asynchronously posts the result back
+  // on the caller's thread.
+  // Ownership of the loaded data is given to the caller.
   virtual void Load(const OnLoadedCallback& callback) = 0;
 
   // Returns whether the database is ready, i.e. whether it has been fully
   // loaded.
   virtual bool IsReady() const = 0;
 
+  // Stores the given event to persistent storage.
+  virtual void WriteEvent(const Event& event) = 0;
+
  protected:
   Store() = default;
 
diff --git a/components/filesystem/file_system_app.cc b/components/filesystem/file_system_app.cc
index e12cba1..c54639c 100644
--- a/components/filesystem/file_system_app.cc
+++ b/components/filesystem/file_system_app.cc
@@ -11,7 +11,6 @@
 #include "base/files/file_util.h"
 #include "base/memory/ptr_util.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
diff --git a/components/font_service/font_service_app.cc b/components/font_service/font_service_app.cc
index 57700b2..5dfe5f9 100644
--- a/components/font_service/font_service_app.cc
+++ b/components/font_service/font_service_app.cc
@@ -9,7 +9,6 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "mojo/public/cpp/system/platform_handle.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 static_assert(
diff --git a/components/history/core/browser/thumbnail_database.cc b/components/history/core/browser/thumbnail_database.cc
index f476c6e..d9bc22de 100644
--- a/components/history/core/browser/thumbnail_database.cc
+++ b/components/history/core/browser/thumbnail_database.cc
@@ -82,9 +82,9 @@
 // fatal (in fact, very old data may be expired immediately at startup
 // anyhow).
 
-// Version 8: ???????? by rogerm@chromium.org on 2015-??-??
+// Version 8: 982ef2c1/r323176 by rogerm@chromium.org on 2015-03-31
 // Version 7: 911a634d/r209424 by qsr@chromium.org on 2013-07-01
-// Version 6: 610f923b/r152367 by pkotwicz@chromium.org on 2012-08-20
+// Version 6: 610f923b/r152367 by pkotwicz@chromium.org on 2012-08-20 (depr.)
 // Version 5: e2ee8ae9/r105004 by groby@chromium.org on 2011-10-12 (deprecated)
 // Version 4: 5f104d76/r77288 by sky@chromium.org on 2011-03-08 (deprecated)
 // Version 3: 09911bf3/r15 by initial.commit on 2008-07-26 (deprecated)
@@ -94,7 +94,7 @@
 // the new version and a test to verify that Init() works with it.
 const int kCurrentVersionNumber = 8;
 const int kCompatibleVersionNumber = 8;
-const int kDeprecatedVersionNumber = 5;  // and earlier.
+const int kDeprecatedVersionNumber = 6;  // and earlier.
 
 void FillIconMapping(const sql::Statement& statement,
                      const GURL& page_url,
@@ -146,8 +146,7 @@
 }
 
 // NOTE(shess): Schema modifications must consider initial creation in
-// |InitImpl()|, recovery in |RecoverDatabaseOrRaze()|, and history pruning in
-// |RetainDataForPageUrls()|.
+// |InitImpl()| and history pruning in |RetainDataForPageUrls()|.
 bool InitTables(sql::Connection* db) {
   const char kIconMappingSql[] =
       "CREATE TABLE IF NOT EXISTS icon_mapping"
@@ -190,8 +189,7 @@
 }
 
 // NOTE(shess): Schema modifications must consider initial creation in
-// |InitImpl()|, recovery in |RecoverDatabaseOrRaze()|, and history pruning in
-// |RetainDataForPageUrls()|.
+// |InitImpl()| and history pruning in |RetainDataForPageUrls()|.
 bool InitIndices(sql::Connection* db) {
   const char kIconMappingUrlIndexSql[] =
       "CREATE INDEX IF NOT EXISTS icon_mapping_page_url_idx"
@@ -218,199 +216,6 @@
   return true;
 }
 
-enum RecoveryEventType {
-  RECOVERY_EVENT_RECOVERED = 0,
-  RECOVERY_EVENT_FAILED_SCOPER,
-  RECOVERY_EVENT_FAILED_META_VERSION_ERROR,  // obsolete
-  RECOVERY_EVENT_FAILED_META_VERSION_NONE,  // obsolete
-  RECOVERY_EVENT_FAILED_META_WRONG_VERSION6,  // obsolete
-  RECOVERY_EVENT_FAILED_META_WRONG_VERSION5,  // obsolete
-  RECOVERY_EVENT_FAILED_META_WRONG_VERSION,
-  RECOVERY_EVENT_FAILED_RECOVER_META,  // obsolete
-  RECOVERY_EVENT_FAILED_META_INSERT,  // obsolete
-  RECOVERY_EVENT_FAILED_INIT,
-  RECOVERY_EVENT_FAILED_RECOVER_FAVICONS,  // obsolete
-  RECOVERY_EVENT_FAILED_FAVICONS_INSERT,  // obsolete
-  RECOVERY_EVENT_FAILED_RECOVER_FAVICON_BITMAPS,  // obsolete
-  RECOVERY_EVENT_FAILED_FAVICON_BITMAPS_INSERT,  // obsolete
-  RECOVERY_EVENT_FAILED_RECOVER_ICON_MAPPING,  // obsolete
-  RECOVERY_EVENT_FAILED_ICON_MAPPING_INSERT,  // obsolete
-  RECOVERY_EVENT_RECOVERED_VERSION6,  // obsolete
-  RECOVERY_EVENT_FAILED_META_INIT,
-  RECOVERY_EVENT_FAILED_META_VERSION,
-  RECOVERY_EVENT_DEPRECATED,
-  RECOVERY_EVENT_FAILED_V5_INITSCHEMA,  // obsolete
-  RECOVERY_EVENT_FAILED_V5_AUTORECOVER_FAVICONS,  // obsolete
-  RECOVERY_EVENT_FAILED_V5_AUTORECOVER_ICON_MAPPING,  // obsolete
-  RECOVERY_EVENT_RECOVERED_VERSION5,  // obsolete
-  RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS,
-  RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS,
-  RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING,
-  RECOVERY_EVENT_FAILED_COMMIT,
-
-  // Always keep this at the end.
-  RECOVERY_EVENT_MAX,
-};
-
-void RecordRecoveryEvent(RecoveryEventType recovery_event) {
-  UMA_HISTOGRAM_ENUMERATION("History.FaviconsRecovery",
-                            recovery_event, RECOVERY_EVENT_MAX);
-}
-
-// Recover the database to the extent possible, razing it if recovery
-// is not possible.
-// TODO(shess): This is mostly just a safe proof of concept.  In the
-// real world, this database is probably not worthwhile recovering, as
-// opposed to just razing it and starting over whenever corruption is
-// detected.  So this database is a good test subject.
-void RecoverDatabaseOrRaze(sql::Connection* db, const base::FilePath& db_path) {
-  // NOTE(shess): This code is currently specific to the version
-  // number.  I am working on simplifying things to loosen the
-  // dependency, meanwhile contact me if you need to bump the version.
-  DCHECK_EQ(8, kCurrentVersionNumber);
-
-  // TODO(shess): Reset back after?
-  db->reset_error_callback();
-
-  // For histogram purposes.
-  size_t favicons_rows_recovered = 0;
-  size_t favicon_bitmaps_rows_recovered = 0;
-  size_t icon_mapping_rows_recovered = 0;
-  int64_t original_size = 0;
-  base::GetFileSize(db_path, &original_size);
-
-  std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
-  if (!recovery) {
-    // TODO(shess): Unable to create recovery connection.  This
-    // implies something substantial is wrong.  At this point |db| has
-    // been poisoned so there is nothing really to do.
-    //
-    // Possible responses are unclear.  If the failure relates to a
-    // problem somehow specific to the temporary file used to back the
-    // database, then an in-memory database could possibly be used.
-    // This could potentially allow recovering the main database, and
-    // might be simple to implement w/in Begin().
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER);
-    return;
-  }
-
-  // Setup the meta recovery table and fetch the version number from
-  // the corrupt database.
-  int version = 0;
-  if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) {
-    // TODO(shess): Prior histograms indicate all failures are in
-    // creating the recover virtual table for corrupt.meta.  The table
-    // may not exist, or the database may be too far gone.  Either
-    // way, unclear how to resolve.
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION);
-    return;
-  }
-
-  // This code may be able to fetch version information that the regular
-  // deprecation path cannot.
-  // NOTE(shess,rogerm): v6 is not currently deprecated in the normal Init()
-  // path, but is deprecated in the recovery path in the interest of keeping
-  // the code simple.  http://crbug.com/327485 for numbers.
-  DCHECK_LE(kDeprecatedVersionNumber, 6);
-  if (version <= 6) {
-    sql::Recovery::Unrecoverable(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_DEPRECATED);
-    return;
-  }
-
-  // Earlier versions have been handled or deprecated.
-  if (version < 7) {
-    sql::Recovery::Unrecoverable(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION);
-    return;
-  }
-
-  // Recover to current schema version.
-  sql::MetaTable recover_meta_table;
-  if (!recover_meta_table.Init(recovery->db(), kCurrentVersionNumber,
-                               kCompatibleVersionNumber)) {
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT);
-    return;
-  }
-
-  // Create a fresh version of the database.  The recovery code uses
-  // conflict-resolution to handle duplicates, so the indices are
-  // necessary.
-  if (!InitTables(recovery->db()) || !InitIndices(recovery->db())) {
-    // TODO(shess): Unable to create the new schema in the new
-    // database.  The new database should be a temporary file, so
-    // being unable to work with it is pretty unclear.
-    //
-    // What are the potential responses, even?  The recovery database
-    // could be opened as in-memory.  If the temp database had a
-    // filesystem problem and the temp filesystem differs from the
-    // main database, then that could fix it.
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_INIT);
-    return;
-  }
-
-  if (!recovery->AutoRecoverTable("favicons", &favicons_rows_recovered)) {
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICONS);
-    return;
-  }
-  if (!recovery->AutoRecoverTable("favicon_bitmaps",
-                                  &favicon_bitmaps_rows_recovered)) {
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_FAVICON_BITMAPS);
-    return;
-  }
-  if (!recovery->AutoRecoverTable("icon_mapping",
-                                  &icon_mapping_rows_recovered)) {
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_ICON_MAPPING);
-    return;
-  }
-
-  // TODO(shess): Is it possible/likely to have broken foreign-key
-  // issues with the tables?
-  // - icon_mapping.icon_id maps to no favicons.id
-  // - favicon_bitmaps.icon_id maps to no favicons.id
-  // - favicons.id is referenced by no icon_mapping.icon_id
-  // - favicons.id is referenced by no favicon_bitmaps.icon_id
-  // This step is possibly not worth the effort necessary to develop
-  // and sequence the statements, as it is basically a form of garbage
-  // collection.
-
-  if (!sql::Recovery::Recovered(std::move(recovery))) {
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_COMMIT);
-    return;
-  }
-
-  // Track the size of the recovered database relative to the size of
-  // the input database.  The size should almost always be smaller,
-  // unless the input database was empty to start with.  If the
-  // percentage results are very low, something is awry.
-  int64_t final_size = 0;
-  if (original_size > 0 &&
-      base::GetFileSize(db_path, &final_size) &&
-      final_size > 0) {
-    int percentage = static_cast<int>(original_size * 100 / final_size);
-    UMA_HISTOGRAM_PERCENTAGE("History.FaviconsRecoveredPercentage",
-                             std::max(100, percentage));
-  }
-
-  // Using 10,000 because these cases mostly care about "none
-  // recovered" and "lots recovered".  More than 10,000 rows recovered
-  // probably means there's something wrong with the profile.
-  UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFavicons",
-                             static_cast<int>(favicons_rows_recovered));
-  UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsFaviconBitmaps",
-                             static_cast<int>(favicon_bitmaps_rows_recovered));
-  UMA_HISTOGRAM_COUNTS_10000("History.FaviconsRecoveredRowsIconMapping",
-                             static_cast<int>(icon_mapping_rows_recovered));
-
-  RecordRecoveryEvent(RECOVERY_EVENT_RECOVERED);
-}
-
 void DatabaseErrorCallback(sql::Connection* db,
                            const base::FilePath& db_path,
                            HistoryBackendClient* backend_client,
@@ -425,11 +230,36 @@
   }
 
   // Attempt to recover corrupt databases.
-  int error = (extended_error & 0xFF);
-  if (error == SQLITE_CORRUPT ||
-      error == SQLITE_CANTOPEN ||
-      error == SQLITE_NOTADB) {
-    RecoverDatabaseOrRaze(db, db_path);
+  if (sql::Recovery::ShouldRecover(extended_error)) {
+    // NOTE(shess): This approach is valid as of version 8.  When bumping the
+    // version, it will PROBABLY remain valid, but consider whether any schema
+    // changes might break automated recovery.
+    DCHECK_EQ(8, kCurrentVersionNumber);
+
+    // Prevent reentrant calls.
+    db->reset_error_callback();
+
+    // TODO(shess): Is it possible/likely to have broken foreign-key
+    // issues with the tables?
+    // - icon_mapping.icon_id maps to no favicons.id
+    // - favicon_bitmaps.icon_id maps to no favicons.id
+    // - favicons.id is referenced by no icon_mapping.icon_id
+    // - favicons.id is referenced by no favicon_bitmaps.icon_id
+    // This step is possibly not worth the effort necessary to develop
+    // and sequence the statements, as it is basically a form of garbage
+    // collection.
+
+    // After this call, the |db| handle is poisoned so that future calls will
+    // return errors until the handle is re-opened.
+    sql::Recovery::RecoverDatabaseWithMetaVersion(db, db_path);
+
+    // The DLOG(FATAL) below is intended to draw immediate attention to errors
+    // in newly-written code.  Database corruption is generally a result of OS
+    // or hardware issues, not coding errors at the client level, so displaying
+    // the error would probably lead to confusion.  The ignored call signals the
+    // test-expectation framework that the error was handled.
+    ignore_result(sql::Connection::IsExpectedSqliteError(extended_error));
+    return;
   }
 
   // The default handling is to assert on debug and to ignore on release.
diff --git a/components/history/core/browser/thumbnail_database_unittest.cc b/components/history/core/browser/thumbnail_database_unittest.cc
index 61873b3..b20bbaf 100644
--- a/components/history/core/browser/thumbnail_database_unittest.cc
+++ b/components/history/core/browser/thumbnail_database_unittest.cc
@@ -636,34 +636,8 @@
   ASSERT_TRUE(db.get() != NULL);
   VerifyTablesAndColumns(&db->db_);
 
-  EXPECT_TRUE(CheckPageHasIcon(db.get(),
-                               kPageUrl1,
-                               favicon_base::FAVICON,
-                               kIconUrl1,
-                               kLargeSize,
-                               sizeof(kBlob1),
-                               kBlob1));
-  EXPECT_TRUE(CheckPageHasIcon(db.get(),
-                               kPageUrl2,
-                               favicon_base::FAVICON,
-                               kIconUrl2,
-                               kLargeSize,
-                               sizeof(kBlob2),
-                               kBlob2));
-  EXPECT_TRUE(CheckPageHasIcon(db.get(),
-                               kPageUrl3,
-                               favicon_base::FAVICON,
-                               kIconUrl1,
-                               kLargeSize,
-                               sizeof(kBlob1),
-                               kBlob1));
-  EXPECT_TRUE(CheckPageHasIcon(db.get(),
-                               kPageUrl3,
-                               favicon_base::TOUCH_ICON,
-                               kIconUrl3,
-                               kLargeSize,
-                               sizeof(kBlob2),
-                               kBlob2));
+  // Version 6 is deprecated, the data should all be gone.
+  VerifyDatabaseEmpty(&db->db_);
 }
 
 // Test loading version 7 database.
diff --git a/components/history/core/browser/top_sites_database.cc b/components/history/core/browser/top_sites_database.cc
index 3ae0a108..4359300 100644
--- a/components/history/core/browser/top_sites_database.cc
+++ b/components/history/core/browser/top_sites_database.cc
@@ -58,16 +58,13 @@
 // anyhow).
 
 // Version 3: b6d6a783/r231648 by beaudoin@chromium.org on 2013-10-29
-// Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31
+// Version 2: eb0b24e6/r87284 by satorux@chromium.org on 2011-05-31 (deprecated)
 // Version 1: 809cc4d8/r64072 by sky@chromium.org on 2010-10-27 (deprecated)
 
 // NOTE(shess): When changing the version, add a new golden file for
 // the new version and a test to verify that Init() works with it.
-// NOTE(shess): RecoverDatabaseOrRaze() depends on the specific
-// version number.  The code is subtle and in development, contact me
-// if the necessary changes are not obvious.
 static const int kVersionNumber = 3;
-static const int kDeprecatedVersionNumber = 1;  // and earlier.
+static const int kDeprecatedVersionNumber = 2;  // and earlier.
 
 bool InitTables(sql::Connection* db) {
   const char kThumbnailsSql[] =
@@ -108,9 +105,8 @@
 // Track various failure (and success) cases in recovery code.
 //
 // TODO(shess): The recovery code is complete, but by nature runs in challenging
-// circumstances, so initially the default error response is to leave the
-// existing database in place.  This histogram is intended to expose the
-// failures seen in the fleet.  Frequent failure cases can be explored more
+// circumstances, so errors will happen.  This histogram is intended to expose
+// the failures seen in the fleet.  Frequent failure cases can be explored more
 // deeply to see if the complexity to fix them is warranted.  Infrequent failure
 // cases can be resolved by marking the database unrecoverable (which will
 // delete the data).
@@ -126,12 +122,12 @@
 
   // Sqlite.RecoveryEvent can usually be used to get more detail about the
   // specific failure (see sql/recovery.cc).
-  RECOVERY_EVENT_FAILED_SCOPER,
+  OBSOLETE_RECOVERY_EVENT_FAILED_SCOPER,
   RECOVERY_EVENT_FAILED_META_VERSION,
   RECOVERY_EVENT_FAILED_META_WRONG_VERSION,
-  RECOVERY_EVENT_FAILED_META_INIT,
-  RECOVERY_EVENT_FAILED_SCHEMA_INIT,
-  RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS,
+  OBSOLETE_RECOVERY_EVENT_FAILED_META_INIT,
+  OBSOLETE_RECOVERY_EVENT_FAILED_SCHEMA_INIT,
+  OBSOLETE_RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS,
   RECOVERY_EVENT_FAILED_COMMIT,
 
   // Track invariants resolved by FixThumbnailsTable().
@@ -139,6 +135,9 @@
   RECOVERY_EVENT_INVARIANT_REDIRECT,
   RECOVERY_EVENT_INVARIANT_CONTIGUOUS,
 
+  // Track automated full-database recovery.
+  RECOVERY_EVENT_FAILED_AUTORECOVER,
+
   // Always keep this at the end.
   RECOVERY_EVENT_MAX,
 };
@@ -203,89 +202,48 @@
     RecordRecoveryEvent(RECOVERY_EVENT_INVARIANT_CONTIGUOUS);
 }
 
-// Recover the database to the extent possible, razing it if recovery is not
-// possible.
-void RecoverDatabaseOrRaze(sql::Connection* db, const base::FilePath& db_path) {
+// Recover the database to the extent possible, then fixup any broken
+// constraints.
+void RecoverAndFixup(sql::Connection* db, const base::FilePath& db_path) {
   // NOTE(shess): If the version changes, review this code.
   DCHECK_EQ(3, kVersionNumber);
 
-  // It is almost certain that some operation against |db| will fail, prevent
-  // reentry.
-  db->reset_error_callback();
-
-  // For generating histogram stats.
-  size_t thumbnails_recovered = 0;
-  int64_t original_size = 0;
-  base::GetFileSize(db_path, &original_size);
-
-  std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
+  std::unique_ptr<sql::Recovery> recovery =
+      sql::Recovery::BeginRecoverDatabase(db, db_path);
   if (!recovery) {
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCOPER);
+    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER);
     return;
   }
 
-  // Setup the meta recovery table and fetch the version number from the corrupt
-  // database.
+  // If the [meta] table does not exist, or the [version] key cannot be found,
+  // then the schema is indeterminate.  The only plausible approach would be to
+  // validate that the schema contains all of the tables and indices and columns
+  // expected, but that complexity may not be warranted, this case has only been
+  // seen for a few thousand database files.
   int version = 0;
   if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) {
-    // TODO(shess): Prior histograms indicate all failures are in creating the
-    // recover virtual table for corrupt.meta.  The table may not exist, or the
-    // database may be too far gone.  Either way, unclear how to resolve.
-    sql::Recovery::Rollback(std::move(recovery));
+    sql::Recovery::Unrecoverable(std::move(recovery));
     RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_VERSION);
     return;
   }
 
-  // This code runs in a context which may be able to read version information
-  // that the regular deprecation path cannot.  The effect of this code will be
-  // to raze the database.
+  // In this case the next open will clear the database anyhow.
   if (version <= kDeprecatedVersionNumber) {
     sql::Recovery::Unrecoverable(std::move(recovery));
     RecordRecoveryEvent(RECOVERY_EVENT_DEPRECATED);
     return;
   }
 
-  // TODO(shess): Earlier versions have been deprecated, later versions should
-  // be impossible.  Unrecoverable() seems like a feasible response if this is
-  // infrequent enough.
-  if (version != 2 && version != 3) {
+  // TODO(shess): Consider marking corrupt databases from the future
+  // Unrecoverable(), since this histogram value has never been seen.  OTOH,
+  // this may be too risky, because if future code was correlated with
+  // corruption then rollback would be a sensible response.
+  if (version > kVersionNumber) {
     RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_WRONG_VERSION);
     sql::Recovery::Rollback(std::move(recovery));
     return;
   }
 
-  // Both v2 and v3 recover to current schema version.
-  sql::MetaTable recover_meta_table;
-  if (!recover_meta_table.Init(recovery->db(), kVersionNumber,
-                               kVersionNumber)) {
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_META_INIT);
-    return;
-  }
-
-  // Create a fresh version of the schema.  The recovery code uses
-  // conflict-resolution to handle duplicates, so any indices are necessary.
-  if (!InitTables(recovery->db())) {
-    // TODO(shess): Unable to create the new schema in the new database.  The
-    // new database should be a temporary file, so being unable to work with it
-    // is pretty unclear.
-    //
-    // What are the potential responses, even?  The recovery database could be
-    // opened as in-memory.  If the temp database had a filesystem problem and
-    // the temp filesystem differs from the main database, then that could fix
-    // it.
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_SCHEMA_INIT);
-    return;
-  }
-
-  // In the v2 case the missing column will get default values.
-  if (!recovery->AutoRecoverTable("thumbnails", &thumbnails_recovered)) {
-    sql::Recovery::Rollback(std::move(recovery));
-    RecordRecoveryEvent(RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS);
-    return;
-  }
-
   // TODO(shess): Inline this?
   FixThumbnailsTable(recovery->db());
 
@@ -297,23 +255,6 @@
     return;
   }
 
-  // Track the size of the recovered database relative to the size of the input
-  // database.  The size should almost always be smaller, unless the input
-  // database was empty to start with.  If the percentage results are very low,
-  // something is awry.
-  int64_t final_size = 0;
-  if (original_size > 0 && base::GetFileSize(db_path, &final_size) &&
-      final_size > 0) {
-    UMA_HISTOGRAM_PERCENTAGE("History.TopSitesRecoveredPercentage",
-                             final_size * 100 / original_size);
-  }
-
-  // Using 10,000 because these cases mostly care about "none recovered" and
-  // "lots recovered".  More than 10,000 rows recovered probably means there's
-  // something wrong with the profile.
-  UMA_HISTOGRAM_COUNTS_10000("History.TopSitesRecoveredRowsThumbnails",
-                             static_cast<int>(thumbnails_recovered));
-
   RecordRecoveryEvent(RECOVERY_EVENT_RECOVERED);
 }
 
@@ -325,11 +266,21 @@
   // be the history thread, but at this level I can't see how to reach that.
 
   // Attempt to recover corrupt databases.
-  int error = (extended_error & 0xFF);
-  if (error == SQLITE_CORRUPT ||
-      error == SQLITE_CANTOPEN ||
-      error == SQLITE_NOTADB) {
-    RecoverDatabaseOrRaze(db, db_path);
+  if (sql::Recovery::ShouldRecover(extended_error)) {
+    // Prevent reentrant calls.
+    db->reset_error_callback();
+
+    // After this call, the |db| handle is poisoned so that future calls will
+    // return errors until the handle is re-opened.
+    RecoverAndFixup(db, db_path);
+
+    // The DLOG(FATAL) below is intended to draw immediate attention to errors
+    // in newly-written code.  Database corruption is generally a result of OS
+    // or hardware issues, not coding errors at the client level, so displaying
+    // the error would probably lead to confusion.  The ignored call signals the
+    // test-expectation framework that the error was handled.
+    ignore_result(sql::Connection::IsExpectedSqliteError(extended_error));
+    return;
   }
 
   // TODO(shess): This database's error histograms look like:
diff --git a/components/history/core/browser/top_sites_database_unittest.cc b/components/history/core/browser/top_sites_database_unittest.cc
index 289b983..2968355 100644
--- a/components/history/core/browser/top_sites_database_unittest.cc
+++ b/components/history/core/browser/top_sites_database_unittest.cc
@@ -86,31 +86,15 @@
   VerifyDatabaseEmpty(db.db_.get());
 }
 
+// Version 2 is deprecated, the resulting schema should be current,
+// with no data.
 TEST_F(TopSitesDatabaseTest, Version2) {
   ASSERT_TRUE(CreateDatabaseFromSQL(file_name_, "TopSites.v2.sql"));
 
   TopSitesDatabase db;
   ASSERT_TRUE(db.Init(file_name_));
-
   VerifyTablesAndColumns(db.db_.get());
-
-  // Basic operational check.
-  MostVisitedURLList urls;
-  std::map<GURL, Images> thumbnails;
-  db.GetPageThumbnails(&urls, &thumbnails);
-  ASSERT_EQ(3u, urls.size());
-  ASSERT_EQ(3u, thumbnails.size());
-  EXPECT_EQ(kUrl0, urls[0].url);  // [0] because of url_rank.
-  // kGoogleThumbnail includes nul terminator.
-  ASSERT_EQ(sizeof(kGoogleThumbnail) - 1,
-            thumbnails[urls[0].url].thumbnail->size());
-  EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(),
-                      kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1));
-
-  ASSERT_TRUE(db.RemoveURL(urls[1]));
-  db.GetPageThumbnails(&urls, &thumbnails);
-  ASSERT_EQ(2u, urls.size());
-  ASSERT_EQ(2u, thumbnails.size());
+  VerifyDatabaseEmpty(db.db_.get());
 }
 
 TEST_F(TopSitesDatabaseTest, Version3) {
@@ -198,29 +182,15 @@
     ASSERT_TRUE(expecter.SawExpectedErrors());
   }
 
-  // Corruption should be detected and recovered during Init().  After recovery,
-  // the Version2 checks should work.
+  // Corruption should be detected and recovered during Init().
   {
     sql::test::ScopedErrorExpecter expecter;
     expecter.ExpectError(SQLITE_CORRUPT);
 
     TopSitesDatabase db;
     ASSERT_TRUE(db.Init(file_name_));
-
     VerifyTablesAndColumns(db.db_.get());
-
-    // Basic operational check.
-    MostVisitedURLList urls;
-    std::map<GURL, Images> thumbnails;
-    db.GetPageThumbnails(&urls, &thumbnails);
-    ASSERT_EQ(3u, urls.size());
-    ASSERT_EQ(3u, thumbnails.size());
-    EXPECT_EQ(kUrl0, urls[0].url);  // [0] because of url_rank.
-    // kGoogleThumbnail includes nul terminator.
-    ASSERT_EQ(sizeof(kGoogleThumbnail) - 1,
-              thumbnails[urls[0].url].thumbnail->size());
-    EXPECT_TRUE(!memcmp(thumbnails[urls[0].url].thumbnail->front(),
-                        kGoogleThumbnail, sizeof(kGoogleThumbnail) - 1));
+    VerifyDatabaseEmpty(db.db_.get());
 
     ASSERT_TRUE(expecter.SawExpectedErrors());
   }
diff --git a/components/infobars/core/infobar_delegate.cc b/components/infobars/core/infobar_delegate.cc
index 9f597fa..c3c0c97 100644
--- a/components/infobars/core/infobar_delegate.cc
+++ b/components/infobars/core/infobar_delegate.cc
@@ -131,11 +131,6 @@
   return nullptr;
 }
 
-MediaThrottleInfoBarDelegate*
-    InfoBarDelegate::AsMediaThrottleInfoBarDelegate() {
-  return nullptr;
-}
-
 offline_pages::OfflinePageInfoBarDelegate*
 InfoBarDelegate::AsOfflinePageInfoBarDelegate() {
   return nullptr;
diff --git a/components/infobars/core/infobar_delegate.h b/components/infobars/core/infobar_delegate.h
index d7297aa..c041844 100644
--- a/components/infobars/core/infobar_delegate.h
+++ b/components/infobars/core/infobar_delegate.h
@@ -23,7 +23,6 @@
 
 #if defined(OS_ANDROID)
 class MediaStreamInfoBarDelegateAndroid;
-class MediaThrottleInfoBarDelegate;
 
 namespace offline_pages {
 class OfflinePageInfoBarDelegate;
@@ -229,7 +228,6 @@
 #if defined(OS_ANDROID)
   virtual MediaStreamInfoBarDelegateAndroid*
   AsMediaStreamInfoBarDelegateAndroid();
-  virtual MediaThrottleInfoBarDelegate* AsMediaThrottleInfoBarDelegate();
   virtual offline_pages::OfflinePageInfoBarDelegate*
   AsOfflinePageInfoBarDelegate();
 #endif
diff --git a/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
index 4032c52..9563fc2 100644
--- a/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -1468,6 +1468,14 @@
                                CredentialType::CREDENTIAL_TYPE_PASSWORD);
 }
 
+TEST_F(CredentialManagerImplTest, MigrateWithEmptyStore) {
+  // HTTP scheme is valid for localhost. Nothing should crash.
+  NavigateAndCommit(GURL("http://127.0.0.1:8000/"));
+
+  std::vector<GURL> federations;
+  ExpectZeroClickSignInFailure(false, true, federations);
+}
+
 TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
   PasswordStore::FormDigest synthesized =
       cm_service_impl_->GetSynthesizedFormForOrigin();
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index ae1279a..cd89fb0 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -131,7 +131,8 @@
 
 void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
     std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
-  if (results.empty()) {
+  // localhost is a secure origin but not https.
+  if (results.empty() && origin_.SchemeIs(url::kHttpsScheme)) {
     // Try to migrate the HTTP passwords and process them later.
     http_migrator_ = base::MakeUnique<HttpPasswordStoreMigrator>(
         origin_, delegate_->client(), this);
diff --git a/components/payments/content/BUILD.gn b/components/payments/content/BUILD.gn
index c586afe..a200799 100644
--- a/components/payments/content/BUILD.gn
+++ b/components/payments/content/BUILD.gn
@@ -26,6 +26,7 @@
     "//components/payments/core",
     "//content/public/browser",
     "//mojo/public/cpp/bindings",
+    "//third_party/libphonenumber",
   ]
 }
 
diff --git a/components/payments/content/DEPS b/components/payments/content/DEPS
index c72416a..548a164 100644
--- a/components/payments/content/DEPS
+++ b/components/payments/content/DEPS
@@ -8,6 +8,7 @@
   "+content/public",
   "+mojo/public/cpp",
   "+net",
+  "+third_party/libphonenumber",
   "+third_party/re2",
   "+ui/base",
 ]
diff --git a/components/payments/content/payment_response_helper.cc b/components/payments/content/payment_response_helper.cc
index 997731f6..0d1177a 100644
--- a/components/payments/content/payment_response_helper.cc
+++ b/components/payments/content/payment_response_helper.cc
@@ -9,9 +9,16 @@
 #include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/payments/content/payment_request_spec.h"
+#include "third_party/libphonenumber/phonenumber_api.h"
 
 namespace payments {
 
+namespace {
+
+using ::i18n::phonenumbers::PhoneNumberUtil;
+
+}  // namespace
+
 PaymentResponseHelper::PaymentResponseHelper(
     const std::string& app_locale,
     PaymentRequestSpec* spec,
@@ -112,10 +119,28 @@
   }
   if (spec_->request_payer_phone()) {
     DCHECK(selected_contact_profile_);
-    // TODO(crbug.com/705945): Format phone number according to spec.
-    payment_response->payer_phone =
-        base::UTF16ToUTF8(selected_contact_profile_->GetRawInfo(
-            autofill::PHONE_HOME_WHOLE_NUMBER));
+
+    // Try to format the phone number to the E.164 format to send in the Payment
+    // Response, as defined in the Payment Request spec. If it's not possible,
+    // send the original. More info at:
+    // https://w3c.github.io/browser-payment-api/#paymentrequest-updated-algorithm
+    // TODO(sebsg): Move this code to a reusable location.
+    const std::string original_number =
+        base::UTF16ToUTF8(selected_contact_profile_->GetInfo(
+            autofill::AutofillType(autofill::PHONE_HOME_WHOLE_NUMBER),
+            app_locale_));
+    i18n::phonenumbers::PhoneNumber parsed_number;
+    PhoneNumberUtil* phone_number_util = PhoneNumberUtil::GetInstance();
+    if (phone_number_util->Parse(original_number, "US", &parsed_number) ==
+        ::i18n::phonenumbers::PhoneNumberUtil::NO_PARSING_ERROR) {
+      std::string formatted_number;
+      phone_number_util->Format(parsed_number,
+                                PhoneNumberUtil::PhoneNumberFormat::E164,
+                                &formatted_number);
+      payment_response->payer_phone = formatted_number;
+    } else {
+      payment_response->payer_phone = original_number;
+    }
   }
 
   delegate_->OnPaymentResponseReady(std::move(payment_response));
diff --git a/components/payments/content/payment_response_helper_unittest.cc b/components/payments/content/payment_response_helper_unittest.cc
index d072121..3b56de99 100644
--- a/components/payments/content/payment_response_helper_unittest.cc
+++ b/components/payments/content/payment_response_helper_unittest.cc
@@ -245,7 +245,7 @@
 
   // Check that all the expected values were set.
   EXPECT_EQ("John H. Doe", response()->payer_name.value());
-  EXPECT_EQ("16502111111", response()->payer_phone.value());
+  EXPECT_EQ("+16502111111", response()->payer_phone.value());
   EXPECT_EQ("johndoe@hades.com", response()->payer_email.value());
 }
 
@@ -266,4 +266,22 @@
   EXPECT_FALSE(response()->payer_email.has_value());
 }
 
+// Tests the the generated PaymentResponse has the correct values for the
+// contact details when all values are requested.
+TEST_F(PaymentResponseHelperTest,
+       GeneratePaymentResponse_ContactPhoneIsFormatted) {
+  // Request one contact detail value.
+  mojom::PaymentOptionsPtr options = mojom::PaymentOptions::New();
+  options->request_payer_phone = true;
+  test_address()->SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+                             base::UTF8ToUTF16("(515) 123-1234"));
+  RecreateSpecWithOptions(std::move(options));
+
+  PaymentResponseHelper helper("en-US", spec(), test_instrument(),
+                               test_address(), test_address(), this);
+
+  // Check that the phone was formatted.
+  EXPECT_EQ("+15151231234", response()->payer_phone.value());
+}
+
 }  // namespace payments
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index 36ca4ab..4f0877a9 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -49,6 +49,7 @@
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/content_descriptor_keys.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/main_function_params.h"
@@ -707,6 +708,16 @@
     std::string process_type =
         command_line.GetSwitchValueASCII(switches::kProcessType);
 
+    // --enable-network-service requires both --enable-browser-side-navigation
+    // (PlzNavigate) and the LoadingWithMojo feature.
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableNetworkService)) {
+      base::CommandLine::ForCurrentProcess()->AppendSwitch(
+          switches::kEnableBrowserSideNavigation);
+      base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+          switches::kEnableFeatures, features::kLoadingWithMojo.name);
+    }
+
     // Run this logic on all child processes. Zygotes will run this at a later
     // point in time when the command line has been updated.
     std::unique_ptr<base::FieldTrialList> field_trial_list;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index ef9f563..731f573 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -910,8 +910,6 @@
     "media/android/media_player_renderer.h",
     "media/android/media_resource_getter_impl.cc",
     "media/android/media_resource_getter_impl.h",
-    "media/android/media_throttler.cc",
-    "media/android/media_throttler.h",
     "media/android/media_web_contents_observer_android.cc",
     "media/android/media_web_contents_observer_android.h",
     "media/audible_metrics.cc",
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index 638e0ecc2..b7a99d5 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -42,7 +42,6 @@
 #include "services/file/file_service.h"
 #include "services/file/public/interfaces/constants.mojom.h"
 #include "services/file/user_id_map.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/interfaces/service.mojom.h"
 #include "storage/browser/database/database_tracker.h"
@@ -150,11 +149,9 @@
 class BrowserContextServiceManagerConnectionHolder
     : public base::SupportsUserData::Data {
  public:
-  BrowserContextServiceManagerConnectionHolder(
-      std::unique_ptr<service_manager::Connection> connection,
+  explicit BrowserContextServiceManagerConnectionHolder(
       service_manager::mojom::ServiceRequest request)
-      : root_connection_(std::move(connection)),
-        service_manager_connection_(ServiceManagerConnection::Create(
+      : service_manager_connection_(ServiceManagerConnection::Create(
             std::move(request),
             BrowserThread::GetTaskRunnerForThread(BrowserThread::IO))) {}
   ~BrowserContextServiceManagerConnectionHolder() override {}
@@ -164,7 +161,6 @@
   }
 
  private:
-  std::unique_ptr<service_manager::Connection> root_connection_;
   std::unique_ptr<ServiceManagerConnection> service_manager_connection_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserContextServiceManagerConnectionHolder);
@@ -442,9 +438,9 @@
         identity, std::move(service), mojo::MakeRequest(&pid_receiver));
     pid_receiver->SetPID(base::GetCurrentProcId());
 
+    service_manager_connection->GetConnector()->StartService(identity);
     BrowserContextServiceManagerConnectionHolder* connection_holder =
         new BrowserContextServiceManagerConnectionHolder(
-            service_manager_connection->GetConnector()->Connect(identity),
             std::move(service_request));
     browser_context->SetUserData(kServiceManagerConnection, connection_holder);
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index ab3135b..4036937d 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -508,6 +508,7 @@
 void NavigationRequest::OnResponseStarted(
     const scoped_refptr<ResourceResponse>& response,
     std::unique_ptr<StreamHandle> body,
+    mojo::ScopedDataPipeConsumerHandle consumer_handle,
     const SSLStatus& ssl_status,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& request_id,
@@ -580,6 +581,7 @@
   // Store the response and the StreamHandle until checks have been processed.
   response_ = response;
   body_ = std::move(body);
+  handle_ = std::move(consumer_handle);
 
   // Check if the navigation should be allowed to proceed.
   navigation_handle_->WillProcessResponse(
@@ -840,8 +842,8 @@
   DCHECK_EQ(request_params_.has_user_gesture, begin_params_.has_user_gesture);
 
   render_frame_host->CommitNavigation(response_.get(), std::move(body_),
-                                      common_params_, request_params_,
-                                      is_view_source_);
+                                      std::move(handle_), common_params_,
+                                      request_params_, is_view_source_);
 
   frame_tree_node_->ResetNavigationRequest(true, true);
 }
diff --git a/content/browser/frame_host/navigation_request.h b/content/browser/frame_host/navigation_request.h
index 24980b9..095b77f5 100644
--- a/content/browser/frame_host/navigation_request.h
+++ b/content/browser/frame_host/navigation_request.h
@@ -17,6 +17,7 @@
 #include "content/common/navigation_params.h"
 #include "content/public/browser/navigation_throttle.h"
 #include "content/public/common/previews_state.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 
 namespace content {
 
@@ -182,6 +183,7 @@
       const scoped_refptr<ResourceResponse>& response) override;
   void OnResponseStarted(const scoped_refptr<ResourceResponse>& response,
                          std::unique_ptr<StreamHandle> body,
+                         mojo::ScopedDataPipeConsumerHandle consumer_handle,
                          const SSLStatus& ssl_status,
                          std::unique_ptr<NavigationData> navigation_data,
                          const GlobalRequestID& request_id,
@@ -248,10 +250,12 @@
 
   std::unique_ptr<NavigationHandleImpl> navigation_handle_;
 
-  // Holds the ResourceResponse and the StreamHandle for the navigation while
-  // the WillProcessResponse checks are performed by the NavigationHandle.
+  // Holds the ResourceResponse and the StreamHandle (or
+  // DataPipeConsumerHandle) for the navigation while the WillProcessResponse
+  // checks are performed by the NavigationHandle.
   scoped_refptr<ResourceResponse> response_;
   std::unique_ptr<StreamHandle> body_;
+  mojo::ScopedDataPipeConsumerHandle handle_;
 
   base::Closure on_start_checks_complete_closure_;
 
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index d84e291..6dd1df2 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -1160,11 +1160,11 @@
     RenderFrameHostImpl* render_frame_host =
         frame_tree_node->render_manager()->GetFrameHostForNavigation(
             *scoped_request.get());
-    render_frame_host->CommitNavigation(nullptr,  // response
-                                        nullptr,  // body
-                                        scoped_request->common_params(),
-                                        scoped_request->request_params(),
-                                        scoped_request->is_view_source());
+    render_frame_host->CommitNavigation(
+        nullptr,  // response
+        nullptr,  // body
+        mojo::ScopedDataPipeConsumerHandle(), scoped_request->common_params(),
+        scoped_request->request_params(), scoped_request->is_view_source());
     return;
   }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 55d6a08e..22394e1 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -105,6 +105,7 @@
 #include "media/mojo/interfaces/remoting.mojom.h"
 #include "mojo/public/cpp/bindings/associated_interface_ptr.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/accessibility/ax_tree.h"
@@ -2642,8 +2643,8 @@
       base::Optional<SourceLocation>(),
       CSPDisposition::CHECK /* should_check_main_world_csp */);
   if (IsBrowserSideNavigationEnabled()) {
-    CommitNavigation(nullptr, nullptr, common_params, RequestNavigationParams(),
-                     false);
+    CommitNavigation(nullptr, nullptr, mojo::ScopedDataPipeConsumerHandle(),
+                     common_params, RequestNavigationParams(), false);
   } else {
     Navigate(common_params, StartNavigationParams(), RequestNavigationParams());
   }
@@ -2802,11 +2803,12 @@
 void RenderFrameHostImpl::CommitNavigation(
     ResourceResponse* response,
     std::unique_ptr<StreamHandle> body,
+    mojo::ScopedDataPipeConsumerHandle handle,
     const CommonNavigationParams& common_params,
     const RequestNavigationParams& request_params,
     bool is_view_source) {
   DCHECK(
-      (response && body.get()) ||
+      (response && (body.get() || handle.is_valid())) ||
       common_params.url.SchemeIs(url::kDataScheme) ||
       !ShouldMakeNetworkRequestForURL(common_params.url) ||
       FrameMsg_Navigate_Type::IsSameDocument(common_params.navigation_type) ||
@@ -2828,7 +2830,8 @@
   const GURL body_url = body.get() ? body->GetURL() : GURL();
   const ResourceResponseHead head = response ?
       response->head : ResourceResponseHead();
-  Send(new FrameMsg_CommitNavigation(routing_id_, head, body_url, common_params,
+  Send(new FrameMsg_CommitNavigation(routing_id_, head, body_url,
+                                     handle.release(), common_params,
                                      request_params));
 
   // If a network request was made, update the Previews state.
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 6f30641bb..10c52a3 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -43,6 +43,7 @@
 #include "content/public/common/javascript_dialog_type.h"
 #include "content/public/common/previews_state.h"
 #include "media/mojo/interfaces/interface_factory.mojom.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/http/http_response_headers.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
@@ -539,6 +540,7 @@
   // handled by this RenderFrame.
   void CommitNavigation(ResourceResponse* response,
                         std::unique_ptr<StreamHandle> body,
+                        mojo::ScopedDataPipeConsumerHandle handle,
                         const CommonNavigationParams& common_params,
                         const RequestNavigationParams& request_params,
                         bool is_view_source);
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 39d00af7..2eade52 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -62,7 +62,6 @@
 #include "media/media_features.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/runner/common/client_util.h"
 #include "ui/display/display_switches.h"
diff --git a/content/browser/loader/navigation_url_loader_delegate.h b/content/browser/loader/navigation_url_loader_delegate.h
index c67854a..8a71b22 100644
--- a/content/browser/loader/navigation_url_loader_delegate.h
+++ b/content/browser/loader/navigation_url_loader_delegate.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "content/common/content_export.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 
 namespace net {
 struct RedirectInfo;
@@ -35,9 +36,12 @@
   // Called when the request receives its response. No further calls will be
   // made to the delegate. The response body is returned as a stream in
   // |body_stream|. |navigation_data| is passed to the NavigationHandle.
+  // If --enable-network-service, then |consumer_handle| will be used,
+  // otherwise |body_stream|. Only one of these will ever be non-null.
   virtual void OnResponseStarted(
       const scoped_refptr<ResourceResponse>& response,
       std::unique_ptr<StreamHandle> body_stream,
+      mojo::ScopedDataPipeConsumerHandle consumer_handle,
       const SSLStatus& ssl_status,
       std::unique_ptr<NavigationData> navigation_data,
       const GlobalRequestID& request_id,
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index b1053623..4617b46 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -100,7 +100,8 @@
     bool is_stream) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  delegate_->OnResponseStarted(response, std::move(body), ssl_status,
+  delegate_->OnResponseStarted(response, std::move(body),
+                               mojo::ScopedDataPipeConsumerHandle(), ssl_status,
                                std::move(navigation_data), request_id,
                                is_download, is_stream);
 }
diff --git a/content/browser/loader/navigation_url_loader_network_service.cc b/content/browser/loader/navigation_url_loader_network_service.cc
index b29827b..c503716 100644
--- a/content/browser/loader/navigation_url_loader_network_service.cc
+++ b/content/browser/loader/navigation_url_loader_network_service.cc
@@ -8,7 +8,11 @@
 #include "content/browser/frame_host/navigation_request_info.h"
 #include "content/browser/loader/navigation_url_loader_delegate.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/navigation_data.h"
 #include "content/public/browser/navigation_ui_data.h"
+#include "content/public/browser/ssl_status.h"
+#include "content/public/browser/stream_handle.h"
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "net/url_request/url_request_context.h"
@@ -62,8 +66,11 @@
 void NavigationURLLoaderNetworkService::OnReceiveResponse(
     const ResourceResponseHead& head,
     mojom::DownloadedTempFilePtr downloaded_file) {
-  // TODO(scottmg): This should mirror code in
-  // NavigationResourceHandler::OnReponseStarted().
+  // TODO(scottmg): This needs to do more of what
+  // NavigationResourceHandler::OnReponseStarted() does. Or maybe in
+  // OnStartLoadingResponseBody().
+  response_ = base::MakeShared<ResourceResponse>();
+  response_->head = head;
 }
 
 void NavigationURLLoaderNetworkService::OnReceiveRedirect(
@@ -91,7 +98,16 @@
     int32_t transfer_size_diff) {}
 
 void NavigationURLLoaderNetworkService::OnStartLoadingResponseBody(
-    mojo::ScopedDataPipeConsumerHandle body) {}
+    mojo::ScopedDataPipeConsumerHandle body) {
+  DCHECK(response_);
+  // Temporarily, we pass both a stream (null) and the data pipe to the
+  // delegate until PlzNavigate has shipped and we can be comfortable fully
+  // switching to the data pipe.
+  delegate_->OnResponseStarted(response_, nullptr, std::move(body), SSLStatus(),
+                               std::unique_ptr<NavigationData>(),
+                               GlobalRequestID() /* request_id? */,
+                               false /* is_download? */, false /* is_stream */);
+}
 
 void NavigationURLLoaderNetworkService::OnComplete(
     const ResourceRequestCompletionStatus& completion_status) {}
diff --git a/content/browser/loader/navigation_url_loader_network_service.h b/content/browser/loader/navigation_url_loader_network_service.h
index b301769..25c46e7 100644
--- a/content/browser/loader/navigation_url_loader_network_service.h
+++ b/content/browser/loader/navigation_url_loader_network_service.h
@@ -66,6 +66,7 @@
   mojom::URLLoaderFactoryPtr url_loader_factory_;
   mojo::Binding<mojom::URLLoaderClient> binding_;
   mojom::URLLoaderAssociatedPtr url_loader_associated_ptr_;
+  scoped_refptr<ResourceResponse> response_;
 
   DISALLOW_COPY_AND_ASSIGN(NavigationURLLoaderNetworkService);
 };
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc
index 36ae2e5..d5128ec 100644
--- a/content/browser/media/android/browser_media_player_manager.cc
+++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -11,7 +11,6 @@
 #include "base/memory/singleton.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/media/android/media_resource_getter_impl.h"
-#include "content/browser/media/android/media_throttler.h"
 #include "content/browser/media/android/media_web_contents_observer_android.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -69,9 +68,13 @@
 // static
 BrowserMediaPlayerManager* BrowserMediaPlayerManager::Create(
     RenderFrameHost* rfh) {
-  if (g_factory)
-    return g_factory(rfh);
-  return new BrowserMediaPlayerManager(rfh);
+  // In chrome, |g_factory| should be set to create a RemoteMediaPlayerManager,
+  // since RegisterFactory() should be called from
+  // ChromeMainDelegateAndroid::BasicStartupComplete.
+  //
+  // In webview, no factory should be set, and returning a nullptr should be
+  // handled by the caller.
+  return g_factory != nullptr ? g_factory(rfh) : nullptr;
 }
 
 #if !defined(USE_AURA)
@@ -372,13 +375,12 @@
   if (!player)
     return;
 
-  if (RequestDecoderResources(player_id, false)) {
-    StartInternal(player_id);
-  } else if (WebContentsDelegate* delegate = web_contents_->GetDelegate()){
-    delegate->RequestMediaDecodePermission(
-        web_contents_,
-        base::Bind(&BrowserMediaPlayerManager::OnPlaybackPermissionGranted,
-                   weak_ptr_factory_.GetWeakPtr(), player_id));
+  RequestDecoderResources(player_id, false);
+
+  player->Start();
+  if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
+    video_view_->OpenVideo();
+    fullscreen_player_is_released_ = false;
   }
 }
 
@@ -484,9 +486,6 @@
 
 bool BrowserMediaPlayerManager::RequestDecoderResources(
     int player_id, bool temporary) {
-  if (!MediaThrottler::GetInstance()->RequestDecoderResources())
-    return false;
-
   ActivePlayerMap::iterator it;
   // The player is already active, ignore it. A long running player should not
   // request temporary permissions.
@@ -525,7 +524,6 @@
     return;
 
   active_players_.erase(player_id);
-  MediaThrottler::GetInstance()->OnDecodeRequestFinished();
 }
 
 int BrowserMediaPlayerManager::RoutingID() {
@@ -545,24 +543,4 @@
   player->Release();
 }
 
-void BrowserMediaPlayerManager::OnPlaybackPermissionGranted(
-    int player_id, bool granted) {
-  if (!granted)
-    return;
-
-  MediaThrottler::GetInstance()->Reset();
-  StartInternal(player_id);
-}
-
-void BrowserMediaPlayerManager::StartInternal(int player_id) {
-  MediaPlayerAndroid* player = GetPlayer(player_id);
-  if (!player)
-    return;
-  player->Start();
-  if (fullscreen_player_id_ == player_id && fullscreen_player_is_released_) {
-    video_view_->OpenVideo();
-    fullscreen_player_is_released_ = false;
-  }
-}
-
 }  // namespace content
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h
index 6fb9a4f..edbe2da3 100644
--- a/content/browser/media/android/browser_media_player_manager.h
+++ b/content/browser/media/android/browser_media_player_manager.h
@@ -48,7 +48,8 @@
   static void RegisterMediaUrlInterceptor(
       media::MediaUrlInterceptor* media_url_interceptor);
 
-  // Returns a new instance using the registered factory if available.
+  // Returns a new instance using the registered factory.
+  // Returns nullptr if no factory was registered.
   static BrowserMediaPlayerManager* Create(RenderFrameHost* rfh);
 
 #if !defined(USE_AURA)
@@ -160,12 +161,6 @@
   // player from |players_|.
   void ReleasePlayer(media::MediaPlayerAndroid* player);
 
-  // Called when user approves media playback after being throttled.
-  void OnPlaybackPermissionGranted(int player_id, bool granted);
-
-  // Helper method to start playback.
-  void StartInternal(int player_id);
-
   RenderFrameHost* const render_frame_host_;
 
   // An array of managed players.
diff --git a/content/browser/media/android/media_throttler.cc b/content/browser/media/android/media_throttler.cc
deleted file mode 100644
index 1782373..0000000
--- a/content/browser/media/android/media_throttler.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/media/android/media_throttler.h"
-
-#include "base/android/context_utils.h"
-#include "base/android/jni_android.h"
-#include "jni/MediaThrottler_jni.h"
-
-namespace content {
-
-// static
-MediaThrottler* MediaThrottler::GetInstance() {
-  return base::Singleton<MediaThrottler>::get();
-}
-
-MediaThrottler::~MediaThrottler() {}
-
-bool MediaThrottler::RequestDecoderResources() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  return Java_MediaThrottler_requestDecoderResources(env, j_media_throttler_);
-}
-
-void MediaThrottler::OnDecodeRequestFinished() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_MediaThrottler_onDecodeRequestFinished(env, j_media_throttler_);
-}
-
-void MediaThrottler::Reset() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_MediaThrottler_reset(env, j_media_throttler_);
-}
-
-MediaThrottler::MediaThrottler() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  CHECK(env);
-
-  j_media_throttler_.Reset(Java_MediaThrottler_create(
-      env, base::android::GetApplicationContext()));
-}
-
-}  // namespace content
diff --git a/content/browser/media/android/media_throttler.h b/content/browser/media/android/media_throttler.h
deleted file mode 100644
index 65130ba..0000000
--- a/content/browser/media/android/media_throttler.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_THROTTLER_H_
-#define CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_THROTTLER_H_
-
-#include <jni.h>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "base/memory/singleton.h"
-
-namespace content {
-
-class MediaThrottler {
- public:
-  // Called to get the singleton MediaThrottler instance.
-  static MediaThrottler* GetInstance();
-
-  virtual ~MediaThrottler();
-
-  // Called to request the permission to decode media data. Returns true if
-  // permitted, or false otherwise.
-  bool RequestDecoderResources();
-
-  // Called when a decode request finishes.
-  void OnDecodeRequestFinished();
-
-  // Resets the throttler to a fresh state.
-  void Reset();
-
- private:
-  friend struct base::DefaultSingletonTraits<MediaThrottler>;
-  MediaThrottler();
-
-  base::android::ScopedJavaGlobalRef<jobject> j_media_throttler_;
-  DISALLOW_COPY_AND_ASSIGN(MediaThrottler);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_THROTTLER_H_
diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc
index c61a0b0a..63eaf6f8 100644
--- a/content/browser/media/android/media_web_contents_observer_android.cc
+++ b/content/browser/media/android/media_web_contents_observer_android.cc
@@ -115,44 +115,50 @@
 bool MediaWebContentsObserverAndroid::OnMediaPlayerMessageReceived(
     const IPC::Message& msg,
     RenderFrameHost* render_frame_host) {
+  // The only BMPM instance that is still currently used is the
+  // RemoteMediaPlayerManager, used in casting.
+  //
+  // In the webview case, casting is not supported, and GetMediaPlayerManager()
+  // will return a nullptr. It is safe to not handle the messages, since the
+  // only message we can receive is an unavoidable MediaPlayerHostMsg_Initialize
+  // that WMPI sends out in WebMediaPlayerImpl::DoLoad().
+  BrowserMediaPlayerManager* media_player_manager =
+      GetMediaPlayerManager(render_frame_host);
+
+  if (!media_player_manager)
+    return false;
+
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(MediaWebContentsObserverAndroid, msg)
     IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_EnterFullscreen,
-                        GetMediaPlayerManager(render_frame_host),
+                        media_player_manager,
                         BrowserMediaPlayerManager::OnEnterFullscreen)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize,
-                        GetMediaPlayerManager(render_frame_host),
+    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Initialize, media_player_manager,
                         BrowserMediaPlayerManager::OnInitialize)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Start,
-                        GetMediaPlayerManager(render_frame_host),
+    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Start, media_player_manager,
                         BrowserMediaPlayerManager::OnStart)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Seek,
-                        GetMediaPlayerManager(render_frame_host),
+    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Seek, media_player_manager,
                         BrowserMediaPlayerManager::OnSeek)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Pause,
-                        GetMediaPlayerManager(render_frame_host),
+    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_Pause, media_player_manager,
                         BrowserMediaPlayerManager::OnPause)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetVolume,
-                        GetMediaPlayerManager(render_frame_host),
+    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetVolume, media_player_manager,
                         BrowserMediaPlayerManager::OnSetVolume)
-    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetPoster,
-                        GetMediaPlayerManager(render_frame_host),
+    IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SetPoster, media_player_manager,
                         BrowserMediaPlayerManager::OnSetPoster)
     IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_SuspendAndRelease,
-                        GetMediaPlayerManager(render_frame_host),
+                        media_player_manager,
                         BrowserMediaPlayerManager::OnSuspendAndReleaseResources)
     IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_DestroyMediaPlayer,
-                        GetMediaPlayerManager(render_frame_host),
+                        media_player_manager,
                         BrowserMediaPlayerManager::OnDestroyPlayer)
     IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlayback,
-                        GetMediaPlayerManager(render_frame_host),
+                        media_player_manager,
                         BrowserMediaPlayerManager::OnRequestRemotePlayback)
     IPC_MESSAGE_FORWARD(
-        MediaPlayerHostMsg_RequestRemotePlaybackControl,
-        GetMediaPlayerManager(render_frame_host),
+        MediaPlayerHostMsg_RequestRemotePlaybackControl, media_player_manager,
         BrowserMediaPlayerManager::OnRequestRemotePlaybackControl)
     IPC_MESSAGE_FORWARD(MediaPlayerHostMsg_RequestRemotePlaybackStop,
-                        GetMediaPlayerManager(render_frame_host),
+                        media_player_manager,
                         BrowserMediaPlayerManager::OnRequestRemotePlaybackStop)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
index 25c56ffb..9538287 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_aura.cc
@@ -149,17 +149,16 @@
   ui::EventType event_type =
       WebMouseEventTypeToEventType(web_mouse_event.GetType());
   int flags = WebEventModifiersToEventFlags(web_mouse_event.GetModifiers());
+  ui::PointerDetails pointer_details(
+      WebMousePointerTypeToEventPointerType(web_mouse_event.pointer_type));
   ui::MouseEvent mouse_event(event_type, gfx::Point(), gfx::Point(),
-                             ui::EventTimeForNow(), flags, flags);
+                             ui::EventTimeForNow(), flags, flags,
+                             pointer_details);
   gfx::PointF location(
       web_mouse_event.PositionInWidget().x * device_scale_factor_,
       web_mouse_event.PositionInWidget().y * device_scale_factor_);
   mouse_event.set_location_f(location);
   mouse_event.set_root_location_f(location);
-  ui::PointerDetails pointer_details = mouse_event.pointer_details();
-  pointer_details.pointer_type =
-      WebMousePointerTypeToEventPointerType(web_mouse_event.pointer_type);
-  mouse_event.set_pointer_details(pointer_details);
 
   aura::Window* window = GetWindow();
   mouse_event.ConvertLocationToTarget(window, window->GetRootWindow());
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 0d6f9e348..da4804e 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -80,10 +80,6 @@
 #include "base/file_descriptor_posix.h"
 #endif
 
-#if defined(OS_ANDROID)
-#include "content/browser/media/android/media_throttler.h"
-#endif
-
 #if defined(OS_MACOSX)
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #endif
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index a691ef8..05f7cfe 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -183,7 +183,6 @@
 #include "ppapi/features/features.h"
 #include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "services/service_manager/runner/common/client_util.h"
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index ea61cbf..4c5b066 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -40,7 +40,6 @@
 #include "content/public/common/service_manager_connection.h"
 #include "content/public/common/service_names.mojom.h"
 #include "mojo/edk/embedder/embedder.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "ui/base/ui_base_switches.h"
 
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index a5718012..7500a8f 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -66,7 +66,6 @@
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 #include "services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h"
-#include "services/device/public/interfaces/constants.mojom.h"
 #include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
@@ -510,13 +509,8 @@
   // also for some edge cases where there is no ServiceManagerConnection, we do
   // not create the power monitor.
   if (!base::PowerMonitor::Get() && service_manager_connection_) {
-    std::unique_ptr<service_manager::Connection> device_connection =
-        service_manager_connection_->GetConnector()->Connect(
-            device::mojom::kServiceName);
     auto power_monitor_source =
-        base::MakeUnique<device::PowerMonitorBroadcastSource>(
-            device_connection->GetRemoteInterfaces());
-
+        base::MakeUnique<device::PowerMonitorBroadcastSource>(GetConnector());
     power_monitor_.reset(
         new base::PowerMonitor(std::move(power_monitor_source)));
   }
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index 50254c1..4484df9 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -620,7 +620,8 @@
     const url::Origin& frame_origin,
     std::unique_ptr<RequestPeer> peer,
     blink::WebURLRequest::LoadingIPCType ipc_type,
-    mojom::URLLoaderFactory* url_loader_factory) {
+    mojom::URLLoaderFactory* url_loader_factory,
+    mojo::ScopedDataPipeConsumerHandle consumer_handle) {
   CheckSchemeForReferrerPolicy(*request);
 
   // Compute a unique request_id for this renderer process.
@@ -634,6 +635,21 @@
                                                         loading_task_runner);
   }
 
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+      loading_task_runner ? loading_task_runner : main_thread_task_runner_;
+
+  if (consumer_handle.is_valid()) {
+    pending_requests_[request_id]->url_loader_client =
+        base::MakeUnique<URLLoaderClientImpl>(request_id, this, task_runner);
+
+    task_runner->PostTask(FROM_HERE,
+                          base::Bind(&ResourceDispatcher::ContinueForNavigation,
+                                     weak_factory_.GetWeakPtr(), request_id,
+                                     base::Passed(std::move(consumer_handle))));
+
+    return request_id;
+  }
+
   if (ipc_type == blink::WebURLRequest::LoadingIPCType::kMojo) {
     scoped_refptr<base::SingleThreadTaskRunner> task_runner =
         loading_task_runner ? loading_task_runner : main_thread_task_runner_;
@@ -735,6 +751,36 @@
   return result;
 }
 
+void ResourceDispatcher::ContinueForNavigation(
+    int request_id,
+    mojo::ScopedDataPipeConsumerHandle consumer_handle) {
+  PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
+  if (!request_info)
+    return;
+
+  URLLoaderClientImpl* client_ptr = request_info->url_loader_client.get();
+
+  // Short circuiting call to OnReceivedResponse to immediately start
+  // the request. ResourceResponseHead can be empty here because we
+  // pull the StreamOverride's one in
+  // WebURLLoaderImpl::Context::OnReceivedResponse.
+  client_ptr->OnReceiveResponse(ResourceResponseHead(),
+                                mojom::DownloadedTempFilePtr());
+  // Start streaming now.
+  client_ptr->OnStartLoadingResponseBody(std::move(consumer_handle));
+
+  // Call OnComplete now too, as it won't get called on the client.
+  // TODO(kinuko): Fill this properly.
+  ResourceRequestCompletionStatus completion_status;
+  completion_status.error_code = net::OK;
+  completion_status.was_ignored_by_handler = false;
+  completion_status.exists_in_cache = false;
+  completion_status.completion_time = base::TimeTicks::Now();
+  completion_status.encoded_data_length = -1;
+  completion_status.encoded_body_length = -1;
+  client_ptr->OnComplete(completion_status);
+}
+
 // static
 bool ResourceDispatcher::IsResourceDispatcherMessage(
     const IPC::Message& message) {
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h
index 5554c44b..8b61daf 100644
--- a/content/child/resource_dispatcher.h
+++ b/content/child/resource_dispatcher.h
@@ -26,6 +26,7 @@
 #include "content/public/common/resource_type.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/base/request_priority.h"
 #include "third_party/WebKit/public/platform/WebURLRequest.h"
 #include "url/gurl.h"
@@ -98,7 +99,8 @@
       const url::Origin& frame_origin,
       std::unique_ptr<RequestPeer> peer,
       blink::WebURLRequest::LoadingIPCType ipc_type,
-      mojom::URLLoaderFactory* url_loader_factory);
+      mojom::URLLoaderFactory* url_loader_factory,
+      mojo::ScopedDataPipeConsumerHandle consumer_handle);
 
   // Removes a request from the |pending_requests_| list, returning true if the
   // request was found and removed.
@@ -240,6 +242,10 @@
   // invocations will return current time until set_io_timestamp is called.
   base::TimeTicks ConsumeIOTimestamp();
 
+  void ContinueForNavigation(
+      int request_id,
+      mojo::ScopedDataPipeConsumerHandle consumer_handle);
+
   // Returns true if the message passed in is a resource related message.
   static bool IsResourceDispatcherMessage(const IPC::Message& message);
 
diff --git a/content/child/resource_dispatcher_unittest.cc b/content/child/resource_dispatcher_unittest.cc
index 700e30c..24ae91c1 100644
--- a/content/child/resource_dispatcher_unittest.cc
+++ b/content/child/resource_dispatcher_unittest.cc
@@ -229,7 +229,8 @@
         new TestRequestPeer(dispatcher(), peer_context));
     int request_id = dispatcher()->StartAsync(
         std::move(request), 0, nullptr, url::Origin(), std::move(peer),
-        blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr);
+        blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr,
+        mojo::ScopedDataPipeConsumerHandle());
     peer_context->request_id = request_id;
     return request_id;
   }
diff --git a/content/child/url_loader_client_impl_unittest.cc b/content/child/url_loader_client_impl_unittest.cc
index f6705b46..61b62c86 100644
--- a/content/child/url_loader_client_impl_unittest.cc
+++ b/content/child/url_loader_client_impl_unittest.cc
@@ -33,7 +33,7 @@
         base::MakeUnique<TestRequestPeer>(dispatcher_.get(),
                                           &request_peer_context_),
         blink::WebURLRequest::LoadingIPCType::kMojo,
-        url_loader_factory_proxy_.get());
+        url_loader_factory_proxy_.get(), mojo::ScopedDataPipeConsumerHandle());
     request_peer_context_.request_id = request_id_;
 
     base::RunLoop().RunUntilIdle();
diff --git a/content/child/url_response_body_consumer_unittest.cc b/content/child/url_response_body_consumer_unittest.cc
index 5ab0035a..af05919c 100644
--- a/content/child/url_response_body_consumer_unittest.cc
+++ b/content/child/url_response_body_consumer_unittest.cc
@@ -137,7 +137,8 @@
     return dispatcher_->StartAsync(
         std::move(request), 0, nullptr, url::Origin(),
         base::MakeUnique<TestRequestPeer>(context, message_loop_.task_runner()),
-        blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr);
+        blink::WebURLRequest::LoadingIPCType::kChromeIPC, nullptr,
+        mojo::ScopedDataPipeConsumerHandle());
   }
 
   void Run(TestRequestPeer::Context* context) {
diff --git a/content/child/web_url_loader_impl.cc b/content/child/web_url_loader_impl.cc
index 3b31280d..716adc9 100644
--- a/content/child/web_url_loader_impl.cc
+++ b/content/child/web_url_loader_impl.cc
@@ -602,11 +602,16 @@
   // PlzNavigate: during navigation, the renderer should request a stream which
   // contains the body of the response. The network request has already been
   // made by the browser.
+  mojo::ScopedDataPipeConsumerHandle consumer_handle;
   if (stream_override_.get()) {
     CHECK(IsBrowserSideNavigationEnabled());
     DCHECK(!sync_load_response);
     DCHECK_NE(WebURLRequest::kFrameTypeNone, request.GetFrameType());
-    resource_request->resource_body_stream_url = stream_override_->stream_url;
+    if (stream_override_->consumer_handle.is_valid()) {
+      consumer_handle = std::move(stream_override_->consumer_handle);
+    } else {
+      resource_request->resource_body_stream_url = stream_override_->stream_url;
+    }
   }
 
   // PlzNavigate: Invalid renderer main resource requests are rejected by the
@@ -641,7 +646,8 @@
       std::move(resource_request), request.RequestorID(), task_runner_,
       extra_data->frame_origin(),
       base::MakeUnique<WebURLLoaderImpl::RequestPeerImpl>(this),
-      request.GetLoadingIPCType(), url_loader_factory_);
+      request.GetLoadingIPCType(), url_loader_factory_,
+      std::move(consumer_handle));
 
   if (defers_loading_ != NOT_DEFERRING)
     resource_dispatcher_->SetDefersLoading(request_id_, true);
@@ -808,6 +814,13 @@
   if (!client_)
     return;
 
+  if (stream_override_ && stream_override_->stream_url.is_empty()) {
+    // Since ResourceDispatcher::ContinueForNavigation called OnComplete
+    // immediately, it didn't have the size of the resource immediately. So as
+    // data is read off the data pipe, keep track of how much we're reading.
+    stream_override_->total_transferred += data_length;
+  }
+
   TRACE_EVENT_WITH_FLOW0(
       "loading", "WebURLLoaderImpl::Context::OnReceivedData",
       this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT);
@@ -850,6 +863,12 @@
     const base::TimeTicks& completion_time,
     int64_t total_transfer_size,
     int64_t encoded_body_size) {
+  if (stream_override_ && stream_override_->stream_url.is_empty()) {
+    // TODO(kinuko|scottmg|jam): This is wrong. https://crbug.com/705744.
+    total_transfer_size = stream_override_->total_transferred;
+    encoded_body_size = stream_override_->total_transferred;
+  }
+
   if (ftp_listing_delegate_) {
     ftp_listing_delegate_->OnCompletedRequest();
     ftp_listing_delegate_.reset(NULL);
diff --git a/content/child/web_url_loader_impl.h b/content/child/web_url_loader_impl.h
index 5f8eef6..a382570 100644
--- a/content/child/web_url_loader_impl.h
+++ b/content/child/web_url_loader_impl.h
@@ -10,6 +10,7 @@
 #include "content/common/content_export.h"
 #include "content/common/url_loader_factory.mojom.h"
 #include "content/public/common/resource_response.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/url_request/redirect_info.h"
 #include "third_party/WebKit/public/platform/WebURLLoader.h"
 #include "url/gurl.h"
@@ -27,6 +28,7 @@
   // TODO(clamy): The browser should be made aware on destruction of this struct
   // that it can release its associated stream handle.
   GURL stream_url;
+  mojo::ScopedDataPipeConsumerHandle consumer_handle;
   ResourceResponseHead response;
   std::vector<GURL> redirects;
   std::vector<ResourceResponseInfo> redirect_responses;
@@ -35,6 +37,8 @@
   // The delta between the actual transfer size and the one reported by the
   // AsyncResourceLoader due to not having the ResourceResponse.
   int total_transfer_size_delta;
+
+  int total_transferred = 0;
 };
 
 class CONTENT_EXPORT WebURLLoaderImpl
diff --git a/content/child/web_url_loader_impl_unittest.cc b/content/child/web_url_loader_impl_unittest.cc
index 267d027..e4877d24 100644
--- a/content/child/web_url_loader_impl_unittest.cc
+++ b/content/child/web_url_loader_impl_unittest.cc
@@ -82,7 +82,8 @@
       const url::Origin& frame_origin,
       std::unique_ptr<RequestPeer> peer,
       blink::WebURLRequest::LoadingIPCType ipc_type,
-      mojom::URLLoaderFactory* url_loader_factory) override {
+      mojom::URLLoaderFactory* url_loader_factory,
+      mojo::ScopedDataPipeConsumerHandle consumer_handle) override {
     EXPECT_FALSE(peer_);
     peer_ = std::move(peer);
     url_ = request->url;
diff --git a/content/common/content_param_traits.h b/content/common/content_param_traits.h
index 640207c..6cd7d92 100644
--- a/content/common/content_param_traits.h
+++ b/content/common/content_param_traits.h
@@ -16,6 +16,7 @@
 
 #include "content/common/content_param_traits_macros.h"
 #include "content/common/cursors/webcursor.h"
+#include "ipc/ipc_mojo_param_traits.h"
 #include "third_party/WebKit/public/platform/WebInputEvent.h"
 
 namespace content {
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 002ae95d..b8be34e0 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -907,12 +907,14 @@
 // PlzNavigate
 // Tells the renderer that a navigation is ready to commit.  The renderer should
 // request |stream_url| to get access to the stream containing the body of the
-// response.
-IPC_MESSAGE_ROUTED4(FrameMsg_CommitNavigation,
-                    content::ResourceResponseHead,    /* response */
-                    GURL,                             /* stream_url */
-                    content::CommonNavigationParams,  /* common_params */
-                    content::RequestNavigationParams  /* request_params */)
+// response. When --enable-network-service is in effect, |stream_url| is not
+// used, and instead the data is passed to the renderer in |handle|.
+IPC_MESSAGE_ROUTED5(FrameMsg_CommitNavigation,
+                    content::ResourceResponseHead,   /* response */
+                    GURL,                            /* stream_url */
+                    mojo::DataPipeConsumerHandle,    /* handle */
+                    content::CommonNavigationParams, /* common_params */
+                    content::RequestNavigationParams /* request_params */)
 
 // PlzNavigate
 // Tells the renderer that a navigation failed with the error code |error_code|
diff --git a/content/common/input/synthetic_web_input_event_builders.cc b/content/common/input/synthetic_web_input_event_builders.cc
index 2719f50..5e5638e 100644
--- a/content/common/input/synthetic_web_input_event_builders.cc
+++ b/content/common/input/synthetic_web_input_event_builders.cc
@@ -38,7 +38,7 @@
   result.SetPositionInWidget(window_x, window_y);
   result.SetModifiers(modifiers);
   result.pointer_type = pointer_type;
-  result.id = ui::PointerEvent::kMousePointerId;
+  result.id = ui::MouseEvent::kMousePointerId;
   return result;
 }
 
diff --git a/content/network/url_loader_impl.cc b/content/network/url_loader_impl.cc
index 6732481..a29cec4 100644
--- a/content/network/url_loader_impl.cc
+++ b/content/network/url_loader_impl.cc
@@ -167,6 +167,8 @@
       GURL(request.url), net::DEFAULT_PRIORITY, this);
   url_request_->set_method(request.method);
 
+  url_request_->set_first_party_for_cookies(request.first_party_for_cookies);
+
   const Referrer referrer(request.referrer, request.referrer_policy);
   Referrer::SetReferrerForRequest(url_request_.get(), referrer);
 
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 90eef04..e87b476c 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -139,7 +139,6 @@
     "java/src/org/chromium/content/browser/LauncherThread.java",
     "java/src/org/chromium/content/browser/MediaResourceGetter.java",
     "java/src/org/chromium/content/browser/MediaSessionImpl.java",
-    "java/src/org/chromium/content/browser/MediaThrottler.java",
     "java/src/org/chromium/content/browser/MemoryMonitorAndroid.java",
     "java/src/org/chromium/content/browser/MotionEventSynthesizer.java",
     "java/src/org/chromium/content/browser/NfcFactory.java",
@@ -344,7 +343,6 @@
     "java/src/org/chromium/content/browser/LauncherThread.java",
     "java/src/org/chromium/content/browser/MediaResourceGetter.java",
     "java/src/org/chromium/content/browser/MediaSessionImpl.java",
-    "java/src/org/chromium/content/browser/MediaThrottler.java",
     "java/src/org/chromium/content/browser/MemoryMonitorAndroid.java",
     "java/src/org/chromium/content/browser/MotionEventSynthesizer.java",
     "java/src/org/chromium/content/browser/ScreenOrientationProvider.java",
diff --git a/content/public/android/java/src/org/chromium/content/browser/MediaThrottler.java b/content/public/android/java/src/org/chromium/content/browser/MediaThrottler.java
deleted file mode 100644
index ece07e1..0000000
--- a/content/public/android/java/src/org/chromium/content/browser/MediaThrottler.java
+++ /dev/null
@@ -1,224 +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.content.browser;
-
-import android.content.Context;
-import android.media.MediaPlayer;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.SystemClock;
-
-import org.chromium.base.Log;
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.content.R;
-
-/**
- * Class for listening to Android MediaServer Crashes to throttle media decoding
- * when needed.
- */
-@JNINamespace("content")
-class MediaThrottler implements MediaPlayer.OnErrorListener {
-    private static final String TAG = "cr_MediaThrottler";
-    private static final long UNKNOWN_LAST_SERVER_CRASH_TIME = -1;
-
-    // Number of active decode requests.
-    private int mRequestCount;
-
-    // Application context.
-    private final Context mContext;
-
-    // Watch dog player. Used to listen to all media server crashes.
-    private MediaPlayer mPlayer;
-
-    // The last media server crash time since Chrome lauches.
-    private long mLastCrashTime = UNKNOWN_LAST_SERVER_CRASH_TIME;
-
-    // Server crash count since last reset() call.
-    private int mServerCrashCount;
-
-    // Object for synchronized access to memeber variables.
-    private final Object mLock = new Object();
-
-    // Handler for posting delayed tasks.
-    private Handler mHandler;
-
-    // Intervals between media server crashes that are considered normal. It
-    // takes about 5 seconds to restart the media server. So this value has to
-    // be larger than 5 seconds.
-    private static final long SERVER_CRASH_INTERVAL_THRESHOLD_IN_MILLIS = 60000;
-
-    // Delay to keep the watch dog player alive When there are no decoding
-    // requests. This is introduced to avoid recreating the watch dog over and
-    // over if a burst of small decoding requests arrive.
-    private static final int RELEASE_WATCH_DOG_PLAYER_DELAY_IN_MILLIS = 5000;
-
-    // When |mServerCrashCount| reaches this threshold, throttling will start.
-    // This is to prevent a page from loading a malformed video over and over
-    // to crash the media server excessively.
-    private static final int SERVER_CRASH_COUNT_THRESHOLD_FOR_THROTTLING = 4;
-
-    /**
-     * A background task to release the watch dog player.
-     */
-    private class ReleaseWatchDogTask extends AsyncTask<Void, Void, Void> {
-        @Override
-        protected Void doInBackground(Void... voids) {
-            synchronized (mLock) {
-                if (mRequestCount == 0 && mPlayer != null) {
-                    mPlayer.release();
-                    mPlayer = null;
-                }
-            }
-            return null;
-        }
-    }
-
-    private final Runnable mDelayedReleaseRunnable = new Runnable() {
-        @Override
-        public void run() {
-            new ReleaseWatchDogTask().execute();
-        }
-    };
-
-    @CalledByNative
-    private static MediaThrottler create(Context context) {
-        return new MediaThrottler(context);
-    }
-
-    private MediaThrottler(Context context) {
-        mContext = context;
-        mHandler = new Handler(Looper.getMainLooper());
-    }
-
-    /**
-     * A background task to start the watch dog player.
-     */
-    private class StartWatchDogTask extends AsyncTask<Void, Void, Void> {
-        @Override
-        protected Void doInBackground(Void... voids) {
-            synchronized (mLock) {
-                if (mPlayer != null || mRequestCount == 0) return null;
-                try {
-                    mPlayer = MediaPlayer.create(mContext, R.raw.empty);
-                } catch (IllegalStateException e) {
-                    Log.e(TAG, "Exception happens while creating the watch dog player.", e);
-                } catch (RuntimeException e) {
-                    Log.e(TAG, "Exception happens while creating the watch dog player.", e);
-                }
-                if (mPlayer == null) {
-                    Log.e(TAG, "Unable to create watch dog player, treat it as server crash.");
-                    onMediaServerCrash();
-                } else {
-                    mPlayer.setOnErrorListener(MediaThrottler.this);
-                }
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Called to request the permission to decode media data.
-     *
-     * @return true if the request is permitted, or false otherwise.
-     */
-    @CalledByNative
-    private boolean requestDecoderResources() {
-        synchronized (mLock) {
-            long currentTime = SystemClock.elapsedRealtime();
-            if (mLastCrashTime != UNKNOWN_LAST_SERVER_CRASH_TIME
-                    && (currentTime - mLastCrashTime < SERVER_CRASH_INTERVAL_THRESHOLD_IN_MILLIS)
-                    && mServerCrashCount >= SERVER_CRASH_COUNT_THRESHOLD_FOR_THROTTLING) {
-                Log.e(TAG, "Request to decode media data denied due to throttling.");
-                return false;
-            }
-            mRequestCount++;
-            if (mRequestCount == 1 || mPlayer == null) {
-                mHandler.removeCallbacks(mDelayedReleaseRunnable);
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        new StartWatchDogTask().execute();
-                    }
-                });
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Called to signal that a decode request has been completed.
-     */
-    @CalledByNative
-    private void onDecodeRequestFinished() {
-        synchronized (mLock) {
-            mRequestCount--;
-            if (mRequestCount == 0) {
-                // Don't release the watch dog immediately, there could be a
-                // number of small requests coming together.
-                prepareToStopWatchDog();
-            }
-        }
-    }
-
-    /**
-     * Posts a delayed task to stop the watch dog player.
-     */
-    private void prepareToStopWatchDog() {
-        mHandler.postDelayed(mDelayedReleaseRunnable, RELEASE_WATCH_DOG_PLAYER_DELAY_IN_MILLIS);
-    }
-
-    @Override
-    public boolean onError(MediaPlayer mp, int what, int extra) {
-        if (what == MediaPlayer.MEDIA_ERROR_SERVER_DIED) {
-            synchronized (mLock) {
-                onMediaServerCrash();
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Called when media server crashes.
-     */
-    private void onMediaServerCrash() {
-        assert Thread.holdsLock(mLock);
-        long currentTime = SystemClock.elapsedRealtime();
-        if (mLastCrashTime != UNKNOWN_LAST_SERVER_CRASH_TIME
-                && (currentTime - mLastCrashTime < SERVER_CRASH_INTERVAL_THRESHOLD_IN_MILLIS)) {
-            mServerCrashCount++;
-        } else {
-            recordNumMediaServerCrashes();
-            mServerCrashCount = 1;
-        }
-        mLastCrashTime = currentTime;
-    }
-
-    /**
-     * Resets the MediaThrottler to its initial state so that subsequent requests
-     * will not be throttled.
-     */
-    @CalledByNative
-    private void reset() {
-        synchronized (mLock) {
-            recordNumMediaServerCrashes();
-            mServerCrashCount = 0;
-            mLastCrashTime = UNKNOWN_LAST_SERVER_CRASH_TIME;
-        }
-    }
-
-    /**
-     * Records the number of consecutive media server crashes in UMA.
-     */
-    private void recordNumMediaServerCrashes() {
-        assert Thread.holdsLock(mLock);
-        if (mServerCrashCount > 0) {
-            RecordHistogram.recordCountHistogram(
-                    "Media.Android.NumMediaServerCrashes", mServerCrashCount);
-        }
-    }
-}
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 40581d3..1f85972 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -29,6 +29,7 @@
           "device:time_zone_monitor",
           "device:vibration"
         ],
+        "network": [ "url_loader" ],
         "ui": [
           "discardable_memory",
           "gpu_client"
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 3d69d32..6a368e18 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -208,12 +208,6 @@
 }
 
 #if defined(OS_ANDROID)
-void WebContentsDelegate::RequestMediaDecodePermission(
-    WebContents* web_contents,
-    const base::Callback<void(bool)>& callback) {
-  callback.Run(false);
-}
-
 base::android::ScopedJavaLocalRef<jobject>
 WebContentsDelegate::GetContentVideoViewEmbedder() {
   return base::android::ScopedJavaLocalRef<jobject>();
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index bb2d849e..232d3a9 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -490,12 +490,6 @@
                                               MediaStreamType type);
 
 #if defined(OS_ANDROID)
-  // Asks permission to decode media stream. After permission is determined,
-  // |callback| will be called with the result.
-  virtual void RequestMediaDecodePermission(
-      WebContents* web_contents,
-      const base::Callback<void(bool)>& callback);
-
   // Creates a view embedding the video view.
   virtual base::android::ScopedJavaLocalRef<jobject>
       GetContentVideoViewEmbedder();
diff --git a/content/public/test/test_service.cc b/content/public/test/test_service.cc
index 4e45f21..1763106 100644
--- a/content/public/test/test_service.cc
+++ b/content/public/test/test_service.cc
@@ -8,7 +8,6 @@
 
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace content {
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 334cdba..a978544e 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5197,6 +5197,7 @@
 void RenderFrameImpl::OnCommitNavigation(
     const ResourceResponseHead& response,
     const GURL& stream_url,
+    mojo::DataPipeConsumerHandle handle,
     const CommonNavigationParams& common_params,
     const RequestNavigationParams& request_params) {
   CHECK(IsBrowserSideNavigationEnabled());
@@ -5205,6 +5206,7 @@
   std::unique_ptr<StreamOverrideParameters> stream_override(
       new StreamOverrideParameters());
   stream_override->stream_url = stream_url;
+  stream_override->consumer_handle = mojo::ScopedDataPipeConsumerHandle(handle);
   stream_override->response = response;
   stream_override->redirects = request_params.redirects;
   stream_override->redirect_responses = request_params.redirect_response;
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 9fbf80e..c9abba4 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -52,6 +52,7 @@
 #include "media/mojo/interfaces/remoting.mojom.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "ppapi/features/features.h"
 #include "services/service_manager/public/cpp/service_info.h"
 #include "services/service_manager/public/interfaces/connector.mojom.h"
@@ -892,6 +893,7 @@
   void OnPostMessageEvent(const FrameMsg_PostMessage_Params& params);
   void OnCommitNavigation(const ResourceResponseHead& response,
                           const GURL& stream_url,
+                          mojo::DataPipeConsumerHandle handle,
                           const CommonNavigationParams& common_params,
                           const RequestNavigationParams& request_params);
   void OnFailedNavigation(const CommonNavigationParams& common_params,
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 27eaf39..4ba0c48 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -306,13 +306,29 @@
 
 blink::WebURLLoader* RendererBlinkPlatformImpl::CreateURLLoader() {
   ChildThreadImpl* child_thread = ChildThreadImpl::current();
-  if (!url_loader_factory_ && child_thread)
-    child_thread->channel()->GetRemoteAssociatedInterface(&url_loader_factory_);
+
+  mojom::URLLoaderFactory* factory =
+      url_loader_factory_ ? url_loader_factory_.get()
+                          : network_service_url_loader_factory_.get();
+  if (!factory && child_thread) {
+    bool network_service_enabled =
+        base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kEnableNetworkService);
+    if (network_service_enabled) {
+      connector_->BindInterface(mojom::kNetworkServiceName,
+                                &network_service_url_loader_factory_);
+      factory = network_service_url_loader_factory_.get();
+    } else {
+      child_thread->channel()->GetRemoteAssociatedInterface(
+          &url_loader_factory_);
+      factory = url_loader_factory_.get();
+    }
+  }
+
   // There may be no child thread in RenderViewTests.  These tests can still use
   // data URLs to bypass the ResourceDispatcher.
   return new content::WebURLLoaderImpl(
-      child_thread ? child_thread->resource_dispatcher() : nullptr,
-      url_loader_factory_.get());
+      child_thread ? child_thread->resource_dispatcher() : nullptr, factory);
 }
 
 blink::WebThread* RendererBlinkPlatformImpl::CurrentThread() {
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index f6adbef..19306dfd 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -304,6 +304,9 @@
 
   mojom::URLLoaderFactoryAssociatedPtr url_loader_factory_;
 
+  // Only used when network service is enabled.
+  mojom::URLLoaderFactoryPtr network_service_url_loader_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(RendererBlinkPlatformImpl);
 };
 
diff --git a/content/test/gpu/gpu_tests/gpu_process_expectations.py b/content/test/gpu/gpu_tests/gpu_process_expectations.py
index b459316..e8faff5 100644
--- a/content/test/gpu/gpu_tests/gpu_process_expectations.py
+++ b/content/test/gpu/gpu_tests/gpu_process_expectations.py
@@ -19,7 +19,6 @@
 
     # Chrome on Windows and Linux create a GPU process that uses SwiftShader
     # when using either --disable-gpu or a blacklisted GPU.
-    self.Skip('GpuProcess_no_gpu_process', ['win', 'debug'], bug=630728)
     self.Skip('GpuProcess_skip_gpu_process', ['win', 'linux'], bug=630728)
 
     # Currently SwiftShader is integrated only on Windows and Linux. Remove
diff --git a/content/test/gpu/gpu_tests/pixel_expectations.py b/content/test/gpu/gpu_tests/pixel_expectations.py
index 681236c..798ccc2 100644
--- a/content/test/gpu/gpu_tests/pixel_expectations.py
+++ b/content/test/gpu/gpu_tests/pixel_expectations.py
@@ -52,18 +52,3 @@
 
     # TODO(jbauman): Re-enable when references images created.
     self.Fail('Pixel_DirectComposition_Video_*', ['win'], bug=704389)
-
-    # TODO(xlai): Remove this after verifying reference images.
-    self.Fail('Pixel_OffscreenCanvasAccelerated2D', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasAccelerated2DWorker', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasUnaccelerated2D', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasUnaccelerated2DWorker', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasUnaccelerated2DGPUCompositing',
-        bug=706647)
-    self.Fail('Pixel_OffscreenCanvasUnaccelerated2DGPUCompositingWorker',
-        bug=706647)
-    self.Fail('Pixel_OffscreenCanvasWebGLDefault', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasWebGLDefaultWorker', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasWebGLSoftwareCompositing', bug=706647)
-    self.Fail('Pixel_OffscreenCanvasWebGLSoftwareCompositingWorker',
-        bug=706647)
diff --git a/content/test/test_navigation_url_loader.cc b/content/test/test_navigation_url_loader.cc
index 026778e..0ba5b7e 100644
--- a/content/test/test_navigation_url_loader.cc
+++ b/content/test/test_navigation_url_loader.cc
@@ -56,9 +56,9 @@
     const scoped_refptr<ResourceResponse>& response,
     std::unique_ptr<StreamHandle> body,
     std::unique_ptr<NavigationData> navigation_data) {
-  delegate_->OnResponseStarted(response, std::move(body), SSLStatus(),
-                               std::move(navigation_data), GlobalRequestID(),
-                               false, false);
+  delegate_->OnResponseStarted(
+      response, std::move(body), mojo::ScopedDataPipeConsumerHandle(),
+      SSLStatus(), std::move(navigation_data), GlobalRequestID(), false, false);
 }
 
 TestNavigationURLLoader::~TestNavigationURLLoader() {}
diff --git a/content/test/test_navigation_url_loader_delegate.cc b/content/test/test_navigation_url_loader_delegate.cc
index 443749b..1d74335d 100644
--- a/content/test/test_navigation_url_loader_delegate.cc
+++ b/content/test/test_navigation_url_loader_delegate.cc
@@ -44,6 +44,7 @@
 
 void TestNavigationURLLoaderDelegate::ReleaseBody() {
   body_.reset();
+  handle_.reset();
 }
 
 void TestNavigationURLLoaderDelegate::OnRequestRedirected(
@@ -58,6 +59,7 @@
 void TestNavigationURLLoaderDelegate::OnResponseStarted(
     const scoped_refptr<ResourceResponse>& response,
     std::unique_ptr<StreamHandle> body,
+    mojo::ScopedDataPipeConsumerHandle consumer_handle,
     const SSLStatus& ssl_status,
     std::unique_ptr<NavigationData> navigation_data,
     const GlobalRequestID& request_id,
@@ -65,6 +67,7 @@
     bool is_stream) {
   response_ = response;
   body_ = std::move(body);
+  handle_ = std::move(consumer_handle);
   if (response_started_)
     response_started_->Quit();
 }
diff --git a/content/test/test_navigation_url_loader_delegate.h b/content/test/test_navigation_url_loader_delegate.h
index ddc1402..1916f3f3 100644
--- a/content/test/test_navigation_url_loader_delegate.h
+++ b/content/test/test_navigation_url_loader_delegate.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "content/browser/loader/navigation_url_loader_delegate.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "net/url_request/redirect_info.h"
 
 namespace base {
@@ -56,6 +57,7 @@
       const scoped_refptr<ResourceResponse>& response) override;
   void OnResponseStarted(const scoped_refptr<ResourceResponse>& response,
                          std::unique_ptr<StreamHandle> body,
+                         mojo::ScopedDataPipeConsumerHandle consumer_handle,
                          const SSLStatus& ssl_status,
                          std::unique_ptr<NavigationData> navigation_data,
                          const GlobalRequestID& request_id,
@@ -69,6 +71,7 @@
   scoped_refptr<ResourceResponse> redirect_response_;
   scoped_refptr<ResourceResponse> response_;
   std::unique_ptr<StreamHandle> body_;
+  mojo::ScopedDataPipeConsumerHandle handle_;
   int net_error_;
   int on_request_handled_counter_;
 
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index cd75e627..6c0bb013 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -30,7 +30,8 @@
                                const RequestNavigationParams& request_params) {
   // PlzNavigate
   if (IsBrowserSideNavigationEnabled()) {
-    OnCommitNavigation(ResourceResponseHead(), GURL(), common_params,
+    OnCommitNavigation(ResourceResponseHead(), GURL(),
+                       mojo::DataPipeConsumerHandle(), common_params,
                        request_params);
   } else {
     OnNavigate(common_params, start_params, request_params);
diff --git a/content/utility/utility_service_factory.cc b/content/utility/utility_service_factory.cc
index a1c8336..73c2cf8 100644
--- a/content/utility/utility_service_factory.cc
+++ b/content/utility/utility_service_factory.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "content/child/child_process.h"
 #include "content/network/network_service.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_switches.h"
@@ -60,6 +61,7 @@
           switches::kEnableNetworkService)) {
     ServiceInfo network_info;
     network_info.factory = base::Bind(&NetworkService::CreateNetworkService);
+    network_info.task_runner = ChildProcess::current()->io_task_runner();
     services->insert(
         std::make_pair(content::mojom::kNetworkServiceName, network_info));
   }
diff --git a/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadDevice.java b/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadDevice.java
index f00f558..ca6e57e 100644
--- a/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadDevice.java
+++ b/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadDevice.java
@@ -76,7 +76,7 @@
                 mAxes[i++] = axis;
             }
         }
-        mMappings = GamepadMappings.getMappings(mDeviceName, mAxes);
+        mMappings = GamepadMappings.getMappings(inputDevice, mAxes);
     }
 
     /**
diff --git a/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadMappings.java b/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadMappings.java
index c93f8d9a0..9b2825fa 100644
--- a/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadMappings.java
+++ b/device/gamepad/android/java/src/org/chromium/device/gamepad/GamepadMappings.java
@@ -4,6 +4,9 @@
 
 package org.chromium.device.gamepad;
 
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
@@ -26,7 +29,38 @@
     @VisibleForTesting
     static final String AMAZON_FIRE_DEVICE_NAME = "Amazon Fire Game Controller";
 
-    public static GamepadMappings getMappings(String deviceName, int[] axes) {
+    @VisibleForTesting
+    static final int PS_DUALSHOCK_4_VENDOR_ID = 1356;
+    @VisibleForTesting
+    static final int PS_DUALSHOCK_4_PRODUCT_ID = 1476;
+    @VisibleForTesting
+    static final int PS_DUALSHOCK_4_SLIM_PRODUCT_ID = 2508;
+
+    public static GamepadMappings getMappings(InputDevice device, int[] axes) {
+        GamepadMappings mappings = null;
+        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+            mappings = getMappings(device.getProductId(), device.getVendorId());
+        }
+        if (mappings == null) mappings = getMappings(device.getName());
+        if (mappings == null) mappings = new UnknownGamepadMappings(axes);
+        return mappings;
+    }
+
+    @TargetApi(Build.VERSION_CODES.KITKAT)
+    @VisibleForTesting
+    static GamepadMappings getMappings(int productId, int vendorId) {
+        // Device name of a PS4 gamepad is "Wireless Controller". This is not reliably unique
+        // so we better go by the product and vendor ids.
+        if (vendorId == PS_DUALSHOCK_4_VENDOR_ID
+                && (productId == PS_DUALSHOCK_4_PRODUCT_ID
+                           || productId == PS_DUALSHOCK_4_SLIM_PRODUCT_ID)) {
+            return new PS4GamepadMappings();
+        }
+        return null;
+    }
+
+    @VisibleForTesting
+    static GamepadMappings getMappings(String deviceName) {
         if (deviceName.startsWith(NVIDIA_SHIELD_DEVICE_NAME_PREFIX)
                 || deviceName.equals(MICROSOFT_XBOX_PAD_DEVICE_NAME)) {
             return new XboxCompatibleGamepadMappings();
@@ -37,7 +71,11 @@
         } else if (deviceName.equals(AMAZON_FIRE_DEVICE_NAME)) {
             return new AmazonFireGamepadMappings();
         }
+        return null;
+    }
 
+    @VisibleForTesting
+    static GamepadMappings getUnknownGamepadMappings(int[] axes) {
         return new UnknownGamepadMappings(axes);
     }
 
@@ -244,6 +282,46 @@
         }
     }
 
+    static class PS4GamepadMappings extends GamepadMappings {
+        // Scale input from [-1, 1] to [0, 1] uniformly.
+        private static float scaleRxRy(float input) {
+            return 1.f - ((1.f - input) / 2.f);
+        }
+
+        /**
+         * Method for mapping PS4 gamepad axis and button values
+         * to standard gamepad button and axes values.
+         */
+        @Override
+        public void mapToStandardGamepad(
+                float[] mappedAxes, float[] mappedButtons, float[] rawAxes, float[] rawButtons) {
+            float a = rawButtons[KeyEvent.KEYCODE_BUTTON_A];
+            float b = rawButtons[KeyEvent.KEYCODE_BUTTON_B];
+            float c = rawButtons[KeyEvent.KEYCODE_BUTTON_C];
+            float x = rawButtons[KeyEvent.KEYCODE_BUTTON_X];
+            mappedButtons[CanonicalButtonIndex.PRIMARY] = b;
+            mappedButtons[CanonicalButtonIndex.SECONDARY] = c;
+            mappedButtons[CanonicalButtonIndex.TERTIARY] = a;
+            mappedButtons[CanonicalButtonIndex.QUATERNARY] = x;
+
+            float y = rawButtons[KeyEvent.KEYCODE_BUTTON_Y];
+            float z = rawButtons[KeyEvent.KEYCODE_BUTTON_Z];
+            mappedButtons[CanonicalButtonIndex.LEFT_SHOULDER] = y;
+            mappedButtons[CanonicalButtonIndex.RIGHT_SHOULDER] = z;
+
+            float rx = rawAxes[MotionEvent.AXIS_RX];
+            float ry = rawAxes[MotionEvent.AXIS_RY];
+            mappedButtons[CanonicalButtonIndex.LEFT_TRIGGER] = scaleRxRy(rx);
+            mappedButtons[CanonicalButtonIndex.RIGHT_TRIGGER] = scaleRxRy(ry);
+
+            mapHatAxisToDpadButtons(mappedButtons, rawAxes);
+            mapCommonStartSelectMetaButtons(mappedButtons, rawButtons);
+
+            mapXYAxes(mappedAxes, rawAxes);
+            mapZAndRZAxesToRightStick(mappedAxes, rawAxes);
+        }
+    }
+
     private static class SamsungEIGP20GamepadMappings extends GamepadMappings {
 
         /**
diff --git a/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java b/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java
index 6ed2941..fbbc33a 100644
--- a/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java
+++ b/device/gamepad/android/junit/src/org/chromium/device/gamepad/GamepadMappingsTest.java
@@ -62,8 +62,8 @@
     @Test
     @Feature({"Gamepad"})
     public void testShieldGamepadMappings() throws Exception {
-        GamepadMappings mappings = GamepadMappings.getMappings(
-                GamepadMappings.NVIDIA_SHIELD_DEVICE_NAME_PREFIX, null);
+        GamepadMappings mappings =
+                GamepadMappings.getMappings(GamepadMappings.NVIDIA_SHIELD_DEVICE_NAME_PREFIX);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertShieldGamepadMappings();
@@ -72,8 +72,8 @@
     @Test
     @Feature({"Gamepad"})
     public void testXBox360GamepadMappings() throws Exception {
-        GamepadMappings mappings = GamepadMappings.getMappings(
-                GamepadMappings.MICROSOFT_XBOX_PAD_DEVICE_NAME, null);
+        GamepadMappings mappings =
+                GamepadMappings.getMappings(GamepadMappings.MICROSOFT_XBOX_PAD_DEVICE_NAME);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertShieldGamepadMappings();
@@ -82,8 +82,8 @@
     @Test
     @Feature({"Gamepad"})
     public void testPS3SixAxisGamepadMappings() throws Exception {
-        GamepadMappings mappings = GamepadMappings.getMappings(
-                GamepadMappings.PS3_SIXAXIS_DEVICE_NAME, null);
+        GamepadMappings mappings =
+                GamepadMappings.getMappings(GamepadMappings.PS3_SIXAXIS_DEVICE_NAME);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.PRIMARY],
@@ -109,8 +109,8 @@
     @Test
     @Feature({"Gamepad"})
     public void testSamsungEIGP20GamepadMappings() throws Exception {
-        GamepadMappings mappings = GamepadMappings.getMappings(
-                GamepadMappings.SAMSUNG_EI_GP20_DEVICE_NAME, null);
+        GamepadMappings mappings =
+                GamepadMappings.getMappings(GamepadMappings.SAMSUNG_EI_GP20_DEVICE_NAME);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertMappedCommonXYABButtons();
@@ -128,8 +128,8 @@
     @Test
     @Feature({"Gamepad"})
     public void testAmazonFireGamepadMappings() throws Exception {
-        GamepadMappings mappings = GamepadMappings.getMappings(
-                GamepadMappings.AMAZON_FIRE_DEVICE_NAME, null);
+        GamepadMappings mappings =
+                GamepadMappings.getMappings(GamepadMappings.AMAZON_FIRE_DEVICE_NAME);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertMappedCommonXYABButtons();
@@ -158,7 +158,7 @@
             MotionEvent.AXIS_HAT_Y
         };
 
-        GamepadMappings mappings = GamepadMappings.getMappings("", axes);
+        GamepadMappings mappings = GamepadMappings.getUnknownGamepadMappings(axes);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertMappedCommonXYABButtons();
@@ -187,7 +187,7 @@
             MotionEvent.AXIS_HAT_Y
         };
 
-        GamepadMappings mappings = GamepadMappings.getMappings("", axes);
+        GamepadMappings mappings = GamepadMappings.getUnknownGamepadMappings(axes);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertMappedCommonXYABButtons();
@@ -216,7 +216,7 @@
             MotionEvent.AXIS_HAT_Y
         };
 
-        GamepadMappings mappings = GamepadMappings.getMappings("", axes);
+        GamepadMappings mappings = GamepadMappings.getUnknownGamepadMappings(axes);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertMappedCommonXYABButtons();
@@ -241,7 +241,7 @@
             MotionEvent.AXIS_RZ
         };
 
-        GamepadMappings mappings = GamepadMappings.getMappings("", axes);
+        GamepadMappings mappings = GamepadMappings.getUnknownGamepadMappings(axes);
         mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
 
         assertMappedCommonXYABButtons();
@@ -256,6 +256,42 @@
         assertMapping();
     }
 
+    @Test
+    @Feature({"Gamepad"})
+    public void testPS4GamepadMappings() throws Exception {
+        GamepadMappings mappings =
+                GamepadMappings.getMappings(GamepadMappings.PS_DUALSHOCK_4_PRODUCT_ID,
+                        GamepadMappings.PS_DUALSHOCK_4_VENDOR_ID);
+        mappings.mapToStandardGamepad(mMappedAxes, mMappedButtons, mRawAxes, mRawButtons);
+
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.PRIMARY],
+                mRawButtons[KeyEvent.KEYCODE_BUTTON_B], ERROR_TOLERANCE);
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.SECONDARY],
+                mRawButtons[KeyEvent.KEYCODE_BUTTON_C], ERROR_TOLERANCE);
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.TERTIARY],
+                mRawButtons[KeyEvent.KEYCODE_BUTTON_A], ERROR_TOLERANCE);
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.QUATERNARY],
+                mRawButtons[KeyEvent.KEYCODE_BUTTON_X], ERROR_TOLERANCE);
+
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.LEFT_SHOULDER],
+                mRawButtons[KeyEvent.KEYCODE_BUTTON_Z], ERROR_TOLERANCE);
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.RIGHT_SHOULDER],
+                mRawButtons[KeyEvent.KEYCODE_BUTTON_Y], ERROR_TOLERANCE);
+
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.LEFT_TRIGGER],
+                mRawAxes[MotionEvent.AXIS_RX], ERROR_TOLERANCE);
+        Assert.assertEquals(mMappedButtons[CanonicalButtonIndex.RIGHT_TRIGGER],
+                mRawAxes[MotionEvent.AXIS_RY], ERROR_TOLERANCE);
+
+        assertMappedCommonStartSelectMetaButtons();
+        assertMappedXYAxes();
+        assertMappedHatAxisToDpadButtons();
+        assertMappedZAndRZAxesToRightStick();
+
+        expectNoThumbstickButtons();
+        assertMapping();
+    }
+
     /**
      * Asserts that the current gamepad mapping being tested matches the shield mappings.
      */
@@ -281,6 +317,11 @@
         mUnmappedButtons.set(CanonicalButtonIndex.META);
     }
 
+    public void expectNoThumbstickButtons() {
+        mUnmappedButtons.set(CanonicalButtonIndex.LEFT_THUMBSTICK);
+        mUnmappedButtons.set(CanonicalButtonIndex.RIGHT_THUMBSTICK);
+    }
+
     public void assertMapping() {
         for (int i = 0; i < mMappedAxes.length; i++) {
             if (mUnmappedAxes.get(i)) {
diff --git a/gpu/ipc/in_process_command_buffer.cc b/gpu/ipc/in_process_command_buffer.cc
index 0b2a86d..833b985a 100644
--- a/gpu/ipc/in_process_command_buffer.cc
+++ b/gpu/ipc/in_process_command_buffer.cc
@@ -884,8 +884,8 @@
   mailbox_manager->PullTextureUpdates(sync_token);
   waiting_for_sync_point_ = false;
   executor_->SetScheduled(true);
-  QueueTask(false, base::Bind(&InProcessCommandBuffer::FlushOnGpuThread,
-                              gpu_thread_weak_ptr_, last_put_offset_));
+  service_->ScheduleTask(base::Bind(
+      &InProcessCommandBuffer::ProcessTasksOnGpuThread, gpu_thread_weak_ptr_));
 }
 
 void InProcessCommandBuffer::DescheduleUntilFinishedOnGpuThread() {
diff --git a/ios/chrome/browser/native_app_launcher/BUILD.gn b/ios/chrome/browser/native_app_launcher/BUILD.gn
index 813ad6d..76ecaa68 100644
--- a/ios/chrome/browser/native_app_launcher/BUILD.gn
+++ b/ios/chrome/browser/native_app_launcher/BUILD.gn
@@ -68,6 +68,7 @@
     "//ios/chrome/browser/net",
     "//ios/chrome/browser/store_kit",
     "//ios/chrome/browser/tabs",
+    "//ios/chrome/browser/web:web",
     "//ios/public/provider/chrome/browser",
     "//ios/public/provider/chrome/browser/native_app_launcher",
     "//ios/public/provider/chrome/browser/signin",
diff --git a/ios/chrome/browser/native_app_launcher/native_app_navigation_util.h b/ios/chrome/browser/native_app_launcher/native_app_navigation_util.h
index fd44625..36c4fbf 100644
--- a/ios/chrome/browser/native_app_launcher/native_app_navigation_util.h
+++ b/ios/chrome/browser/native_app_launcher/native_app_navigation_util.h
@@ -13,7 +13,8 @@
 
 // Returns whether the current state is arrived at via a "link navigation" in
 // the sense of Native App Launcher, i.e. a navigation caused by an explicit
-// user action in the rectangle of the web content area.
+// user action in the rectangle of the web content area. |web_state| must not
+// be nullptr.
 bool IsLinkNavigation(web::WebState* web_state);
 
 }  // namespace native_app_launcher
diff --git a/ios/chrome/browser/native_app_launcher/native_app_navigation_util.mm b/ios/chrome/browser/native_app_launcher/native_app_navigation_util.mm
index a99d66b..1e2298e 100644
--- a/ios/chrome/browser/native_app_launcher/native_app_navigation_util.mm
+++ b/ios/chrome/browser/native_app_launcher/native_app_navigation_util.mm
@@ -4,9 +4,8 @@
 
 #include "ios/chrome/browser/native_app_launcher/native_app_navigation_util.h"
 
-#include "base/logging.h"
-#include "ios/web/public/navigation_item.h"
-#include "ios/web/public/navigation_manager.h"
+#import "ios/chrome/browser/web/navigation_manager_util.h"
+#import "ios/web/public/navigation_item.h"
 #import "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -16,27 +15,15 @@
 namespace native_app_launcher {
 
 bool IsLinkNavigation(web::WebState* web_state) {
-  web::NavigationManager* navigationManager = web_state->GetNavigationManager();
-  DCHECK(navigationManager);
-  int index = navigationManager->GetLastCommittedItemIndex();
-  // Walks backward on the navigation items list looking for the first item
-  // that is not the result of a redirect. Check if user arrived at that
-  // via link click or a suggestion on the UI.
-  while (index >= 0) {
-    web::NavigationItem* item = navigationManager->GetItemAtIndex(index);
-    DCHECK(item);
-    ui::PageTransition currentTransition = item->GetTransitionType();
-    // Checks non-redirect entries for transitions that are either links or
-    // bookmarks.
-    if ((currentTransition & ui::PAGE_TRANSITION_IS_REDIRECT_MASK) == 0) {
-      return PageTransitionCoreTypeIs(currentTransition,
-                                      ui::PAGE_TRANSITION_LINK) ||
-             PageTransitionCoreTypeIs(currentTransition,
-                                      ui::PAGE_TRANSITION_AUTO_BOOKMARK);
-    }
-    --index;
-  }
-  return false;
+  DCHECK(web_state);
+  web::NavigationItem* item =
+      GetLastCommittedNonRedirectedItem(web_state->GetNavigationManager());
+  if (!item)
+    return false;
+  ui::PageTransition transition = item->GetTransitionType();
+  return PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_LINK) ||
+         PageTransitionCoreTypeIs(transition,
+                                  ui::PAGE_TRANSITION_AUTO_BOOKMARK);
 }
 
 }  // namespace native_app_launcher
diff --git a/ios/chrome/browser/native_app_launcher/native_app_navigation_util_unittest.mm b/ios/chrome/browser/native_app_launcher/native_app_navigation_util_unittest.mm
index d329f0a..b36ae902 100644
--- a/ios/chrome/browser/native_app_launcher/native_app_navigation_util_unittest.mm
+++ b/ios/chrome/browser/native_app_launcher/native_app_navigation_util_unittest.mm
@@ -72,15 +72,15 @@
 // the first non-redirect entry.
 TEST_F(NativeAppNavigationUtilsTest, TestHasLinkClickedWithRedirect) {
   AddItem("http://foo.com/page0", ui::PAGE_TRANSITION_LINK);
-  AddItem("http://bar.com/page1", ui::PAGE_TRANSITION_SERVER_REDIRECT);
-  AddItem("http://zap.com/page2", ui::PAGE_TRANSITION_SERVER_REDIRECT);
+  AddItem("http://bar.com/page1", ui::PAGE_TRANSITION_CLIENT_REDIRECT);
+  AddItem("http://zap.com/page2", ui::PAGE_TRANSITION_CLIENT_REDIRECT);
   EXPECT_TRUE(native_app_launcher::IsLinkNavigation(web_state()));
 }
 
 // The first non-redirect entry is tested. Earlier redirects do not matter.
 TEST_F(NativeAppNavigationUtilsTest, TestTypedUrlWithRedirectEarlier) {
   AddItem("http://foo.com/page0", ui::PAGE_TRANSITION_LINK);
-  AddItem("http://bar.com/page1", ui::PAGE_TRANSITION_SERVER_REDIRECT);
+  AddItem("http://bar.com/page1", ui::PAGE_TRANSITION_CLIENT_REDIRECT);
   AddItem("http://blah.com/page2", ui::PAGE_TRANSITION_TYPED);
   EXPECT_FALSE(native_app_launcher::IsLinkNavigation(web_state()));
 }
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 222276a..d8c0b03 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -563,8 +563,7 @@
 @property(nonatomic, assign, readonly, getter=isToolbarOnScreen)
     BOOL toolbarOnScreen;
 // Whether a new tab animation is occurring.
-@property(nonatomic, assign, readonly, getter=isInNewTabAnimation)
-    BOOL inNewTabAnimation;
+@property(nonatomic, assign, getter=isInNewTabAnimation) BOOL inNewTabAnimation;
 // Whether BVC prefers to hide the status bar. This value is used to determine
 // the response from the |prefersStatusBarHidden| method.
 @property(nonatomic, assign) BOOL hideStatusBar;
@@ -677,7 +676,7 @@
 // Updates the toolbar display based on the current tab.
 - (void)updateToolbar;
 // Updates |dialogPresenter|'s |active| property to account for the BVC's
-// |active| and |visible| properties.
+// |active|, |visible|, and |inNewTabAnimation| properties.
 - (void)updateDialogPresenterActiveState;
 // Dismisses popups and modal dialogs that are displayed above the BVC upon size
 // changes (e.g. rotation, resizing,…) or when the accessibility escape gesture
@@ -1156,6 +1155,13 @@
   return [self headerHeight] - [self currentHeaderOffset] > 0;
 }
 
+- (void)setInNewTabAnimation:(BOOL)inNewTabAnimation {
+  if (_inNewTabAnimation == inNewTabAnimation)
+    return;
+  _inNewTabAnimation = inNewTabAnimation;
+  [self updateDialogPresenterActiveState];
+}
+
 - (BOOL)isInNewTabAnimation {
   return _inNewTabAnimation;
 }
@@ -1577,7 +1583,7 @@
     }
   };
 
-  _inNewTabAnimation = YES;
+  self.inNewTabAnimation = YES;
   if (!inBackground) {
     UIView* animationParentView = _contentArea;
     // Create the new page image, and load with the new tab page snapshot.
@@ -1601,7 +1607,7 @@
         newPage.frame.size.height - newPage.image.size.height, origin,
         _isOffTheRecord, NULL, ^{
           [newPage removeFromSuperview];
-          _inNewTabAnimation = NO;
+          self.inNewTabAnimation = NO;
           // Use the model's currentTab here because it is possible that it can
           // be reset to a new value before the new Tab animation finished (e.g.
           // if another Tab shows a dialog via |dialogPresenter|). However, that
@@ -1640,7 +1646,7 @@
         topCard, [_contentArea frame], IsPortrait(), ^{
           [background removeFromSuperview];
           [topCard removeFromSuperview];
-          _inNewTabAnimation = NO;
+          self.inNewTabAnimation = NO;
           // Resnapshot the top card if it has its own toolbar, as the toolbar
           // will be captured in the new tab animation, but isn't desired for
           // the stack view snapshots.
@@ -1891,7 +1897,7 @@
     [self ensureViewCreated];
 
   DCHECK(_contentArea);
-  if (!_inNewTabAnimation) {
+  if (!self.inNewTabAnimation) {
     // Hide findbar.  |updateToolbar| will restore the findbar later.
     [self hideFindBarWithAnimation:NO];
 
@@ -1964,7 +1970,8 @@
 }
 
 - (void)updateDialogPresenterActiveState {
-  self.dialogPresenter.active = self.active && self.viewVisible;
+  self.dialogPresenter.active =
+      self.active && self.viewVisible && !self.inNewTabAnimation;
 }
 
 - (void)dismissPopups {
@@ -2172,7 +2179,7 @@
 
   [self displayTab:tab isNewSelection:YES];
 
-  if (_expectingForegroundTab && !_inNewTabAnimation) {
+  if (_expectingForegroundTab && !self.inNewTabAnimation) {
     // Now that the new tab has been displayed, return to normal. Rather than
     // keep a reference to the previous tab, just turn off preview mode for all
     // tabs (since doing so is a no-op for the tabs that don't have it set).
@@ -4483,7 +4490,7 @@
 
 - (void)startVoiceSearch {
   // Delay Voice Search until new tab animations have finished.
-  if (_inNewTabAnimation) {
+  if (self.inNewTabAnimation) {
     _startVoiceSearchAfterNewTabAnimation = YES;
     return;
   }
diff --git a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
index 26f1cd2..5e81cc9 100644
--- a/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
+++ b/ios/chrome/browser/ui/dialogs/javascript_dialog_egtest.mm
@@ -7,19 +7,23 @@
 #import <XCTest/XCTest.h>
 
 #import "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/dialogs/dialog_presenter.h"
 #include "ios/chrome/browser/ui/tools_menu/tools_menu_constants.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/test/app/chrome_test_util.h"
+#import "ios/chrome/test/earl_grey/chrome_actions.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
 #import "ios/chrome/test/earl_grey/chrome_matchers.h"
 #import "ios/chrome/test/earl_grey/chrome_test_case.h"
+#import "ios/testing/earl_grey/matchers.h"
 #import "ios/testing/wait_util.h"
 #import "ios/web/public/test/http_server.h"
 #import "ios/web/public/test/http_server_util.h"
+#include "ios/web/public/test/url_test_util.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
@@ -30,6 +34,7 @@
 #endif
 
 using chrome_test_util::NavigationBarDoneButton;
+using web::test::HttpServer;
 
 namespace {
 
@@ -140,11 +145,31 @@
   return nil;
 }
 
-// Const for an http server that returns a blank document.
+// HTTP server constants.
+
+// URL and response for a blank document.
 const char* kJavaScriptTestURL = "http://jsalerts";
 const char* kJavaScriptTestResponse =
     "<!DOCTYPE html><html><body></body></html>";
 
+// URL and response for a page with an onload alert.
+const char* kOnLoadAlertURL = "http://onloadalert";
+const char* kOnLoadAlertResponse =
+    "<!DOCTYPE html><html><body onload=\"alert('alert')\"></body></html>";
+
+// URL and response for a page with a link to |kOnLoadAlertURL|.
+const char* kPageWithLinkURL = "http://pagewithlink";
+const char* kPageWithLinkResponseFormat =
+    "<!DOCTYPE html><html><body><a id=\"%s\" href=\"%s\">%s</a></body></html>";
+const char* kPageWithLinkText = "LINK TO ONLOAD ALERT PAGE";
+const char* kLinkID = "link-id";
+std::string GetPageWithLinkResponse() {
+  return base::SysNSStringToUTF8([NSString
+      stringWithFormat:@(kPageWithLinkResponseFormat), kLinkID,
+                       HttpServer::MakeUrl(kOnLoadAlertURL).spec().c_str(),
+                       kPageWithLinkText]);
+}
+
 // Waits until |string| is displayed on the web view.
 void WaitForWebDisplay(const std::string& string) {
   id<GREYMatcher> response1Matcher =
@@ -176,13 +201,13 @@
     return !error;
   };
   GREYAssert(testing::WaitUntilConditionOrTimeout(
-                 testing::kWaitForJSCompletionTimeout, condition),
+                 testing::kWaitForUIElementTimeout, condition),
              @"Alert with title was not present: %@", alert_label);
 }
 
 void WaitForJavaScripDialogToBeShown() {
   NSString* alert_label = [DialogPresenter
-      localizedTitleForJavaScriptAlertFromPage:web::test::HttpServer::MakeUrl(
+      localizedTitleForJavaScriptAlertFromPage:HttpServer::MakeUrl(
                                                    kJavaScriptTestURL)];
   WaitForAlertToBeShown(alert_label);
 }
@@ -207,7 +232,7 @@
   ConditionBlock condition = ^{
     NSError* error = nil;
     NSString* alertLabel = [DialogPresenter
-        localizedTitleForJavaScriptAlertFromPage:web::test::HttpServer::MakeUrl(
+        localizedTitleForJavaScriptAlertFromPage:HttpServer::MakeUrl(
                                                      kJavaScriptTestURL)];
     id<GREYMatcher> titleLabel =
         chrome_test_util::StaticTextWithAccessibilityLabel(alertLabel);
@@ -254,9 +279,13 @@
 
 }  // namespace
 
-@interface JavaScriptDialogTestCase : ChromeTestCase {
-  GURL _URL;
-}
+@interface JavaScriptDialogTestCase : ChromeTestCase
+
+// Loads the blank test page at kJavaScriptTestURL.
+- (void)loadBlankTestPage;
+
+// Loads a page with a link to kOnLoadAlertURL.
+- (void)loadPageWithLink;
 
 @end
 
@@ -264,17 +293,11 @@
 
 - (void)setUp {
   [super setUp];
-  _URL = web::test::HttpServer::MakeUrl(kJavaScriptTestURL);
   std::map<GURL, std::string> responses;
-  responses[web::test::HttpServer::MakeUrl(kJavaScriptTestURL)] =
-      kJavaScriptTestResponse;
+  responses[HttpServer::MakeUrl(kJavaScriptTestURL)] = kJavaScriptTestResponse;
+  responses[HttpServer::MakeUrl(kPageWithLinkURL)] = GetPageWithLinkResponse();
+  responses[HttpServer::MakeUrl(kOnLoadAlertURL)] = kOnLoadAlertResponse;
   web::test::SetUpSimpleHttpServer(responses);
-
-  [ChromeEarlGrey loadURL:_URL];
-  id<GREYMatcher> response2Matcher =
-      chrome_test_util::WebViewContainingText(std::string());
-  [[EarlGrey selectElementWithMatcher:response2Matcher]
-      assertWithMatcher:grey_notNil()];
 }
 
 - (void)tearDown {
@@ -297,6 +320,18 @@
   [super tearDown];
 }
 
+#pragma mark - Utility
+
+- (void)loadBlankTestPage {
+  [ChromeEarlGrey loadURL:HttpServer::MakeUrl(kJavaScriptTestURL)];
+  WaitForWebDisplay(std::string());
+}
+
+- (void)loadPageWithLink {
+  [ChromeEarlGrey loadURL:HttpServer::MakeUrl(kPageWithLinkURL)];
+  WaitForWebDisplay(kPageWithLinkText);
+}
+
 #pragma mark - Tests
 
 // Tests that an alert is shown, and that the completion block is called.
@@ -308,7 +343,8 @@
                           @"correctly.");
 #endif
 
-  // Show an alert.
+  // Load the blank test page and show an alert.
+  [self loadBlankTestPage];
   ShowJavaScriptDialog(JavaScriptAlertType::ALERT);
 
   // Tap the OK button.
@@ -328,7 +364,8 @@
                           @"correctly.");
 #endif
 
-  // Show a confirmation dialog.
+  // Load the blank test page and show a confirmation dialog.
+  [self loadBlankTestPage];
   ShowJavaScriptDialog(JavaScriptAlertType::CONFIRMATION);
 
   // Tap the OK button.
@@ -348,7 +385,8 @@
                           @"correctly.");
 #endif
 
-  // Show a confirmation dialog.
+  // Load the blank test page and show a confirmation dialog.
+  [self loadBlankTestPage];
   ShowJavaScriptDialog(JavaScriptAlertType::CONFIRMATION);
 
   // Tap the Cancel button.
@@ -368,7 +406,8 @@
                           @"correctly.");
 #endif
 
-  // Show a prompt dialog.
+  // Load the blank test page and show a prompt dialog.
+  [self loadBlankTestPage];
   ShowJavaScriptDialog(JavaScriptAlertType::PROMPT);
 
   // Enter text into text field.
@@ -391,7 +430,8 @@
                           @"correctly.");
 #endif
 
-  // Show a prompt dialog.
+  // Load the blank test page and show a prompt dialog.
+  [self loadBlankTestPage];
   ShowJavaScriptDialog(JavaScriptAlertType::PROMPT);
 
   // Enter text into text field.
@@ -406,7 +446,8 @@
 
 // Tests that JavaScript alerts that are shown in a loop can be suppressed.
 - (void)testShowJavaScriptAlertLoop {
-  // Evaluate JavaScript to show alerts in an endless loop.
+  // Load the blank test page and show alerts in a loop.
+  [self loadBlankTestPage];
   web::WebState* webState = chrome_test_util::GetCurrentWebState();
   NSString* script = GetJavaScriptAlertLoopScript();
   webState->ExecuteJavaScript(base::SysNSStringToUTF16(script));
@@ -442,6 +483,9 @@
                           @"correctly.");
 #endif
 
+  // Load the blank test page.
+  [self loadBlankTestPage];
+
   // Show settings.
   [ChromeEarlGreyUI openToolsMenu];
   [[EarlGrey
@@ -481,6 +525,9 @@
                           @"correctly.");
 #endif
 
+  // Load the blank test page.
+  [self loadBlankTestPage];
+
   [ChromeEarlGreyUI openShareMenu];
 
   // Copy URL, dismissing the share menu.
@@ -499,4 +546,42 @@
   WaitForWebDisplay(kAlertResultBody);
 }
 
+// Tests that an alert is presented after a new tab animation is finished.
+- (void)testShowJavaScriptAfterNewTabAnimation {
+// TODO(crbug.com/663026): Reenable the test for devices.
+#if !TARGET_IPHONE_SIMULATOR
+  EARL_GREY_TEST_DISABLED(@"Disabled for devices because existing system "
+                          @"alerts would prevent app alerts to present "
+                          @"correctly.");
+#endif
+
+  // Load the test page with a link to kOnLoadAlertURL and long tap on the link.
+  [self loadPageWithLink];
+  id<GREYMatcher> webViewMatcher =
+      chrome_test_util::WebViewContainingText(std::string(kPageWithLinkText));
+  [[EarlGrey selectElementWithMatcher:webViewMatcher]
+      performAction:chrome_test_util::LongPressElementForContextMenu(
+                        kLinkID, true /* menu should appear */)];
+
+  // Tap on the "Open In New Tab" button.
+  id<GREYMatcher> newTabMatcher = testing::ContextMenuItemWithText(
+      l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB));
+  [[EarlGrey selectElementWithMatcher:newTabMatcher] performAction:grey_tap()];
+
+  // Wait for the alert to be shown.
+  NSString* alertLabel = [DialogPresenter
+      localizedTitleForJavaScriptAlertFromPage:HttpServer::MakeUrl(
+                                                   kJavaScriptTestURL)];
+  WaitForAlertToBeShown(alertLabel);
+
+  // Verify that the omnibox shows the correct URL when the dialog is visible.
+  GURL onloadURL = HttpServer::MakeUrl(kOnLoadAlertURL);
+  std::string title = base::UTF16ToUTF8(web::GetDisplayTitleForUrl(onloadURL));
+  [[EarlGrey selectElementWithMatcher:chrome_test_util::OmniboxText(title)]
+      assertWithMatcher:grey_notNil()];
+
+  // Close the alert.
+  TapOK();
+}
+
 @end
diff --git a/ipc/ipc_mojo_param_traits.cc b/ipc/ipc_mojo_param_traits.cc
index 189af35..12aaace 100644
--- a/ipc/ipc_mojo_param_traits.cc
+++ b/ipc/ipc_mojo_param_traits.cc
@@ -5,6 +5,7 @@
 #include "ipc/ipc_mojo_param_traits.h"
 
 #include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_mojo_handle_attachment.h"
 #include "ipc/ipc_mojo_message_helper.h"
 
 namespace IPC {
@@ -47,4 +48,62 @@
   l->append(")");
 }
 
+void ParamTraits<mojo::DataPipeConsumerHandle>::GetSize(
+    base::PickleSizer* sizer,
+    const param_type& p) {
+  GetParamSize(sizer, p.is_valid());
+  if (p.is_valid())
+    sizer->AddAttachment();
+}
+
+void ParamTraits<mojo::DataPipeConsumerHandle>::Write(base::Pickle* m,
+                                                      const param_type& p) {
+  WriteParam(m, p.is_valid());
+  if (!p.is_valid())
+    return;
+
+  m->WriteAttachment(new internal::MojoHandleAttachment(
+      mojo::ScopedHandle::From(mojo::ScopedDataPipeConsumerHandle(p))));
+}
+
+bool ParamTraits<mojo::DataPipeConsumerHandle>::Read(const base::Pickle* m,
+                                                     base::PickleIterator* iter,
+                                                     param_type* r) {
+  bool is_valid;
+  if (!ReadParam(m, iter, &is_valid))
+    return false;
+  if (!is_valid)
+    return true;
+
+  scoped_refptr<base::Pickle::Attachment> attachment;
+  if (!m->ReadAttachment(iter, &attachment)) {
+    DLOG(ERROR) << "Failed to read attachment for message pipe.";
+    return false;
+  }
+
+  MessageAttachment::Type type =
+      static_cast<MessageAttachment*>(attachment.get())->GetType();
+  if (type != MessageAttachment::Type::MOJO_HANDLE) {
+    DLOG(ERROR) << "Unexpected attachment type:" << type;
+    return false;
+  }
+
+  mojo::ScopedDataPipeConsumerHandle handle;
+  handle.reset(mojo::DataPipeConsumerHandle(
+      static_cast<internal::MojoHandleAttachment*>(attachment.get())
+          ->TakeHandle()
+          .release()
+          .value()));
+  DCHECK(handle.is_valid());
+  *r = handle.release();
+  return true;
+}
+
+void ParamTraits<mojo::DataPipeConsumerHandle>::Log(const param_type& p,
+                                                    std::string* l) {
+  l->append("mojo::DataPipeConsumerHandle(");
+  LogParam(p.value(), l);
+  l->append(")");
+}
+
 }  // namespace IPC
diff --git a/ipc/ipc_mojo_param_traits.h b/ipc/ipc_mojo_param_traits.h
index 39be43e..a4d0228c 100644
--- a/ipc/ipc_mojo_param_traits.h
+++ b/ipc/ipc_mojo_param_traits.h
@@ -9,6 +9,7 @@
 
 #include "ipc/ipc_export.h"
 #include "ipc/ipc_param_traits.h"
+#include "mojo/public/cpp/system/data_pipe.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 
 namespace base {
@@ -29,6 +30,17 @@
   static void Log(const param_type& p, std::string* l);
 };
 
+template <>
+struct IPC_EXPORT ParamTraits<mojo::DataPipeConsumerHandle> {
+  typedef mojo::DataPipeConsumerHandle param_type;
+  static void GetSize(base::PickleSizer* sizer, const param_type& p);
+  static void Write(base::Pickle* m, const param_type& p);
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* r);
+  static void Log(const param_type& p, std::string* l);
+};
+
 }  // namespace IPC
 
 #endif  // IPC_IPC_MOJO_PARAM_TRAITS_H_
diff --git a/mash/catalog_viewer/catalog_viewer.cc b/mash/catalog_viewer/catalog_viewer.cc
index aab46a79..2b817c59 100644
--- a/mash/catalog_viewer/catalog_viewer.cc
+++ b/mash/catalog_viewer/catalog_viewer.cc
@@ -15,7 +15,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/catalog/public/interfaces/catalog.mojom.h"
 #include "services/catalog/public/interfaces/constants.mojom.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
diff --git a/mash/example/views_examples/views_examples.cc b/mash/example/views_examples/views_examples.cc
index cb6e3d3e..8e0c2fe1 100644
--- a/mash/example/views_examples/views_examples.cc
+++ b/mash/example/views_examples/views_examples.cc
@@ -11,7 +11,6 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
diff --git a/mash/example/window_type_launcher/window_type_launcher.cc b/mash/example/window_type_launcher/window_type_launcher.cc
index 46c07923..a33422e 100644
--- a/mash/example/window_type_launcher/window_type_launcher.cc
+++ b/mash/example/window_type_launcher/window_type_launcher.cc
@@ -13,7 +13,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/platform_thread.h"
 #include "services/service_manager/public/c/main.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
diff --git a/mash/session/session.cc b/mash/session/session.cc
index d00e7ec..d02dabb 100644
--- a/mash/session/session.cc
+++ b/mash/session/session.cc
@@ -24,19 +24,20 @@
   StartQuickLaunch();
 
   // Launch a chrome window for dev convience; don't do this in the long term.
-  context()->connector()->Connect(content::mojom::kPackagedServicesServiceName);
+  context()->connector()->StartService(
+      content::mojom::kPackagedServicesServiceName);
 }
 
 void Session::StartWindowManager() {
   // TODO(beng): monitor this service for death & bring down the whole system
   // if necessary.
-  context()->connector()->Connect(common::GetWindowManagerServiceName());
+  context()->connector()->StartService(common::GetWindowManagerServiceName());
 }
 
 void Session::StartQuickLaunch() {
   // TODO(beng): monitor this service for death & bring down the whole system
   // if necessary.
-  context()->connector()->Connect(quick_launch::mojom::kServiceName);
+  context()->connector()->StartService(quick_launch::mojom::kServiceName);
 }
 
 }  // namespace session
diff --git a/mash/task_viewer/task_viewer.cc b/mash/task_viewer/task_viewer.cc
index c7b8cf1..98204fa 100644
--- a/mash/task_viewer/task_viewer.cc
+++ b/mash/task_viewer/task_viewer.cc
@@ -17,7 +17,6 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/catalog/public/interfaces/catalog.mojom.h"
 #include "services/catalog/public/interfaces/constants.mojom.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
diff --git a/media/media_options.gni b/media/media_options.gni
index 00709d3..d07f093 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -54,7 +54,7 @@
   # which are encoded using HEVC require |enable_hevc_demuxing| to be enabled.
   enable_dolby_vision_demuxing = proprietary_codecs && is_chromecast
 
-  enable_webrtc = !is_ios && !is_cast_audio_only
+  enable_webrtc = !is_cast_audio_only
 
   # Enable HLS with SAMPLE-AES decryption.
   # Enabled by default on the cast desktop implementation to allow unit tests of
diff --git a/media/mojo/interfaces/hdr_metadata_struct_traits.h b/media/mojo/interfaces/hdr_metadata_struct_traits.h
index 498f830..6ca3810e 100644
--- a/media/mojo/interfaces/hdr_metadata_struct_traits.h
+++ b/media/mojo/interfaces/hdr_metadata_struct_traits.h
@@ -36,6 +36,14 @@
                    media::MasteringMetadata* output) {
     output->luminance_max = data.luminance_max();
     output->luminance_min = data.luminance_min();
+    if (!data.ReadPrimaryR(&output->primary_r))
+      return false;
+    if (!data.ReadPrimaryG(&output->primary_g))
+      return false;
+    if (!data.ReadPrimaryB(&output->primary_b))
+      return false;
+    if (!data.ReadWhitePoint(&output->white_point))
+      return false;
     return true;
   }
 };
@@ -59,6 +67,8 @@
     output->max_content_light_level = data.max_content_light_level();
     output->max_frame_average_light_level =
         data.max_frame_average_light_level();
+    if (!data.ReadMasteringMetadata(&output->mastering_metadata))
+      return false;
     return true;
   }
 };
diff --git a/media/mojo/services/media_service.cc b/media/mojo/services/media_service.cc
index 242040e..e1b5145 100644
--- a/media/mojo/services/media_service.cc
+++ b/media/mojo/services/media_service.cc
@@ -11,7 +11,6 @@
 #include "media/mojo/services/interface_factory_impl.h"
 #include "media/mojo/services/mojo_media_client.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 namespace media {
diff --git a/media/mojo/services/media_service_unittest.cc b/media/mojo/services/media_service_unittest.cc
index bdc2cd7..c7e611c 100644
--- a/media/mojo/services/media_service_unittest.cc
+++ b/media/mojo/services/media_service_unittest.cc
@@ -77,9 +77,8 @@
   void SetUp() override {
     ServiceTest::SetUp();
 
-    connection_ = connector()->Connect("media");
     media::mojom::MediaServicePtr media_service;
-    connection_->GetInterface(&media_service);
+    connector()->BindInterface("media", &media_service);
 
     auto registry =
         base::MakeUnique<service_manager::InterfaceRegistry>(std::string());
@@ -148,7 +147,6 @@
   MOCK_METHOD0(ConnectionClosed, void());
 
  protected:
-  std::unique_ptr<service_manager::Connection> connection_;
   std::unique_ptr<base::RunLoop> run_loop_;
 
   mojom::InterfaceFactoryPtr interface_factory_;
@@ -202,7 +200,12 @@
 #endif  // defined(ENABLE_MOJO_RENDERER)
 
 TEST_F(MediaServiceTest, Lifetime) {
-  connection_->SetConnectionLostClosure(
+  // The lifetime of the media service is controlled by the number of
+  // live InterfaceFactory impls, not MediaService impls, so this pipe should
+  // be closed when the last InterfaceFactory is destroyed.
+  media::mojom::MediaServicePtr media_service;
+  connector()->BindInterface("media", &media_service);
+  media_service.set_connection_error_handler(
       base::Bind(&MediaServiceTest::ConnectionClosed, base::Unretained(this)));
 
   // Disconnecting CDM and Renderer services doesn't terminate the app.
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 1398543..6fa8f24 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -390,6 +390,20 @@
 // visible, because the normal Read() method is used as a fallback.
 NET_ERROR(READ_IF_READY_NOT_IMPLEMENTED, -174)
 
+// This error is emitted if TLS 1.3 is enabled, connecting with it failed, but
+// retrying at a downgraded maximum version succeeded. This could mean:
+//
+// 1. This is a transient network error that will be resolved when the user
+//    reloads.
+//
+// 2. The user is behind a buggy network middlebox, firewall, or proxy which is
+//    interfering with TLS 1.3.
+//
+// 3. The server is buggy and does not implement TLS version negotiation
+//    correctly. TLS 1.3 was tweaked to avoid a common server bug here, so this
+//    is unlikely.
+NET_ERROR(SSL_VERSION_INTERFERENCE, -175)
+
 // Certificate error codes
 //
 // The values of certificate error codes must be consecutive.
diff --git a/net/http/http_basic_stream.cc b/net/http/http_basic_stream.cc
index 312b927..3a85a6df 100644
--- a/net/http/http_basic_stream.cc
+++ b/net/http/http_basic_stream.cc
@@ -99,6 +99,11 @@
                                                 load_timing_info);
 }
 
+bool HttpBasicStream::GetAlternativeService(
+    AlternativeService* alternative_service) const {
+  return false;
+}
+
 void HttpBasicStream::GetSSLInfo(SSLInfo* ssl_info) {
   parser()->GetSSLInfo(ssl_info);
 }
diff --git a/net/http/http_basic_stream.h b/net/http/http_basic_stream.h
index 4f595c92f..cf0d65d2 100644
--- a/net/http/http_basic_stream.h
+++ b/net/http/http_basic_stream.h
@@ -72,6 +72,9 @@
 
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
 
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override;
+
   void GetSSLInfo(SSLInfo* ssl_info) override;
 
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 363ae401..e95ab37 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -14970,6 +14970,12 @@
     return false;
   }
 
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override {
+    ADD_FAILURE();
+    return false;
+  }
+
   void GetSSLInfo(SSLInfo* ssl_info) override { ADD_FAILURE(); }
 
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {
@@ -15216,6 +15222,12 @@
     return false;
   }
 
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override {
+    ADD_FAILURE();
+    return false;
+  }
+
   void GetSSLInfo(SSLInfo* ssl_info) override {}
 
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {
diff --git a/net/http/http_response_body_drainer_unittest.cc b/net/http/http_response_body_drainer_unittest.cc
index 6b725da..44943e29 100644
--- a/net/http/http_response_body_drainer_unittest.cc
+++ b/net/http/http_response_body_drainer_unittest.cc
@@ -108,6 +108,10 @@
   bool CanReuseConnection() const override { return can_reuse_connection_; }
   int64_t GetTotalReceivedBytes() const override { return 0; }
   int64_t GetTotalSentBytes() const override { return 0; }
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override {
+    return false;
+  }
   void GetSSLInfo(SSLInfo* ssl_info) override {}
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
   bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
diff --git a/net/http/http_stream.h b/net/http/http_stream.h
index 3def66ee..78458e4 100644
--- a/net/http/http_stream.h
+++ b/net/http/http_stream.h
@@ -30,6 +30,7 @@
 
 namespace net {
 
+struct AlternativeService;
 class HttpNetworkSession;
 class HttpRequestHeaders;
 struct HttpRequestInfo;
@@ -150,6 +151,11 @@
   // undefined.
   virtual void GetSSLInfo(SSLInfo* ssl_info) = 0;
 
+  // Returns true and populates |alternative_service| if an alternative service
+  // was used to for this stream. Otherwise returns false.
+  virtual bool GetAlternativeService(
+      AlternativeService* alternative_service) const = 0;
+
   // Get the SSLCertRequestInfo associated with this stream's connection.
   // This should only be called for streams over SSL sockets, otherwise the
   // behavior is undefined.
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index cdb3109..9c38e69 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -103,7 +103,8 @@
                                              bool for_websockets)
     : session_(session),
       job_factory_(new DefaultJobFactory()),
-      for_websockets_(for_websockets) {}
+      for_websockets_(for_websockets),
+      last_logged_job_controller_count_(0) {}
 
 HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
   DCHECK(spdy_session_request_map_.empty());
@@ -356,11 +357,15 @@
       scheme_host_port);
 }
 
-void HttpStreamFactoryImpl::AddJobControllerCountToHistograms() const {
+void HttpStreamFactoryImpl::AddJobControllerCountToHistograms() {
   // Only log the count of JobControllers when the count is hitting one of the
-  // boundaries which is a multiple of 100: 100, 200, 300, etc.
-  if (job_controller_set_.size() < 100 || job_controller_set_.size() % 100 != 0)
+  // boundaries for the first time which is a multiple of 100: 100, 200, 300,
+  // etc.
+  if (job_controller_set_.size() % 100 != 0 ||
+      job_controller_set_.size() <= last_logged_job_controller_count_) {
     return;
+  }
+  last_logged_job_controller_count_ = job_controller_set_.size();
 
   UMA_HISTOGRAM_COUNTS_1M("Net.JobControllerSet.CountOfJobController",
                           job_controller_set_.size());
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 503764c4..53f4536 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -174,7 +174,7 @@
   // Adds the count of JobControllers that are not completed to UMA histogram if
   // the count is a multiple of 100: 100, 200, 400, etc. Break down
   // JobControllers count based on the type of JobController.
-  void AddJobControllerCountToHistograms() const;
+  void AddJobControllerCountToHistograms();
 
   HttpNetworkSession* const session_;
 
@@ -196,6 +196,9 @@
 
   const bool for_websockets_;
 
+  // The count of JobControllers that was most recently logged to histograms.
+  size_t last_logged_job_controller_count_;
+
   DISALLOW_COPY_AND_ASSIGN(HttpStreamFactoryImpl);
 };
 
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 2ac222b..833c429 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -127,6 +127,10 @@
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override {
     return false;
   }
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override {
+    return false;
+  }
   void GetSSLInfo(SSLInfo* ssl_info) override {}
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
   bool GetRemoteEndpoint(IPEndPoint* endpoint) override { return false; }
diff --git a/net/http/proxy_connect_redirect_http_stream.cc b/net/http/proxy_connect_redirect_http_stream.cc
index 5b8a2bc..a493f33 100644
--- a/net/http/proxy_connect_redirect_http_stream.cc
+++ b/net/http/proxy_connect_redirect_http_stream.cc
@@ -79,6 +79,11 @@
   return 0;
 }
 
+bool ProxyConnectRedirectHttpStream::GetAlternativeService(
+    AlternativeService* alternative_service) const {
+  return false;
+}
+
 bool ProxyConnectRedirectHttpStream::GetLoadTimingInfo(
     LoadTimingInfo* load_timing_info) const {
   if (!has_load_timing_info_)
diff --git a/net/http/proxy_connect_redirect_http_stream.h b/net/http/proxy_connect_redirect_http_stream.h
index 74d9136..c66aa21 100644
--- a/net/http/proxy_connect_redirect_http_stream.h
+++ b/net/http/proxy_connect_redirect_http_stream.h
@@ -51,6 +51,8 @@
 
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override;
 
   // This function may be called.
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index bbd14afb..53c84f4 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -563,6 +563,15 @@
 //   }
 EVENT_TYPE(SSL_CIPHER_FALLBACK)
 
+// An SSL connection needs to be retried with a lower protocol version to detect
+// if the error was due to a middlebox interfering with the protocol version we
+// offered.
+// The following parameters are attached to the event:
+//   {
+//     "net_error": <Net integer error code which triggered the probe>,
+//   }
+EVENT_TYPE(SSL_VERSION_INTERFERENCE_PROBE)
+
 // We found that our prediction of the server's certificates was correct and
 // we merged the verification with the SSLHostInfo. (Note: now obsolete.)
 EVENT_TYPE(SSL_VERIFICATION_MERGED)
diff --git a/net/quic/chromium/quic_http_stream.cc b/net/quic/chromium/quic_http_stream.cc
index f52e00e..78f4bac7 100644
--- a/net/quic/chromium/quic_http_stream.cc
+++ b/net/quic/chromium/quic_http_stream.cc
@@ -423,6 +423,14 @@
   return true;
 }
 
+bool QuicHttpStream::GetAlternativeService(
+    AlternativeService* alternative_service) const {
+  alternative_service->protocol = kProtoQUIC;
+  alternative_service->host = server_id_.host();
+  alternative_service->port = server_id_.port();
+  return true;
+}
+
 void QuicHttpStream::PopulateNetErrorDetails(NetErrorDetails* details) {
   details->connection_info = ConnectionInfoFromQuicVersion(quic_version_);
   if (was_handshake_confirmed_)
diff --git a/net/quic/chromium/quic_http_stream.h b/net/quic/chromium/quic_http_stream.h
index 01d83955..262aeed0 100644
--- a/net/quic/chromium/quic_http_stream.h
+++ b/net/quic/chromium/quic_http_stream.h
@@ -64,6 +64,8 @@
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override;
   void PopulateNetErrorDetails(NetErrorDetails* details) override;
   void SetPriority(RequestPriority priority) override;
 
diff --git a/net/quic/chromium/quic_http_stream_test.cc b/net/quic/chromium/quic_http_stream_test.cc
index 1930a1b..28d88c9a 100644
--- a/net/quic/chromium/quic_http_stream_test.cc
+++ b/net/quic/chromium/quic_http_stream_test.cc
@@ -73,7 +73,7 @@
 
 const char kUploadData[] = "Really nifty data!";
 const char kDefaultServerHostName[] = "www.example.org";
-const uint16_t kDefaultServerPort = 80;
+const uint16_t kDefaultServerPort = 443;
 
 class TestQuicConnection : public QuicConnection {
  public:
@@ -362,7 +362,7 @@
   void SetRequest(const string& method,
                   const string& path,
                   RequestPriority priority) {
-    request_headers_ = client_maker_.GetRequestHeaders(method, "http", path);
+    request_headers_ = client_maker_.GetRequestHeaders(method, "https", path);
   }
 
   void SetResponse(const string& status, const string& body) {
@@ -646,7 +646,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   // Make sure getting load timing from the stream early does not crash.
   LoadTimingInfo load_timing_info;
@@ -716,7 +716,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   // Start first request.
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -795,7 +795,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -889,7 +889,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -939,7 +939,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -961,7 +961,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -980,6 +980,31 @@
   EXPECT_TRUE(ssl_info2.is_valid());
 }
 
+TEST_P(QuicHttpStreamTest, GetAlternativeService) {
+  SetRequest("GET", "/", DEFAULT_PRIORITY);
+  Initialize();
+
+  request_.method = "GET";
+  request_.url = GURL("https://www.example.org/");
+
+  EXPECT_EQ(OK,
+            stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
+                                      net_log_.bound(), callback_.callback()));
+
+  AlternativeService alternative_service;
+  EXPECT_TRUE(stream_->GetAlternativeService(&alternative_service));
+  EXPECT_EQ(AlternativeService(kProtoQUIC, "www.example.org", 443),
+            alternative_service);
+
+  session_->connection()->CloseConnection(
+      QUIC_NO_ERROR, "test", ConnectionCloseBehavior::SILENT_CLOSE);
+
+  AlternativeService alternative_service2;
+  EXPECT_TRUE(stream_->GetAlternativeService(&alternative_service2));
+  EXPECT_EQ(AlternativeService(kProtoQUIC, "www.example.org", 443),
+            alternative_service2);
+}
+
 TEST_P(QuicHttpStreamTest, LogGranularQuicConnectionError) {
   SetRequest("GET", "/", DEFAULT_PRIORITY);
   size_t spdy_request_headers_frame_length;
@@ -995,7 +1020,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1035,7 +1060,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1078,7 +1103,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1119,7 +1144,7 @@
       kUploadData, strlen(kUploadData)));
   ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_THAT(request_.upload_data_stream->Init(CompletionCallback(),
                                                 NetLogWithSource()),
@@ -1191,7 +1216,7 @@
   upload_data_stream.AppendData(kUploadData, chunk_size, false);
 
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -1266,7 +1291,7 @@
   upload_data_stream.AppendData(kUploadData, chunk_size, false);
 
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -1335,7 +1360,7 @@
   ChunkedUploadDataStream upload_data_stream(0);
 
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -1402,7 +1427,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1447,7 +1472,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
                                           callback_.callback()));
@@ -1500,7 +1525,7 @@
   Initialize();
 
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK, stream_->InitializeStream(&request_, MEDIUM, net_log_.bound(),
                                           callback_.callback()));
@@ -1543,7 +1568,7 @@
   ChunkedUploadDataStream upload_data_stream(0);
 
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -1575,7 +1600,7 @@
   ChunkedUploadDataStream upload_data_stream(0);
 
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -1605,7 +1630,7 @@
   upload_data_stream.AppendData(kUploadData, chunk_size, false);
 
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -1623,7 +1648,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1689,7 +1714,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1763,7 +1788,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1805,7 +1830,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1877,7 +1902,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1902,7 +1927,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -1997,7 +2022,7 @@
 
   // Initialize the first stream, for receiving the promise on.
   request_.method = "GET";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
 
   EXPECT_EQ(OK,
             stream_->InitializeStream(&request_, DEFAULT_PRIORITY,
@@ -2112,7 +2137,7 @@
   ReadErrorUploadDataStream upload_data_stream(
       ReadErrorUploadDataStream::FailureMode::SYNC);
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
@@ -2149,7 +2174,7 @@
   ReadErrorUploadDataStream upload_data_stream(
       ReadErrorUploadDataStream::FailureMode::ASYNC);
   request_.method = "POST";
-  request_.url = GURL("http://www.example.org/");
+  request_.url = GURL("https://www.example.org/");
   request_.upload_data_stream = &upload_data_stream;
   ASSERT_EQ(OK, request_.upload_data_stream->Init(
                     TestCompletionCallback().callback(), NetLogWithSource()));
diff --git a/net/socket/ssl_client_socket_impl.cc b/net/socket/ssl_client_socket_impl.cc
index 085ef63..ab4f113 100644
--- a/net/socket/ssl_client_socket_impl.cc
+++ b/net/socket/ssl_client_socket_impl.cc
@@ -1066,6 +1066,11 @@
   if (result < 0)
     return result;
 
+  if (ssl_config_.version_interference_probe) {
+    DCHECK_LT(ssl_config_.version_max, TLS1_3_VERSION);
+    return ERR_SSL_VERSION_INTERFERENCE;
+  }
+
   SSLContext::GetInstance()->session_cache()->ResetLookupCount(
       GetSessionCacheKey());
   // Check that if token binding was negotiated, then extended master secret
@@ -1694,17 +1699,13 @@
 
 std::string SSLClientSocketImpl::GetSessionCacheKey() const {
   std::string result = host_and_port_.ToString();
-  result.append("/");
+  result.push_back('/');
   result.append(ssl_session_cache_shard_);
 
-  result.append("/");
-  if (ssl_config_.deprecated_cipher_suites_enabled)
-    result.append("deprecated");
-
-  result.append("/");
-  if (ssl_config_.channel_id_enabled)
-    result.append("channelid");
-
+  result.push_back('/');
+  result.push_back(ssl_config_.deprecated_cipher_suites_enabled ? '1' : '0');
+  result.push_back(ssl_config_.channel_id_enabled ? '1' : '0');
+  result.push_back(ssl_config_.version_interference_probe ? '1' : '0');
   return result;
 }
 
diff --git a/net/socket/ssl_client_socket_pool.cc b/net/socket/ssl_client_socket_pool.cc
index b335e46b..a557e5b 100644
--- a/net/socket/ssl_client_socket_pool.cc
+++ b/net/socket/ssl_client_socket_pool.cc
@@ -4,6 +4,7 @@
 
 #include "net/socket/ssl_client_socket_pool.h"
 
+#include <cstdlib>
 #include <utility>
 
 #include "base/bind.h"
@@ -130,7 +131,9 @@
                     ? "pm/" + context.ssl_session_cache_shard
                     : context.ssl_session_cache_shard)),
       callback_(
-          base::Bind(&SSLConnectJob::OnIOComplete, base::Unretained(this))) {}
+          base::Bind(&SSLConnectJob::OnIOComplete, base::Unretained(this))),
+      version_interference_probe_(false),
+      version_interference_error_(OK) {}
 
 SSLConnectJob::~SSLConnectJob() {
 }
@@ -236,7 +239,10 @@
 }
 
 int SSLConnectJob::DoTransportConnectComplete(int result) {
-  connection_attempts_ = transport_socket_handle_->connection_attempts();
+  connection_attempts_.insert(
+      connection_attempts_.end(),
+      transport_socket_handle_->connection_attempts().begin(),
+      transport_socket_handle_->connection_attempts().end());
   if (result == OK) {
     next_state_ = STATE_SSL_CONNECT;
     transport_socket_handle_->socket()->GetPeerAddress(&server_address_);
@@ -321,13 +327,22 @@
 
   connect_timing_.ssl_start = base::TimeTicks::Now();
 
+  SSLConfig ssl_config = params_->ssl_config();
+  if (version_interference_probe_) {
+    DCHECK_EQ(SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
+    ssl_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2;
+    ssl_config.version_interference_probe = true;
+  }
   ssl_socket_ = client_socket_factory_->CreateSSLClientSocket(
-      std::move(transport_socket_handle_), params_->host_and_port(),
-      params_->ssl_config(), context_);
+      std::move(transport_socket_handle_), params_->host_and_port(), ssl_config,
+      context_);
   return ssl_socket_->Connect(callback_);
 }
 
 int SSLConnectJob::DoSSLConnectComplete(int result) {
+  // Version interference probes should not result in success.
+  DCHECK(!version_interference_probe_ || result != OK);
+
   // TODO(rvargas): Remove ScopedTracker below once crbug.com/462784 is fixed.
   tracked_objects::ScopedTracker tracking_profile(
       FROM_HERE_WITH_EXPLICIT_FUNCTION(
@@ -346,6 +361,32 @@
     return ERR_ALPN_NEGOTIATION_FAILED;
   }
 
+  // Perform a TLS 1.3 version interference probe on various connection
+  // errors. The retry will never produce a successful connection but may map
+  // errors to ERR_SSL_VERSION_INTERFERENCE, which signals a probable
+  // version-interfering middlebox.
+  if (params_->ssl_config().version_max == SSL_PROTOCOL_VERSION_TLS1_3 &&
+      !params_->ssl_config().deprecated_cipher_suites_enabled &&
+      !version_interference_probe_) {
+    if (result == ERR_CONNECTION_CLOSED || result == ERR_SSL_PROTOCOL_ERROR ||
+        result == ERR_SSL_VERSION_OR_CIPHER_MISMATCH ||
+        result == ERR_CONNECTION_RESET ||
+        result == ERR_SSL_BAD_RECORD_MAC_ALERT) {
+      // Report the error code for each time a version interference probe is
+      // triggered.
+      UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceProbeTrigger",
+                                  std::abs(result));
+      net_log().AddEventWithNetErrorCode(
+          NetLogEventType::SSL_VERSION_INTERFERENCE_PROBE, result);
+
+      ResetStateForRetry();
+      version_interference_probe_ = true;
+      version_interference_error_ = result;
+      next_state_ = GetInitialState(params_->GetConnectionType());
+      return OK;
+    }
+  }
+
   const std::string& host = params_->host_and_port().host();
   bool is_google =
       host == "google.com" ||
@@ -450,6 +491,14 @@
                                 std::abs(result));
   }
 
+  if (result == ERR_SSL_VERSION_INTERFERENCE) {
+    // Record the error code version interference was detected at.
+    DCHECK(version_interference_probe_);
+    DCHECK_NE(OK, version_interference_error_);
+    UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLVersionInterferenceError",
+                                std::abs(version_interference_error_));
+  }
+
   if (result == OK || IsCertificateError(result)) {
     SetSocket(std::move(ssl_socket_));
   } else if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED) {
@@ -480,6 +529,13 @@
   return DoLoop(OK);
 }
 
+void SSLConnectJob::ResetStateForRetry() {
+  transport_socket_handle_.reset();
+  ssl_socket_.reset();
+  error_response_info_ = HttpResponseInfo();
+  server_address_ = IPEndPoint();
+}
+
 SSLClientSocketPool::SSLConnectJobFactory::SSLConnectJobFactory(
     TransportClientSocketPool* transport_pool,
     SOCKSClientSocketPool* socks_pool,
diff --git a/net/socket/ssl_client_socket_pool.h b/net/socket/ssl_client_socket_pool.h
index 5dfc041..c4913df 100644
--- a/net/socket/ssl_client_socket_pool.h
+++ b/net/socket/ssl_client_socket_pool.h
@@ -151,6 +151,8 @@
   // Otherwise, it returns a net error code.
   int ConnectInternal() override;
 
+  void ResetStateForRetry();
+
   scoped_refptr<SSLSocketParams> params_;
   TransportClientSocketPool* const transport_pool_;
   SOCKSClientSocketPool* const socks_pool_;
@@ -172,6 +174,12 @@
   // through an HTTPS CONNECT request or a SOCKS proxy).
   IPEndPoint server_address_;
 
+  bool version_interference_probe_;
+
+  // The error which triggered a TLS 1.3 version interference probe, or OK if
+  // none was triggered.
+  int version_interference_error_;
+
   DISALLOW_COPY_AND_ASSIGN(SSLConnectJob);
 };
 
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index b5fd0a9..6067721 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -2841,6 +2841,37 @@
   EXPECT_EQ(SSLInfo::HANDSHAKE_FULL, ssl_info.handshake_type);
 }
 
+// Tests that the version_interference_probe option rejects successful
+// connections and passes errors through.
+TEST_F(SSLClientSocketTest, VersionInterferenceProbe) {
+  ASSERT_TRUE(StartTestServer(SpawnedTestServer::SSLOptions()));
+
+  SSLConfig ssl_config;
+  ssl_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2;
+  ssl_config.version_interference_probe = true;
+
+  // Successful connections map to a dedicated error.
+  int rv;
+  ASSERT_TRUE(CreateAndConnectSSLClientSocket(ssl_config, &rv));
+  EXPECT_THAT(rv, IsError(ERR_SSL_VERSION_INTERFERENCE));
+
+  // Failed connections pass through.
+  TestCompletionCallback callback;
+  std::unique_ptr<StreamSocket> real_transport(
+      new TCPClientSocket(addr(), NULL, NULL, NetLogSource()));
+  std::unique_ptr<SynchronousErrorStreamSocket> transport(
+      new SynchronousErrorStreamSocket(std::move(real_transport)));
+  rv = callback.GetResult(transport->Connect(callback.callback()));
+  EXPECT_THAT(rv, IsOk());
+  SynchronousErrorStreamSocket* raw_transport = transport.get();
+  std::unique_ptr<SSLClientSocket> sock(CreateSSLClientSocket(
+      std::move(transport), spawned_test_server()->host_port_pair(),
+      ssl_config));
+  raw_transport->SetNextWriteError(ERR_CONNECTION_RESET);
+  rv = callback.GetResult(sock->Connect(callback.callback()));
+  EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
+}
+
 TEST_F(SSLClientSocketTest, RequireECDHE) {
   // Run test server without ECDHE.
   SpawnedTestServer::SSLOptions ssl_options;
diff --git a/net/spdy/spdy_http_stream.cc b/net/spdy/spdy_http_stream.cc
index 8bfc4b7..0e07de3 100644
--- a/net/spdy/spdy_http_stream.cc
+++ b/net/spdy/spdy_http_stream.cc
@@ -191,6 +191,11 @@
   return stream_->raw_sent_bytes();
 }
 
+bool SpdyHttpStream::GetAlternativeService(
+    AlternativeService* alternative_service) const {
+  return false;
+}
+
 bool SpdyHttpStream::GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const {
   if (stream_closed_) {
     if (!closed_stream_has_load_timing_info_)
diff --git a/net/spdy/spdy_http_stream.h b/net/spdy/spdy_http_stream.h
index 3605f9b..8b7a82d 100644
--- a/net/spdy/spdy_http_stream.h
+++ b/net/spdy/spdy_http_stream.h
@@ -74,6 +74,8 @@
   // not including proxy overhead. Note that some SPDY frames such as pings are
   // not associated with any stream, and are not included in this value.
   int64_t GetTotalSentBytes() const override;
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
   bool GetRemoteEndpoint(IPEndPoint* endpoint) override;
   void PopulateNetErrorDetails(NetErrorDetails* details) override;
diff --git a/net/ssl/ssl_config.cc b/net/ssl/ssl_config.cc
index 726ce48..528ff2a 100644
--- a/net/ssl/ssl_config.cc
+++ b/net/ssl/ssl_config.cc
@@ -28,6 +28,7 @@
       version_min(kDefaultSSLVersionMin),
       version_max(kDefaultSSLVersionMax),
       deprecated_cipher_suites_enabled(false),
+      version_interference_probe(false),
       channel_id_enabled(true),
       false_start_enabled(true),
       signed_cert_timestamps_enabled(true),
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h
index 7e6283d..eee5622 100644
--- a/net/ssl/ssl_config.h
+++ b/net/ssl/ssl_config.h
@@ -114,6 +114,12 @@
   // it. https://crbug.com/684730.
   bool deprecated_cipher_suites_enabled;
 
+  // Enables the version interference probing mode. While TLS 1.3 has avoided
+  // most endpoint intolerance, middlebox interference with TLS 1.3 is
+  // rampant. This causes the connection to be discarded on success with
+  // ERR_SSL_VERSION_INTERFERENCE.
+  bool version_interference_probe;
+
   bool channel_id_enabled;   // True if TLS channel ID extension is enabled.
 
   // List of Token Binding key parameters supported by the client. If empty,
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index 60a9c3b..438bf17 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -154,9 +154,10 @@
     // server. Do not change them.
     enum TLSIntolerantLevel {
       TLS_INTOLERANT_NONE = 0,
-      TLS_INTOLERANT_ALL = 1,  // Intolerant of all TLS versions.
+      TLS_INTOLERANT_ALL = 1,     // Intolerant of all TLS versions.
       TLS_INTOLERANT_TLS1_1 = 2,  // Intolerant of TLS 1.1 or higher.
       TLS_INTOLERANT_TLS1_2 = 3,  // Intolerant of TLS 1.2 or higher.
+      TLS_INTOLERANT_TLS1_3 = 4,  // Intolerant of TLS 1.3 or higher.
     };
 
     // Values which control how the server reacts in response to a ClientHello
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 8fd7236..c22625ea 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -2193,6 +2193,7 @@
                                   'fallback. 1 means all TLS versions will be '
                                   'aborted. 2 means TLS 1.1 or higher will be '
                                   'aborted. 3 means TLS 1.2 or higher will be '
+                                  'aborted. 4 means TLS 1.3 or higher will be '
                                   'aborted.')
     self.option_parser.add_option('--tls-intolerance-type',
                                   dest='tls_intolerance_type',
diff --git a/net/url_request/url_request_http_job_unittest.cc b/net/url_request/url_request_http_job_unittest.cc
index ec26ab8..c0665d8 100644
--- a/net/url_request/url_request_http_job_unittest.cc
+++ b/net/url_request/url_request_http_job_unittest.cc
@@ -1136,6 +1136,11 @@
     return false;
   }
 
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override {
+    return false;
+  }
+
   void GetSSLInfo(SSLInfo* ssl_info) override {}
 
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override {}
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 6583968..1eb9711 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -3423,8 +3423,10 @@
         rev_checking_required_local_anchors_(
             rev_checking_required_local_anchors),
         token_binding_enabled_(token_binding_enabled),
-        min_version_(kDefaultSSLVersionMin) {}
+        min_version_(kDefaultSSLVersionMin),
+        max_version_(kDefaultSSLVersionMax) {}
 
+  void set_max_version(uint16_t version) { max_version_ = version; }
   void set_min_version(uint16_t version) { min_version_ = version; }
 
   // SSLConfigService:
@@ -3434,9 +3436,8 @@
     config->verify_ev_cert = ev_enabled_;
     config->rev_checking_required_local_anchors =
         rev_checking_required_local_anchors_;
-    if (min_version_) {
-      config->version_min = min_version_;
-    }
+    config->version_min = min_version_;
+    config->version_max = max_version_;
     if (token_binding_enabled_) {
       config->token_binding_params.push_back(TB_PARAM_ECDSAP256);
     }
@@ -3451,6 +3452,7 @@
   const bool rev_checking_required_local_anchors_;
   const bool token_binding_enabled_;
   uint16_t min_version_;
+  uint16_t max_version_;
 };
 
 // TODO(svaldez): Update tests to use EmbeddedTestServer.
@@ -9369,10 +9371,21 @@
 
 class HTTPSFallbackTest : public testing::Test {
  public:
-  HTTPSFallbackTest() : context_(true) {}
+  HTTPSFallbackTest()
+      : scoped_task_scheduler_(base::MessageLoop::current()), context_(true) {
+    ssl_config_service_ = new TestSSLConfigService(
+        true /* check for EV */, false /* online revocation checking */,
+        false /* require rev. checking for local anchors */,
+        false /* token binding enabled */);
+    context_.set_ssl_config_service(ssl_config_service_.get());
+  }
   ~HTTPSFallbackTest() override {}
 
  protected:
+  TestSSLConfigService* ssl_config_service() {
+    return ssl_config_service_.get();
+  }
+
   void DoFallbackTest(const SpawnedTestServer::SSLOptions& ssl_options) {
     DCHECK(!request_);
     context_.Init();
@@ -9391,15 +9404,25 @@
     base::RunLoop().Run();
   }
 
+  void ExpectConnection(int version) {
+    EXPECT_EQ(1, delegate_.response_started_count());
+    EXPECT_NE(0, delegate_.bytes_received());
+    EXPECT_EQ(version, SSLConnectionStatusToVersion(
+                           request_->ssl_info().connection_status));
+  }
+
   void ExpectFailure(int error) {
     EXPECT_EQ(1, delegate_.response_started_count());
     EXPECT_EQ(error, delegate_.request_status());
   }
 
  private:
+  // Required by ChannelIDService.
+  base::test::ScopedTaskScheduler scoped_task_scheduler_;
   TestDelegate delegate_;
   TestURLRequestContext context_;
   std::unique_ptr<URLRequest> request_;
+  scoped_refptr<TestSSLConfigService> ssl_config_service_;
 };
 
 // Tests the TLS 1.0 fallback doesn't happen.
@@ -9424,6 +9447,30 @@
   ExpectFailure(ERR_SSL_VERSION_OR_CIPHER_MISMATCH);
 }
 
+// Tests that TLS 1.3 interference results in a dedicated error code.
+TEST_F(HTTPSFallbackTest, TLSv1_3Interference) {
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_OK);
+  ssl_options.tls_intolerant =
+      SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_3;
+  ssl_config_service()->set_max_version(SSL_PROTOCOL_VERSION_TLS1_3);
+
+  ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
+  ExpectFailure(ERR_SSL_VERSION_INTERFERENCE);
+}
+
+// Tests that disabling TLS 1.3 leaves TLS 1.3 interference unnoticed.
+TEST_F(HTTPSFallbackTest, TLSv1_3InterferenceDisableVersion) {
+  SpawnedTestServer::SSLOptions ssl_options(
+      SpawnedTestServer::SSLOptions::CERT_OK);
+  ssl_options.tls_intolerant =
+      SpawnedTestServer::SSLOptions::TLS_INTOLERANT_TLS1_3;
+  ssl_config_service()->set_max_version(SSL_PROTOCOL_VERSION_TLS1_2);
+
+  ASSERT_NO_FATAL_FAILURE(DoFallbackTest(ssl_options));
+  ExpectConnection(SSL_CONNECTION_VERSION_TLS1_2);
+}
+
 class HTTPSSessionTest : public testing::Test {
  public:
   HTTPSSessionTest()
diff --git a/net/websockets/websocket_basic_handshake_stream.cc b/net/websockets/websocket_basic_handshake_stream.cc
index efe263a..c67eb4a 100644
--- a/net/websockets/websocket_basic_handshake_stream.cc
+++ b/net/websockets/websocket_basic_handshake_stream.cc
@@ -420,6 +420,11 @@
   return 0;
 }
 
+bool WebSocketBasicHandshakeStream::GetAlternativeService(
+    AlternativeService* alternative_service) const {
+  return false;
+}
+
 bool WebSocketBasicHandshakeStream::GetLoadTimingInfo(
     LoadTimingInfo* load_timing_info) const {
   return state_.connection()->GetLoadTimingInfo(IsConnectionReused(),
diff --git a/net/websockets/websocket_basic_handshake_stream.h b/net/websockets/websocket_basic_handshake_stream.h
index dffe472e..06bc333 100644
--- a/net/websockets/websocket_basic_handshake_stream.h
+++ b/net/websockets/websocket_basic_handshake_stream.h
@@ -61,6 +61,8 @@
   bool CanReuseConnection() const override;
   int64_t GetTotalReceivedBytes() const override;
   int64_t GetTotalSentBytes() const override;
+  bool GetAlternativeService(
+      AlternativeService* alternative_service) const override;
   bool GetLoadTimingInfo(LoadTimingInfo* load_timing_info) const override;
   void GetSSLInfo(SSLInfo* ssl_info) override;
   void GetSSLCertRequestInfo(SSLCertRequestInfo* cert_request_info) override;
diff --git a/remoting/BUILD.gn b/remoting/BUILD.gn
index 2fad3f0..d2b0db8c 100644
--- a/remoting/BUILD.gn
+++ b/remoting/BUILD.gn
@@ -37,6 +37,10 @@
     ]
   }
 
+  if (is_ios) {
+    deps += [ "//remoting/client/ios:all" ]
+  }
+
   if (enable_remoting_host) {
     deps += [
       "//remoting:remoting_perftests",
diff --git a/remoting/client/ios/facade/host_info.cc b/remoting/client/ios/facade/host_info.cc
index 671473d5..c036e535 100644
--- a/remoting/client/ios/facade/host_info.cc
+++ b/remoting/client/ios/facade/host_info.cc
@@ -22,7 +22,7 @@
     if (!list_value->empty()) {
       for (const auto& item : *list_value) {
         std::string token_url_pattern;
-        if (!item->GetAsString(&token_url_pattern)) {
+        if (!item.GetAsString(&token_url_pattern)) {
           return false;
         }
         token_url_patterns.push_back(token_url_pattern);
diff --git a/remoting/client/ios/facade/host_list_fetcher.cc b/remoting/client/ios/facade/host_list_fetcher.cc
index e0016eb..6c1bb00 100644
--- a/remoting/client/ios/facade/host_list_fetcher.cc
+++ b/remoting/client/ios/facade/host_list_fetcher.cc
@@ -85,10 +85,10 @@
   }
 
   // Any host_info with malformed data will not be added to the hostlist.
-  base::DictionaryValue* host_dict;
+  const base::DictionaryValue* host_dict;
   for (const auto& host_info : *hosts) {
     remoting::HostInfo host;
-    if (host_info->GetAsDictionary(&host_dict) &&
+    if (host_info.GetAsDictionary(&host_dict) &&
         host.ParseHostInfo(*host_dict)) {
       hostlist->push_back(host);
     }
diff --git a/remoting/remoting_enable.gni b/remoting/remoting_enable.gni
index 3b9f45e0..a031976 100644
--- a/remoting/remoting_enable.gni
+++ b/remoting/remoting_enable.gni
@@ -6,5 +6,5 @@
 import("//media/media_options.gni")
 
 declare_args() {
-  enable_remoting = !is_ios && !is_chromecast && enable_webrtc
+  enable_remoting = !is_chromecast && enable_webrtc
 }
diff --git a/services/catalog/catalog.cc b/services/catalog/catalog.cc
index b062eb4..3189881d8 100644
--- a/services/catalog/catalog.cc
+++ b/services/catalog/catalog.cc
@@ -25,7 +25,6 @@
 #include "services/catalog/entry_cache.h"
 #include "services/catalog/instance.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 namespace catalog {
diff --git a/services/device/device_service.cc b/services/device/device_service.cc
index ea0f021..5578cf5 100644
--- a/services/device/device_service.cc
+++ b/services/device/device_service.cc
@@ -23,7 +23,6 @@
 #include "services/device/power_monitor/power_monitor_message_broadcaster.h"
 #include "services/device/public/cpp/device_features.h"
 #include "services/device/time_zone_monitor/time_zone_monitor.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_info.h"
 #include "ui/gfx/native_widget_types.h"
diff --git a/services/device/device_service_test_base.cc b/services/device/device_service_test_base.cc
index e967c17..595f669 100644
--- a/services/device/device_service_test_base.cc
+++ b/services/device/device_service_test_base.cc
@@ -11,8 +11,8 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/device/device_service.h"
 #include "services/device/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/interfaces/service_factory.mojom.h"
 
@@ -31,14 +31,17 @@
   explicit ServiceTestClient(service_manager::test::ServiceTest* test)
       : service_manager::test::ServiceTestClient(test),
         io_thread_("DeviceServiceTestIOThread"),
-        file_thread_("DeviceServiceTestFileThread") {}
+        file_thread_("DeviceServiceTestFileThread") {
+    registry_.AddInterface<service_manager::mojom::ServiceFactory>(this);
+  }
   ~ServiceTestClient() override {}
 
  protected:
-  bool OnConnect(const service_manager::ServiceInfo& remote_info,
-                 service_manager::InterfaceRegistry* registry) override {
-    registry->AddInterface<service_manager::mojom::ServiceFactory>(this);
-    return true;
+  void OnBindInterface(const service_manager::ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   void CreateService(service_manager::mojom::ServiceRequest request,
@@ -69,6 +72,7 @@
  private:
   base::Thread io_thread_;
   base::Thread file_thread_;
+  service_manager::BinderRegistry registry_;
   mojo::BindingSet<service_manager::mojom::ServiceFactory>
       service_factory_bindings_;
   std::unique_ptr<service_manager::ServiceContext> device_service_context_;
diff --git a/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc b/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc
index 9fb1459..e325355 100644
--- a/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc
+++ b/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc
@@ -7,15 +7,18 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 
 namespace device {
 
 PowerMonitorBroadcastSource::PowerMonitorBroadcastSource(
-    service_manager::InterfaceProvider* interface_provider)
+    service_manager::Connector* connector)
     : last_reported_battery_power_state_(false), binding_(this) {
-  if (interface_provider) {
+  if (connector) {
     device::mojom::PowerMonitorPtr power_monitor;
-    interface_provider->GetInterface(mojo::MakeRequest(&power_monitor));
+    connector->BindInterface(device::mojom::kServiceName,
+                             mojo::MakeRequest(&power_monitor));
     power_monitor->AddClient(binding_.CreateInterfacePtrAndBind());
   }
 }
diff --git a/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h b/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h
index 5f8f06e..1969aff1 100644
--- a/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h
+++ b/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h
@@ -9,7 +9,10 @@
 #include "base/power_monitor/power_monitor_source.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/device/public/interfaces/power_monitor.mojom.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+
+namespace service_manager {
+class Connector;
+}
 
 namespace device {
 
@@ -18,8 +21,7 @@
 class PowerMonitorBroadcastSource : public base::PowerMonitorSource,
                                     public device::mojom::PowerMonitorClient {
  public:
-  explicit PowerMonitorBroadcastSource(
-      service_manager::InterfaceProvider* interface_provider);
+  explicit PowerMonitorBroadcastSource(service_manager::Connector* connector);
   ~PowerMonitorBroadcastSource() override;
 
   void PowerStateChange(bool on_battery_power) override;
diff --git a/services/file/file_service.cc b/services/file/file_service.cc
index d10ed4dc..21946921 100644
--- a/services/file/file_service.cc
+++ b/services/file/file_service.cc
@@ -12,7 +12,6 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/file/file_system.h"
 #include "services/file/user_id_map.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 namespace file {
diff --git a/services/file/file_system.cc b/services/file/file_system.cc
index e022d4c..d4ff32f 100644
--- a/services/file/file_system.cc
+++ b/services/file/file_system.cc
@@ -14,7 +14,6 @@
 #include "components/filesystem/lock_table.h"
 #include "components/filesystem/public/interfaces/types.mojom.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/connection.h"
 
 namespace file {
 
diff --git a/services/identity/identity_service.cc b/services/identity/identity_service.cc
index 1cb95dc..dfdb742 100644
--- a/services/identity/identity_service.cc
+++ b/services/identity/identity_service.cc
@@ -5,7 +5,6 @@
 #include "services/identity/identity_service.h"
 
 #include "services/identity/identity_manager.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 namespace identity {
diff --git a/services/navigation/navigation_unittest.cc b/services/navigation/navigation_unittest.cc
index 5dfc8adb..740cc6f 100644
--- a/services/navigation/navigation_unittest.cc
+++ b/services/navigation/navigation_unittest.cc
@@ -24,7 +24,7 @@
  protected:
    void SetUp() override {
      service_manager::test::ServiceTest::SetUp();
-     window_manager_connection_ = connector()->Connect("test_wm");
+     connector()->StartService("test_wm");
    }
 
   mojom::ViewClientPtr GetViewClient() {
@@ -66,7 +66,6 @@
   int load_count_ = 0;
   mojo::Binding<mojom::ViewClient> binding_;
   base::RunLoop* loop_ = nullptr;
-  std::unique_ptr<service_manager::Connection> window_manager_connection_;
 
   DISALLOW_COPY_AND_ASSIGN(NavigationTest);
 };
diff --git a/services/preferences/persistent_pref_store_impl.cc b/services/preferences/persistent_pref_store_impl.cc
index fe7e4b989..959303876 100644
--- a/services/preferences/persistent_pref_store_impl.cc
+++ b/services/preferences/persistent_pref_store_impl.cc
@@ -34,20 +34,27 @@
 
   ~Connection() override = default;
 
-  void OnPrefValueChanged(const std::string& key, const base::Value* value) {
-    if (write_in_progress_ || !base::ContainsKey(observed_keys_, key))
+  void OnPrefValuesChanged(const std::vector<mojom::PrefUpdatePtr>& updates) {
+    if (write_in_progress_)
       return;
 
-    observer_->OnPrefChanged(key, value ? value->CreateDeepCopy() : nullptr);
+    std::vector<mojom::PrefUpdatePtr> filtered_updates;
+    for (const auto& update : updates) {
+      if (base::ContainsKey(observed_keys_, update->key)) {
+        filtered_updates.push_back(mojom::PrefUpdate::New(
+            update->key,
+            update->value ? update->value->CreateDeepCopy() : nullptr, 0));
+      }
+    }
+    if (!filtered_updates.empty())
+      observer_->OnPrefsChanged(std::move(filtered_updates));
   }
 
  private:
   // mojom::PersistentPrefStore:
-  void SetValue(const std::string& key,
-                std::unique_ptr<base::Value> value,
-                uint32_t flags) override {
+  void SetValues(std::vector<mojom::PrefUpdatePtr> updates) override {
     base::AutoReset<bool> scoped_call_in_progress(&write_in_progress_, true);
-    pref_store_->SetValue(key, std::move(value), flags);
+    pref_store_->SetValues(std::move(updates));
   }
 
   void CommitPendingWrite() override { pref_store_->CommitPendingWrite(); }
@@ -76,17 +83,15 @@
     scoped_refptr<PersistentPrefStore> backing_pref_store,
     base::OnceClosure on_initialized)
     : backing_pref_store_(backing_pref_store) {
-  backing_pref_store_->AddObserver(this);
   if (!backing_pref_store_->IsInitializationComplete()) {
+    backing_pref_store_->AddObserver(this);
     on_initialized_ = std::move(on_initialized);
     initializing_ = true;
     backing_pref_store_->ReadPrefsAsync(nullptr);
   }
 }
 
-PersistentPrefStoreImpl::~PersistentPrefStoreImpl() {
-  backing_pref_store_->RemoveObserver(this);
-}
+PersistentPrefStoreImpl::~PersistentPrefStoreImpl() = default;
 
 mojom::PersistentPrefStoreConnectionPtr
 PersistentPrefStoreImpl::CreateConnection(ObservedPrefs observed_prefs) {
@@ -113,32 +118,28 @@
       backing_pref_store_->ReadOnly());
 }
 
-void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {
-  // All mutations are triggered by a client. Updates are only sent to clients
-  // other than the instigator so if there is only one client, it will ignore
-  // the update.
-  if (connections_.size() == 1)
-    return;
-
-  const base::Value* value = nullptr;
-  backing_pref_store_->GetValue(key, &value);
-  for (auto& entry : connections_)
-    entry.first->OnPrefValueChanged(key, value);
-}
+void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {}
 
 void PersistentPrefStoreImpl::OnInitializationCompleted(bool succeeded) {
   DCHECK(initializing_);
+  backing_pref_store_->RemoveObserver(this);
   initializing_ = false;
   std::move(on_initialized_).Run();
 }
 
-void PersistentPrefStoreImpl::SetValue(const std::string& key,
-                                       std::unique_ptr<base::Value> value,
-                                       uint32_t flags) {
-  if (value)
-    backing_pref_store_->SetValue(key, std::move(value), flags);
-  else
-    backing_pref_store_->RemoveValue(key, flags);
+void PersistentPrefStoreImpl::SetValues(
+    std::vector<mojom::PrefUpdatePtr> updates) {
+  for (auto& entry : connections_)
+    entry.first->OnPrefValuesChanged(updates);
+
+  for (auto& update : updates) {
+    if (update->value) {
+      backing_pref_store_->SetValue(update->key, std::move(update->value),
+                                    update->flags);
+    } else {
+      backing_pref_store_->RemoveValue(update->key, update->flags);
+    }
+  }
 }
 
 void PersistentPrefStoreImpl::CommitPendingWrite() {
diff --git a/services/preferences/persistent_pref_store_impl.h b/services/preferences/persistent_pref_store_impl.h
index 49d9cd9..5111ed7 100644
--- a/services/preferences/persistent_pref_store_impl.h
+++ b/services/preferences/persistent_pref_store_impl.h
@@ -14,10 +14,6 @@
 #include "services/preferences/public/interfaces/preferences.mojom.h"
 #include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
 
-namespace base {
-class Value;
-}
-
 namespace prefs {
 
 class PersistentPrefStoreImpl : public PrefStore::Observer {
@@ -40,9 +36,7 @@
  private:
   class Connection;
 
-  void SetValue(const std::string& key,
-                std::unique_ptr<base::Value> value,
-                uint32_t flags);
+  void SetValues(std::vector<mojom::PrefUpdatePtr> updates);
 
   void CommitPendingWrite();
   void SchedulePendingLossyWrites();
diff --git a/services/preferences/public/cpp/persistent_pref_store_client.cc b/services/preferences/public/cpp/persistent_pref_store_client.cc
index 353ac4c..9bcb92f 100644
--- a/services/preferences/public/cpp/persistent_pref_store_client.cc
+++ b/services/preferences/public/cpp/persistent_pref_store_client.cc
@@ -19,12 +19,14 @@
     std::vector<PrefValueStore::PrefStoreType> already_connected_types)
     : connector_(std::move(connector)),
       pref_registry_(std::move(pref_registry)),
-      already_connected_types_(std::move(already_connected_types)) {
+      already_connected_types_(std::move(already_connected_types)),
+      weak_factory_(this) {
   DCHECK(connector_);
 }
 
 PersistentPrefStoreClient::PersistentPrefStoreClient(
-    mojom::PersistentPrefStoreConnectionPtr connection) {
+    mojom::PersistentPrefStoreConnectionPtr connection)
+    : weak_factory_(this) {
   OnConnect(std::move(connection),
             std::unordered_map<PrefValueStore::PrefStoreType,
                                prefs::mojom::PrefStoreConnectionPtr>());
@@ -57,8 +59,8 @@
   DCHECK(pref_store_);
   const base::Value* local_value = nullptr;
   GetMutableValues().Get(key, &local_value);
-  pref_store_->SetValue(
-      key, local_value ? local_value->CreateDeepCopy() : nullptr, flags);
+
+  QueueWrite(key, flags);
   ReportPrefValueChanged(key);
 }
 
@@ -67,7 +69,7 @@
     std::unique_ptr<base::Value> value,
     uint32_t flags) {
   DCHECK(pref_store_);
-  pref_store_->SetValue(key, value->CreateDeepCopy(), flags);
+  QueueWrite(key, flags);
   GetMutableValues().Set(key, std::move(value));
 }
 
@@ -108,6 +110,8 @@
 
 void PersistentPrefStoreClient::CommitPendingWrite() {
   DCHECK(pref_store_);
+  if (!pending_writes_.empty())
+    FlushPendingWrites();
   pref_store_->CommitPendingWrite();
 }
 
@@ -125,7 +129,7 @@
   if (!pref_store_)
     return;
 
-  pref_store_->CommitPendingWrite();
+  CommitPendingWrite();
 }
 
 void PersistentPrefStoreClient::OnConnect(
@@ -149,4 +153,32 @@
   }
 }
 
+void PersistentPrefStoreClient::QueueWrite(const std::string& key,
+                                           uint32_t flags) {
+  if (pending_writes_.empty()) {
+    // Use a weak pointer since a pending write should not prolong the life of
+    // |this|. Instead, the destruction of |this| will flush any pending writes.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::Bind(&PersistentPrefStoreClient::FlushPendingWrites,
+                              weak_factory_.GetWeakPtr()));
+  }
+  pending_writes_.insert(std::make_pair(key, flags));
+}
+
+void PersistentPrefStoreClient::FlushPendingWrites() {
+  std::vector<mojom::PrefUpdatePtr> updates;
+  for (const auto& pref : pending_writes_) {
+    const base::Value* value = nullptr;
+    if (GetValue(pref.first, &value)) {
+      updates.push_back(mojom::PrefUpdate::New(
+          pref.first, value->CreateDeepCopy(), pref.second));
+    } else {
+      updates.push_back(
+          mojom::PrefUpdate::New(pref.first, nullptr, pref.second));
+    }
+  }
+  pref_store_->SetValues(std::move(updates));
+  pending_writes_.clear();
+}
+
 }  // namespace prefs
diff --git a/services/preferences/public/cpp/persistent_pref_store_client.h b/services/preferences/public/cpp/persistent_pref_store_client.h
index 6ed2b11..e317ec9 100644
--- a/services/preferences/public/cpp/persistent_pref_store_client.h
+++ b/services/preferences/public/cpp/persistent_pref_store_client.h
@@ -66,15 +66,21 @@
                                     prefs::mojom::PrefStoreConnectionPtr>
                      other_pref_stores);
 
+  void QueueWrite(const std::string& key, uint32_t flags);
+  void FlushPendingWrites();
+
   mojom::PrefStoreConnectorPtr connector_;
   scoped_refptr<PrefRegistry> pref_registry_;
   bool read_only_ = false;
   PrefReadError read_error_ = PersistentPrefStore::PREF_READ_ERROR_NONE;
   mojom::PersistentPrefStorePtr pref_store_;
+  std::map<std::string, uint32_t> pending_writes_;
 
   std::unique_ptr<ReadErrorDelegate> error_delegate_;
   std::vector<PrefValueStore::PrefStoreType> already_connected_types_;
 
+  base::WeakPtrFactory<PersistentPrefStoreClient> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreClient);
 };
 
diff --git a/services/preferences/public/cpp/pref_store_client_mixin.cc b/services/preferences/public/cpp/pref_store_client_mixin.cc
index a82108a..0387883 100644
--- a/services/preferences/public/cpp/pref_store_client_mixin.cc
+++ b/services/preferences/public/cpp/pref_store_client_mixin.cc
@@ -82,6 +82,23 @@
 }
 
 template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::OnPrefsChanged(
+    std::vector<mojom::PrefUpdatePtr> updates) {
+  for (const auto& update : updates)
+    OnPrefChanged(update->key, std::move(update->value));
+}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::OnInitializationCompleted(
+    bool succeeded) {
+  if (!initialized_) {
+    initialized_ = true;
+    for (auto& observer : observers_)
+      observer.OnInitializationCompleted(succeeded);
+  }
+}
+
+template <typename BasePrefStore>
 void PrefStoreClientMixin<BasePrefStore>::OnPrefChanged(
     const std::string& key,
     std::unique_ptr<base::Value> value) {
@@ -106,16 +123,6 @@
     ReportPrefValueChanged(key);
 }
 
-template <typename BasePrefStore>
-void PrefStoreClientMixin<BasePrefStore>::OnInitializationCompleted(
-    bool succeeded) {
-  if (!initialized_) {
-    initialized_ = true;
-    for (auto& observer : observers_)
-      observer.OnInitializationCompleted(succeeded);
-  }
-}
-
 template class PrefStoreClientMixin<::PrefStore>;
 template class PrefStoreClientMixin<::PersistentPrefStore>;
 
diff --git a/services/preferences/public/cpp/pref_store_client_mixin.h b/services/preferences/public/cpp/pref_store_client_mixin.h
index 9d7a508..19cf250 100644
--- a/services/preferences/public/cpp/pref_store_client_mixin.h
+++ b/services/preferences/public/cpp/pref_store_client_mixin.h
@@ -54,10 +54,12 @@
 
  private:
   // prefs::mojom::PreferenceObserver:
-  void OnPrefChanged(const std::string& key,
-                     std::unique_ptr<base::Value> value) override;
+  void OnPrefsChanged(std::vector<mojom::PrefUpdatePtr> updates) override;
   void OnInitializationCompleted(bool succeeded) override;
 
+  void OnPrefChanged(const std::string& key,
+                     std::unique_ptr<base::Value> value);
+
   // Cached preferences.
   // If null, indicates that initialization failed.
   std::unique_ptr<base::DictionaryValue> cached_prefs_;
diff --git a/services/preferences/public/cpp/pref_store_impl.cc b/services/preferences/public/cpp/pref_store_impl.cc
index b88e99e3..c228962 100644
--- a/services/preferences/public/cpp/pref_store_impl.cc
+++ b/services/preferences/public/cpp/pref_store_impl.cc
@@ -26,14 +26,18 @@
     if (!base::ContainsKey(prefs_, key))
       return;
 
-    observer_->OnPrefChanged(key, value.CreateDeepCopy());
+    std::vector<mojom::PrefUpdatePtr> updates;
+    updates.push_back(mojom::PrefUpdate::New(key, value.CreateDeepCopy(), 0));
+    observer_->OnPrefsChanged(std::move(updates));
   }
 
   void OnPrefRemoved(const std::string& key) const {
     if (!base::ContainsKey(prefs_, key))
       return;
 
-    observer_->OnPrefChanged(key, nullptr);
+    std::vector<mojom::PrefUpdatePtr> updates;
+    updates.push_back(mojom::PrefUpdate::New(key, nullptr, 0));
+    observer_->OnPrefsChanged(std::move(updates));
   }
 
  private:
diff --git a/services/preferences/public/cpp/tests/pref_store_client_unittest.cc b/services/preferences/public/cpp/tests/pref_store_client_unittest.cc
index 6a488a1..dbf86d4 100644
--- a/services/preferences/public/cpp/tests/pref_store_client_unittest.cc
+++ b/services/preferences/public/cpp/tests/pref_store_client_unittest.cc
@@ -40,7 +40,9 @@
 
   bool initialized() { return store_->IsInitializationComplete(); }
   void OnPrefChanged(const std::string& key, const base::Value& value) {
-    observer_ptr_->OnPrefChanged(key, value.CreateDeepCopy());
+    std::vector<mojom::PrefUpdatePtr> updates;
+    updates.push_back(mojom::PrefUpdate::New(key, value.CreateDeepCopy(), 0));
+    observer_ptr_->OnPrefsChanged(std::move(updates));
   }
   void OnInitializationCompleted() {
     observer_ptr_->OnInitializationCompleted(true);
diff --git a/services/preferences/public/interfaces/preferences.mojom b/services/preferences/public/interfaces/preferences.mojom
index 99c0d80..47a79dc 100644
--- a/services/preferences/public/interfaces/preferences.mojom
+++ b/services/preferences/public/interfaces/preferences.mojom
@@ -25,9 +25,8 @@
 
 // Allows observing changes to prefs stored in a |PrefStore|.
 interface PrefStoreObserver {
-  // The preference with the given |key| has changed. If |value| is null then
-  // the preference was deleted.
-  OnPrefChanged(string key, mojo.common.mojom.Value? value);
+  // Preferences have been changed.
+  OnPrefsChanged(array<PrefUpdate> updates);
 
   // The PrefStore has been initialized (asynchronously).
   OnInitializationCompleted(bool succeeded);
@@ -100,11 +99,20 @@
        map<PrefStoreType, PrefStoreConnection> connections);
 };
 
+// An update to a pref.
+struct PrefUpdate {
+  // The key of the pref being updated.
+  string key;
+  // The new value; a null |value| indicates a delete.
+  mojo.common.mojom.Value? value;
+  //|flags| is a bitmask of WritablePrefStore::PrefWriteFlags.
+  uint32 flags;
+};
+
 // An interface providing mutation access to a PersistentPrefStore.
 interface PersistentPrefStore {
-  // Sets the value for |key|. A null |value| indicates a delete. |flags| is a
-  // bitmask of WritablePrefStore::PrefWriteFlags.
-  SetValue(string key, mojo.common.mojom.Value? value, uint32 flags);
+  // Sets the values for prefs.
+  SetValues(array<PrefUpdate> updates);
 
   // These mirror the C++ PersistentPrefStore methods.
   CommitPendingWrite();
diff --git a/services/service_manager/background/tests/background_service_manager_unittest.cc b/services/service_manager/background/tests/background_service_manager_unittest.cc
index e939e0e..3d9f43d 100644
--- a/services/service_manager/background/tests/background_service_manager_unittest.cc
+++ b/services/service_manager/background/tests/background_service_manager_unittest.cc
@@ -27,12 +27,6 @@
   ServiceImpl() {}
   ~ServiceImpl() override {}
 
-  // Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    return false;
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
 };
diff --git a/services/service_manager/background/tests/test_service.cc b/services/service_manager/background/tests/test_service.cc
index 96fd1522..1a4e59a 100644
--- a/services/service_manager/background/tests/test_service.cc
+++ b/services/service_manager/background/tests/test_service.cc
@@ -5,7 +5,7 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/background/tests/test.mojom.h"
 #include "services/service_manager/public/c/main.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_runner.h"
@@ -18,15 +18,16 @@
                    public InterfaceFactory<mojom::TestService>,
                    public mojom::TestService {
  public:
-  TestClient() {}
+  TestClient() { registry_.AddInterface(this); }
   ~TestClient() override {}
 
  private:
   // Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface(this);
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<mojom::TestService>:
@@ -42,6 +43,7 @@
 
   void Quit() override { context()->RequestQuit(); }
 
+  BinderRegistry registry_;
   mojo::BindingSet<mojom::TestService> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(TestClient);
diff --git a/services/service_manager/connect_params.cc b/services/service_manager/connect_params.cc
index e8464a8b..7947a75 100644
--- a/services/service_manager/connect_params.cc
+++ b/services/service_manager/connect_params.cc
@@ -7,6 +7,9 @@
 namespace service_manager {
 
 ConnectParams::ConnectParams() {}
-ConnectParams::~ConnectParams() {}
+ConnectParams::~ConnectParams() {
+  if (!start_service_callback_.is_null())
+    start_service_callback_.Run(result_, resolved_identity_);
+}
 
 }  // namespace service_manager
diff --git a/services/service_manager/connect_params.h b/services/service_manager/connect_params.h
index 8c8787a..c0cbf65 100644
--- a/services/service_manager/connect_params.h
+++ b/services/service_manager/connect_params.h
@@ -10,9 +10,9 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/identity.h"
 #include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
 #include "services/service_manager/public/interfaces/service.mojom.h"
 
 namespace service_manager {
@@ -29,13 +29,6 @@
   void set_target(const Identity& target) { target_ = target; }
   const Identity& target() const { return target_; }
 
-  void set_remote_interfaces(mojom::InterfaceProviderRequest value) {
-    remote_interfaces_ = std::move(value);
-  }
-  mojom::InterfaceProviderRequest TakeRemoteInterfaces() {
-    return std::move(remote_interfaces_);
-  }
-
   void set_client_process_info(
       mojom::ServicePtr service,
       mojom::PIDReceiverRequest pid_receiver_request) {
@@ -68,20 +61,15 @@
     return std::move(interface_pipe_);
   }
 
-  void set_connect_callback(const mojom::Connector::ConnectCallback& value) {
-    connect_callback_ = value;
-  }
-  const mojom::Connector::ConnectCallback& connect_callback() const {
-    return connect_callback_;
+  void set_start_service_callback(
+      const Connector::StartServiceCallback& callback) {
+    start_service_callback_ = callback;
   }
 
-  void set_bind_interface_callback(
-      const mojom::Connector::BindInterfaceCallback& callback) {
-    bind_interface_callback_ = callback;
-  }
-  const mojom::Connector::BindInterfaceCallback&
-      bind_interface_callback() const {
-    return bind_interface_callback_;
+  void set_response_data(mojom::ConnectResult result,
+                         const Identity& resolved_identity) {
+    result_ = result;
+    resolved_identity_ = resolved_identity;
   }
 
  private:
@@ -91,13 +79,16 @@
   // The identity of the application being connected to.
   Identity target_;
 
-  mojom::InterfaceProviderRequest remote_interfaces_;
   mojom::ServicePtr service_;
   mojom::PIDReceiverRequest pid_receiver_request_;
   std::string interface_name_;
   mojo::ScopedMessagePipeHandle interface_pipe_;
-  mojom::Connector::ConnectCallback connect_callback_;
-  mojom::Connector::BindInterfaceCallback bind_interface_callback_;
+  mojom::Connector::StartServiceCallback start_service_callback_;
+
+  // These values are supplied to the response callback for StartService()/
+  // BindInterface() etc. when the connection is completed.
+  mojom::ConnectResult result_ = mojom::ConnectResult::INVALID_ARGUMENT;
+  Identity resolved_identity_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectParams);
 };
diff --git a/services/service_manager/connect_util.cc b/services/service_manager/connect_util.cc
index c37b662..085fdf60 100644
--- a/services/service_manager/connect_util.cc
+++ b/services/service_manager/connect_util.cc
@@ -7,11 +7,18 @@
 #include <memory>
 #include <utility>
 
+#include "base/bind.h"
 #include "services/service_manager/connect_params.h"
 #include "services/service_manager/service_manager.h"
 
 namespace service_manager {
 
+namespace {
+
+void EmptyStartServiceCallback(mojom::ConnectResult result,
+                               const Identity& resolved_identity) {}
+}
+
 mojo::ScopedMessagePipeHandle BindInterface(
     ServiceManager* service_manager,
     const Identity& source,
@@ -22,6 +29,7 @@
   params->set_target(target);
   mojo::MessagePipe pipe;
   params->set_interface_request_info(interface_name, std::move(pipe.handle1));
+  params->set_start_service_callback(base::Bind(&EmptyStartServiceCallback));
   service_manager->Connect(std::move(params));
   return std::move(pipe.handle0);
 }
diff --git a/services/service_manager/public/cpp/BUILD.gn b/services/service_manager/public/cpp/BUILD.gn
index 3320e94..a2452f5c 100644
--- a/services/service_manager/public/cpp/BUILD.gn
+++ b/services/service_manager/public/cpp/BUILD.gn
@@ -13,7 +13,6 @@
   sources = [
     "binder_registry.h",
     "connect.h",
-    "connection.h",
     "connector.h",
     "identity.h",
     "interface_binder.h",
@@ -25,8 +24,6 @@
     "lib/binder_registry.cc",
     "lib/callback_binder.cc",
     "lib/callback_binder.h",
-    "lib/connection_impl.cc",
-    "lib/connection_impl.h",
     "lib/connector_impl.cc",
     "lib/connector_impl.h",
     "lib/identity.cc",
diff --git a/services/service_manager/public/cpp/connection.h b/services/service_manager/public/cpp/connection.h
deleted file mode 100644
index 28eee4d4..0000000
--- a/services/service_manager/public/cpp/connection.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTION_H_
-#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTION_H_
-
-#include "base/memory/weak_ptr.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-
-namespace service_manager {
-
-class InterfaceProvider;
-
-// Represents a connection to another application. An implementation of this
-// interface is returned from Connector::Connect().
-class Connection {
- public:
-  virtual ~Connection() {}
-
-  enum class State {
-    // The service manager has not yet processed the connection.
-    PENDING,
-
-    // The service manager processed the connection and it was established.
-    // GetResult() returns mojom::ConnectionResult::SUCCESS.
-    CONNECTED,
-
-    // The service manager processed the connection and establishment was
-    // prevented by an error, call GetResult().
-    DISCONNECTED
-  };
-
-  class TestApi {
-   public:
-    explicit TestApi(Connection* connection) : connection_(connection) {}
-    base::WeakPtr<Connection> GetWeakPtr() {
-      return connection_->GetWeakPtr();
-    }
-
-   private:
-    Connection* connection_;
-  };
-
-  // 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) {
-    GetRemoteInterfaces()->GetInterface(ptr);
-  }
-  template <typename Interface>
-  void GetInterface(mojo::InterfaceRequest<Interface> request) {
-    GetRemoteInterfaces()->GetInterface(std::move(request));
-  }
-
-  // Returns the remote identity. While the connection is in the pending state,
-  // the user_id() field will be the value passed via Connect(). After the
-  // connection is completed, it will change to the value assigned by the
-  // service manager. Call AddConnectionCompletedClosure() to schedule a closure
-  // to be run when the resolved user id is available.
-  virtual const Identity& GetRemoteIdentity() const = 0;
-
-  // Register a handler to receive an error notification on the pipe to the
-  // remote application's InterfaceProvider.
-  virtual void SetConnectionLostClosure(const base::Closure& handler) = 0;
-
-  // Returns the result of the connection. This function should only be called
-  // when the connection state is not pending. Call
-  // AddConnectionCompletedClosure() to schedule a closure to be run when the
-  // connection is processed by the service manager.
-  virtual mojom::ConnectResult GetResult() const = 0;
-
-  // Returns true if the connection has not yet been processed by the service
-  // manager.
-  virtual bool IsPending() const = 0;
-
-  // Register a closure to be run when the connection has been completed by the
-  // service manager and remote metadata is available. Useful only for
-  // connections created
-  // via Connector::Connect(). Once the connection is complete, metadata is
-  // available immediately.
-  virtual void AddConnectionCompletedClosure(const base::Closure& callback) = 0;
-
-  // Returns an object encapsulating a remote InterfaceProvider.
-  virtual InterfaceProvider* GetRemoteInterfaces() = 0;
-
- protected:
-  virtual base::WeakPtr<Connection> GetWeakPtr() = 0;
-};
-
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTION_H_
diff --git a/services/service_manager/public/cpp/connector.h b/services/service_manager/public/cpp/connector.h
index 37d8338..ae15116 100644
--- a/services/service_manager/public/cpp/connector.h
+++ b/services/service_manager/public/cpp/connector.h
@@ -7,7 +7,6 @@
 
 #include <memory>
 
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/identity.h"
 #include "services/service_manager/public/interfaces/connector.mojom.h"
 #include "services/service_manager/public/interfaces/service.mojom.h"
@@ -17,27 +16,31 @@
 
 // An interface that encapsulates the Service Manager's brokering interface, by
 // which
-// connections between services are established. Once Connect() is called,
-// this class is bound to the thread the call was made on and it cannot be
-// passed to another thread without calling Clone().
+// connections between services are established. Once either StartService() or
+// BindInterface() is called, this class is bound to the thread the call was
+// made on and it cannot be passed to another thread without calling Clone().
 //
 // An instance of this class is created internally by ServiceContext for use
 // on the thread ServiceContext is instantiated on.
 //
 // To use this interface on another thread, call Clone() and pass the new
-// instance to the desired thread before calling Connect().
+// instance to the desired thread before calling StartService() or
+// BindInterface().
 //
 // While instances of this object are owned by the caller, the underlying
 // connection with the service manager is bound to the lifetime of the instance
-// that
-// created it, i.e. when the application is terminated the Connector pipe is
-// closed.
+// that created it, i.e. when the application is terminated the Connector pipe
+// is closed.
 class Connector {
  public:
+  using StartServiceCallback =
+      base::Callback<void(mojom::ConnectResult, const Identity& identity)>;
+
   class TestApi {
    public:
     using Binder = base::Callback<void(mojo::ScopedMessagePipeHandle)>;
     explicit TestApi(Connector* connector) : connector_(connector) {}
+    ~TestApi() { connector_->ResetStartServiceCallback(); }
 
     // Allows caller to specify a callback to bind requests for |interface_name|
     // from |service_name| locally, rather than passing the request through the
@@ -50,6 +53,13 @@
     }
     void ClearBinderOverrides() { connector_->ClearBinderOverrides(); }
 
+    // Register a callback to be run with the result of an attempt to start a
+    // service. This will be run in response to calls to StartService() or
+    // BindInterface().
+    void SetStartServiceCallback(const StartServiceCallback& callback) {
+      connector_->SetStartServiceCallback(callback);
+    }
+
    private:
     Connector* connector_;
   };
@@ -60,22 +70,20 @@
   // for the other end the Connector's interface.
   static std::unique_ptr<Connector> Create(mojom::ConnectorRequest* request);
 
+  // Creates an instance of a service for |identity|.
+  virtual void StartService(const Identity& identity) = 0;
+
+  // Creates an instance of the service |name| inheriting the caller's identity.
+  virtual void StartService(const std::string& name) = 0;
+
   // Creates an instance of a service for |identity| in a process started by the
-  // client (or someone else). Must be called before Connect() may be called to
-  // |identity|.
+  // client (or someone else). Must be called before BindInterface() may be
+  // called to |identity|.
   virtual void StartService(
       const Identity& identity,
       mojom::ServicePtr service,
       mojom::PIDReceiverRequest pid_receiver_request) = 0;
 
-  // Requests a new connection to a service. Returns a pointer to the
-  // connection if the connection is permitted by that service, nullptr
-  // otherwise. Once this method is called, this object is bound to the thread
-  // on which the call took place. To pass to another thread, call Clone() and
-  // pass the result.
-  virtual std::unique_ptr<Connection> Connect(const std::string& name) = 0;
-  virtual std::unique_ptr<Connection> Connect(const Identity& target) = 0;
-
   // Connect to |target| & request to bind |Interface|.
   template <typename Interface>
   void BindInterface(const Identity& target,
@@ -100,8 +108,9 @@
                              mojo::ScopedMessagePipeHandle interface_pipe) = 0;
 
   // Creates a new instance of this class which may be passed to another thread.
-  // The returned object may be passed multiple times until Connect() is called,
-  // at which point this method must be called again to pass again.
+  // The returned object may be passed multiple times until StartService() or
+  // BindInterface() is called, at which point this method must be called again
+  // to pass again.
   virtual std::unique_ptr<Connector> Clone() = 0;
 
   // Binds a Connector request to the other end of this Connector.
@@ -114,6 +123,9 @@
                                         const std::string& interface_name,
                                         const TestApi::Binder& binder) = 0;
   virtual void ClearBinderOverrides() = 0;
+  virtual void SetStartServiceCallback(
+      const StartServiceCallback& callback) = 0;
+  virtual void ResetStartServiceCallback() = 0;
 };
 
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/lib/connection_impl.cc b/services/service_manager/public/cpp/lib/connection_impl.cc
deleted file mode 100644
index bd4ca44..0000000
--- a/services/service_manager/public/cpp/lib/connection_impl.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/service_manager/public/cpp/lib/connection_impl.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/interface_binder.h"
-
-namespace service_manager {
-namespace internal {
-
-////////////////////////////////////////////////////////////////////////////////
-// ConnectionImpl, public:
-
-ConnectionImpl::ConnectionImpl()
-    : weak_factory_(this) {}
-
-ConnectionImpl::ConnectionImpl(const Identity& remote, State initial_state)
-    : remote_(remote),
-      state_(initial_state),
-      weak_factory_(this) {
-}
-
-ConnectionImpl::~ConnectionImpl() {}
-
-void ConnectionImpl::SetRemoteInterfaces(
-    std::unique_ptr<InterfaceProvider> remote_interfaces) {
-  remote_interfaces_owner_ = std::move(remote_interfaces);
-  set_remote_interfaces(remote_interfaces_owner_.get());
-}
-
-service_manager::mojom::Connector::ConnectCallback
-ConnectionImpl::GetConnectCallback() {
-  return base::Bind(&ConnectionImpl::OnConnectionCompleted,
-                    weak_factory_.GetWeakPtr());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ConnectionImpl, Connection implementation:
-
-const Identity& ConnectionImpl::GetRemoteIdentity() const {
-  return remote_;
-}
-
-void ConnectionImpl::SetConnectionLostClosure(const base::Closure& handler) {
-  remote_interfaces_->SetConnectionLostClosure(handler);
-}
-
-service_manager::mojom::ConnectResult ConnectionImpl::GetResult() const {
-  return result_;
-}
-
-bool ConnectionImpl::IsPending() const {
-  return state_ == State::PENDING;
-}
-
-void ConnectionImpl::AddConnectionCompletedClosure(
-    const base::Closure& callback) {
-  if (IsPending())
-    connection_completed_callbacks_.push_back(callback);
-  else
-    callback.Run();
-}
-
-InterfaceProvider* ConnectionImpl::GetRemoteInterfaces() {
-  return remote_interfaces_;
-}
-
-base::WeakPtr<Connection> ConnectionImpl::GetWeakPtr() {
-  return weak_factory_.GetWeakPtr();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ConnectionImpl, private:
-
-void ConnectionImpl::OnConnectionCompleted(
-    service_manager::mojom::ConnectResult result,
-    const std::string& target_user_id) {
-  DCHECK(State::PENDING == state_);
-
-  result_ = result;
-  state_ = result_ == service_manager::mojom::ConnectResult::SUCCEEDED
-               ? State::CONNECTED
-               : State::DISCONNECTED;
-  remote_.set_user_id(target_user_id);
-  std::vector<base::Closure> callbacks;
-  callbacks.swap(connection_completed_callbacks_);
-  for (auto callback : callbacks)
-    callback.Run();
-}
-
-}  // namespace internal
-}  // namespace service_manager
diff --git a/services/service_manager/public/cpp/lib/connection_impl.h b/services/service_manager/public/cpp/lib/connection_impl.h
deleted file mode 100644
index a1fabf5..0000000
--- a/services/service_manager/public/cpp/lib/connection_impl.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
-#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
-
-#include <stdint.h>
-
-#include <set>
-#include <string>
-
-#include "base/callback.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
-
-namespace service_manager {
-namespace internal {
-
-// A ConnectionImpl represents each half of a connection between two
-// applications, allowing customization of which interfaces are published to the
-// other.
-class ConnectionImpl : public Connection {
- public:
-  ConnectionImpl();
-  ConnectionImpl(const Identity& remote, State initial_state);
-  ~ConnectionImpl() override;
-
-  // Sets the remote provider, transferring ownership to the ConnectionImpl.
-  void SetRemoteInterfaces(
-      std::unique_ptr<InterfaceProvider> remote_interfaces);
-
-  // Sets the remote provider, without transferring ownership.
-  void set_remote_interfaces(InterfaceProvider* remote_interfaces) {
-    remote_interfaces_ = remote_interfaces;
-  }
-
-  service_manager::mojom::Connector::ConnectCallback GetConnectCallback();
-
- private:
-  // Connection:
-  const Identity& GetRemoteIdentity() const override;
-  void SetConnectionLostClosure(const base::Closure& handler) override;
-  service_manager::mojom::ConnectResult GetResult() const override;
-  bool IsPending() const override;
-  void AddConnectionCompletedClosure(const base::Closure& callback) override;
-  InterfaceProvider* GetRemoteInterfaces() override;
-  base::WeakPtr<Connection> GetWeakPtr() override;
-
-  void OnConnectionCompleted(service_manager::mojom::ConnectResult result,
-                             const std::string& target_user_id);
-
-  Identity remote_;
-
-  State state_;
-  service_manager::mojom::ConnectResult result_ =
-      service_manager::mojom::ConnectResult::SUCCEEDED;
-  std::vector<base::Closure> connection_completed_callbacks_;
-
-  InterfaceProvider* remote_interfaces_ = nullptr;
-
-  std::unique_ptr<InterfaceProvider> remote_interfaces_owner_;
-
-  base::WeakPtrFactory<ConnectionImpl> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConnectionImpl);
-};
-
-}  // namespace internal
-}  // namespace service_manager
-
-#endif  // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
diff --git a/services/service_manager/public/cpp/lib/connector_impl.cc b/services/service_manager/public/cpp/lib/connector_impl.cc
index 3e7c8410..0040a32 100644
--- a/services/service_manager/public/cpp/lib/connector_impl.cc
+++ b/services/service_manager/public/cpp/lib/connector_impl.cc
@@ -6,14 +6,9 @@
 
 #include "base/memory/ptr_util.h"
 #include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/lib/connection_impl.h"
 
 namespace service_manager {
 
-namespace {
-void EmptyBindCallback(mojom::ConnectResult, const std::string&) {}
-}
-
 ConnectorImpl::ConnectorImpl(mojom::ConnectorPtrInfo unbound_state)
     : unbound_state_(std::move(unbound_state)), weak_factory_(this) {
   thread_checker_.DetachFromThread();
@@ -32,6 +27,17 @@
   connector_.reset();
 }
 
+void ConnectorImpl::StartService(const Identity& identity) {
+  if (BindConnectorIfNecessary())
+    connector_->StartService(identity,
+                             base::Bind(&ConnectorImpl::StartServiceCallback,
+                                        weak_factory_.GetWeakPtr()));
+}
+
+void ConnectorImpl::StartService(const std::string& name) {
+  StartService(Identity(name, mojom::kInheritUserID));
+}
+
 void ConnectorImpl::StartService(
     const Identity& identity,
     mojom::ServicePtr service,
@@ -40,33 +46,11 @@
     return;
 
   DCHECK(service.is_bound() && pid_receiver_request.is_pending());
-  connector_->StartService(identity,
-                           service.PassInterface().PassHandle(),
-                           std::move(pid_receiver_request));
-}
-
-std::unique_ptr<Connection> ConnectorImpl::Connect(const std::string& name) {
-  return Connect(Identity(name, mojom::kInheritUserID));
-}
-
-std::unique_ptr<Connection> ConnectorImpl::Connect(const Identity& target) {
-  if (!BindConnectorIfNecessary())
-    return nullptr;
-
-  DCHECK(thread_checker_.CalledOnValidThread());
-
-  mojom::InterfaceProviderPtr remote_interfaces;
-  mojom::InterfaceProviderRequest remote_request(&remote_interfaces);
-  std::unique_ptr<internal::ConnectionImpl> connection(
-      new internal::ConnectionImpl(target, Connection::State::PENDING));
-  std::unique_ptr<InterfaceProvider> remote_interface_provider(
-      new InterfaceProvider);
-  remote_interface_provider->Bind(std::move(remote_interfaces));
-  connection->SetRemoteInterfaces(std::move(remote_interface_provider));
-
-  connector_->Connect(target, std::move(remote_request),
-                      connection->GetConnectCallback());
-  return std::move(connection);
+  connector_->StartServiceWithProcess(
+      identity, service.PassInterface().PassHandle(),
+      std::move(pid_receiver_request),
+      base::Bind(&ConnectorImpl::StartServiceCallback,
+                 weak_factory_.GetWeakPtr()));
 }
 
 void ConnectorImpl::BindInterface(
@@ -86,7 +70,8 @@
   }
 
   connector_->BindInterface(target, interface_name, std::move(interface_pipe),
-                            base::Bind(&EmptyBindCallback));
+                            base::Bind(&ConnectorImpl::StartServiceCallback,
+                                       weak_factory_.GetWeakPtr()));
 }
 
 std::unique_ptr<Connector> ConnectorImpl::Clone() {
@@ -119,6 +104,15 @@
   local_binder_overrides_.clear();
 }
 
+void ConnectorImpl::SetStartServiceCallback(
+    const Connector::StartServiceCallback& callback) {
+  start_service_callback_ = callback;
+}
+
+void ConnectorImpl::ResetStartServiceCallback() {
+  start_service_callback_.Reset();
+}
+
 bool ConnectorImpl::BindConnectorIfNecessary() {
   // Bind this object to the current thread the first time it is used to
   // connect.
@@ -142,6 +136,12 @@
   return true;
 }
 
+void ConnectorImpl::StartServiceCallback(mojom::ConnectResult result,
+                                         const Identity& user_id) {
+  if (!start_service_callback_.is_null())
+    start_service_callback_.Run(result, user_id);
+}
+
 std::unique_ptr<Connector> Connector::Create(mojom::ConnectorRequest* request) {
   mojom::ConnectorPtr proxy;
   *request = mojo::MakeRequest(&proxy);
diff --git a/services/service_manager/public/cpp/lib/connector_impl.h b/services/service_manager/public/cpp/lib/connector_impl.h
index 6263f44..b07fb2b 100644
--- a/services/service_manager/public/cpp/lib/connector_impl.h
+++ b/services/service_manager/public/cpp/lib/connector_impl.h
@@ -25,11 +25,11 @@
   void OnConnectionError();
 
   // Connector:
+  void StartService(const Identity& identity) override;
+  void StartService(const std::string& name) override;
   void StartService(const Identity& identity,
                     mojom::ServicePtr service,
                     mojom::PIDReceiverRequest pid_receiver_request) override;
-  std::unique_ptr<Connection> Connect(const std::string& name) override;
-  std::unique_ptr<Connection> Connect(const Identity& target) override;
   void BindInterface(const Identity& target,
                      const std::string& interface_name,
                      mojo::ScopedMessagePipeHandle interface_pipe) override;
@@ -40,9 +40,15 @@
                                 const std::string& interface_name,
                                 const TestApi::Binder& binder) override;
   void ClearBinderOverrides() override;
+  void SetStartServiceCallback(const StartServiceCallback& callback) override;
+  void ResetStartServiceCallback() override;
 
   bool BindConnectorIfNecessary();
 
+  // Callback passed to mojom methods StartService()/BindInterface().
+  void StartServiceCallback(mojom::ConnectResult result,
+                            const Identity& user_id);
+
   using BinderOverrideMap = std::map<std::string, TestApi::Binder>;
 
   mojom::ConnectorPtrInfo unbound_state_;
@@ -51,8 +57,9 @@
   base::ThreadChecker thread_checker_;
 
   std::map<std::string, BinderOverrideMap> local_binder_overrides_;
+  Connector::StartServiceCallback start_service_callback_;
 
-  base::WeakPtrFactory<Connector> weak_factory_;
+  base::WeakPtrFactory<ConnectorImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectorImpl);
 };
diff --git a/services/service_manager/public/cpp/lib/identity.cc b/services/service_manager/public/cpp/lib/identity.cc
index 4fa2ff2..409bee1 100644
--- a/services/service_manager/public/cpp/lib/identity.cc
+++ b/services/service_manager/public/cpp/lib/identity.cc
@@ -5,10 +5,11 @@
 #include "services/service_manager/public/cpp/identity.h"
 
 #include "base/guid.h"
+#include "services/service_manager/public/interfaces/connector.mojom.h"
 
 namespace service_manager {
 
-Identity::Identity() {}
+Identity::Identity() : Identity("", mojom::kInheritUserID, "") {}
 
 Identity::Identity(const std::string& name, const std::string& user_id)
     : Identity(name, user_id, "") {}
diff --git a/services/service_manager/public/cpp/lib/interface_registry.cc b/services/service_manager/public/cpp/lib/interface_registry.cc
index 9fb605d8..e74df3c 100644
--- a/services/service_manager/public/cpp/lib/interface_registry.cc
+++ b/services/service_manager/public/cpp/lib/interface_registry.cc
@@ -9,7 +9,6 @@
 
 #include "base/memory/ptr_util.h"
 #include "mojo/public/cpp/bindings/message.h"
-#include "services/service_manager/public/cpp/connection.h"
 
 namespace service_manager {
 namespace {
diff --git a/services/service_manager/public/cpp/lib/service.cc b/services/service_manager/public/cpp/lib/service.cc
index 2b40a6c..b6a20a03b 100644
--- a/services/service_manager/public/cpp/lib/service.cc
+++ b/services/service_manager/public/cpp/lib/service.cc
@@ -6,8 +6,6 @@
 
 #include "base/logging.h"
 #include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
-#include "services/service_manager/public/interfaces/interface_provider_spec.mojom.h"
 
 namespace service_manager {
 
@@ -17,30 +15,9 @@
 
 void Service::OnStart() {}
 
-bool Service::OnConnect(const ServiceInfo& remote_info,
-                        InterfaceRegistry* registry) {
-  return false;
-}
-
 void Service::OnBindInterface(const ServiceInfo& source_info,
                               const std::string& interface_name,
-                              mojo::ScopedMessagePipeHandle interface_pipe) {
-  // TODO(beng): Eliminate this implementation once everyone is migrated to
-  //             OnBindInterface().
-  mojom::InterfaceProviderPtr interface_provider;
-  InterfaceProviderSpec source_spec, target_spec;
-  GetInterfaceProviderSpec(
-      mojom::kServiceManager_ConnectorSpec,
-      service_context_->local_info().interface_provider_specs,
-      &target_spec);
-  GetInterfaceProviderSpec(
-      mojom::kServiceManager_ConnectorSpec,
-      source_info.interface_provider_specs,
-      &source_spec);
-  service_context_->CallOnConnect(source_info, source_spec, target_spec,
-                                  MakeRequest(&interface_provider));
-  interface_provider->GetInterface(interface_name, std::move(interface_pipe));
-}
+                              mojo::ScopedMessagePipeHandle interface_pipe) {}
 
 bool Service::OnServiceManagerConnectionLost() {
   return true;
@@ -64,11 +41,6 @@
   target_->OnStart();
 }
 
-bool ForwardingService::OnConnect(const ServiceInfo& remote_info,
-                                  InterfaceRegistry* registry) {
-  return target_->OnConnect(remote_info, registry);
-}
-
 void ForwardingService::OnBindInterface(
     const ServiceInfo& remote_info,
     const std::string& interface_name,
diff --git a/services/service_manager/public/cpp/lib/service_context.cc b/services/service_manager/public/cpp/lib/service_context.cc
index 6459459..0b53f8c 100644
--- a/services/service_manager/public/cpp/lib/service_context.cc
+++ b/services/service_manager/public/cpp/lib/service_context.cc
@@ -7,15 +7,8 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "base/callback_helpers.h"
 #include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/lib/connector_impl.h"
 #include "services/service_manager/public/cpp/service.h"
 
@@ -88,22 +81,6 @@
   service_->OnStart();
 }
 
-void ServiceContext::OnConnect(
-    const ServiceInfo& source_info,
-    mojom::InterfaceProviderRequest interfaces,
-    const OnConnectCallback& callback) {
-  InterfaceProviderSpec source_spec, target_spec;
-  GetInterfaceProviderSpec(mojom::kServiceManager_ConnectorSpec,
-                           local_info_.interface_provider_specs, &target_spec);
-  GetInterfaceProviderSpec(mojom::kServiceManager_ConnectorSpec,
-                           source_info.interface_provider_specs, &source_spec);
-
-  // Acknowledge the request regardless of whether it's accepted.
-  callback.Run();
-
-  CallOnConnect(source_info, source_spec, target_spec, std::move(interfaces));
-}
-
 void ServiceContext::OnBindInterface(
     const ServiceInfo& source_info,
     const std::string& interface_name,
@@ -119,26 +96,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // ServiceContext, private:
 
-void ServiceContext::CallOnConnect(const ServiceInfo& source_info,
-                                   const InterfaceProviderSpec& source_spec,
-                                   const InterfaceProviderSpec& target_spec,
-                                   mojom::InterfaceProviderRequest interfaces) {
-  auto registry =
-      base::MakeUnique<InterfaceRegistry>(mojom::kServiceManager_ConnectorSpec);
-  registry->Bind(std::move(interfaces), local_info_.identity, target_spec,
-                 source_info.identity, source_spec);
-
-  if (!service_->OnConnect(source_info, registry.get()))
-    return;
-
-  InterfaceRegistry* raw_registry = registry.get();
-  registry->AddConnectionLostClosure(base::Bind(
-      &ServiceContext::OnRegistryConnectionError, base::Unretained(this),
-      raw_registry));
-  connection_interface_registries_.insert(
-      std::make_pair(raw_registry, std::move(registry)));
-}
-
 void ServiceContext::OnConnectionError() {
   if (service_->OnServiceManagerConnectionLost()) {
     // CAUTION: May delete |this|.
@@ -146,21 +103,4 @@
   }
 }
 
-void ServiceContext::OnRegistryConnectionError(InterfaceRegistry* registry) {
-  // NOTE: We destroy the InterfaceRegistry asynchronously since it's calling
-  // into us from its own connection error handler which may continue to access
-  // the InterfaceRegistry's own state after we return.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&ServiceContext::DestroyConnectionInterfaceRegistry,
-                 weak_factory_.GetWeakPtr(), registry));
-}
-
-void ServiceContext::DestroyConnectionInterfaceRegistry(
-    InterfaceRegistry* registry) {
-  auto it = connection_interface_registries_.find(registry);
-  CHECK(it != connection_interface_registries_.end());
-  connection_interface_registries_.erase(it);
-}
-
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/lib/service_test.cc b/services/service_manager/public/cpp/lib/service_test.cc
index 13689ad..30fd49b 100644
--- a/services/service_manager/public/cpp/lib/service_test.cc
+++ b/services/service_manager/public/cpp/lib/service_test.cc
@@ -27,11 +27,10 @@
                        context()->identity().user_id());
 }
 
-bool ServiceTestClient::OnConnect(const ServiceInfo& remote_info,
-                                  InterfaceRegistry* registry) {
-  return false;
-}
-
+void ServiceTestClient::OnBindInterface(
+    const ServiceInfo& source_info,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {}
 
 ServiceTest::ServiceTest() {}
 
diff --git a/services/service_manager/public/cpp/service.h b/services/service_manager/public/cpp/service.h
index db5ad50..9d0c04e 100644
--- a/services/service_manager/public/cpp/service.h
+++ b/services/service_manager/public/cpp/service.h
@@ -12,7 +12,6 @@
 
 namespace service_manager {
 
-class InterfaceRegistry;
 class ServiceContext;
 struct ServiceInfo;
 
@@ -28,16 +27,6 @@
   // will be made before this.
   virtual void OnStart();
 
-  // Called each time a connection to this service is brokered by the Service
-  // Manager. Implement this to expose interfaces to other services.
-  //
-  // Return true if the connection should succeed or false if the connection
-  // should be rejected.
-  //
-  // The default implementation returns false.
-  virtual bool OnConnect(const ServiceInfo& remote_info,
-                         InterfaceRegistry* registry);
-
   // Called when the service identified by |source_info| requests this service
   // bind a request for |interface_name|. If this method has been called, the
   // service manager has already determined that policy permits this interface
@@ -89,8 +78,6 @@
 
   // Service:
   void OnStart() override;
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override;
   void OnBindInterface(const ServiceInfo& remote_info,
                        const std::string& interface_name,
                        mojo::ScopedMessagePipeHandle interface_pipe) override;
diff --git a/services/service_manager/public/cpp/service_context.h b/services/service_manager/public/cpp/service_context.h
index f843462..8cfea21 100644
--- a/services/service_manager/public/cpp/service_context.h
+++ b/services/service_manager/public/cpp/service_context.h
@@ -108,33 +108,16 @@
  private:
   friend class service_manager::Service;
 
-  using InterfaceRegistryMap =
-      std::map<InterfaceRegistry*, std::unique_ptr<InterfaceRegistry>>;
-
   // mojom::Service:
   void OnStart(const ServiceInfo& info,
                const OnStartCallback& callback) override;
-  void OnConnect(const ServiceInfo& source_info,
-                 mojom::InterfaceProviderRequest interfaces,
-                 const OnConnectCallback& callback) override;
   void OnBindInterface(
       const ServiceInfo& source_info,
       const std::string& interface_name,
       mojo::ScopedMessagePipeHandle interface_pipe,
       const OnBindInterfaceCallback& callback) override;
 
-  void CallOnConnect(const ServiceInfo& source_info,
-                     const InterfaceProviderSpec& source_spec,
-                     const InterfaceProviderSpec& target_spec,
-                     mojom::InterfaceProviderRequest request);
-
   void OnConnectionError();
-  void OnRegistryConnectionError(InterfaceRegistry* registry);
-  void DestroyConnectionInterfaceRegistry(InterfaceRegistry* registry);
-
-  // We track the lifetime of incoming connection registries as a convenience
-  // for the client.
-  InterfaceRegistryMap connection_interface_registries_;
 
   // A pending Connector request which will eventually be passed to the Service
   // Manager.
diff --git a/services/service_manager/public/cpp/service_test.h b/services/service_manager/public/cpp/service_test.h
index 1ee7b9a9..a4bfc74 100644
--- a/services/service_manager/public/cpp/service_test.h
+++ b/services/service_manager/public/cpp/service_test.h
@@ -43,8 +43,9 @@
 
  protected:
   void OnStart() override;
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override;
 
  private:
   ServiceTest* test_;
diff --git a/services/service_manager/public/interfaces/connector.mojom b/services/service_manager/public/interfaces/connector.mojom
index 3c759cbb..63168e4a 100644
--- a/services/service_manager/public/interfaces/connector.mojom
+++ b/services/service_manager/public/interfaces/connector.mojom
@@ -6,50 +6,51 @@
 
 import "services/service_manager/public/interfaces/interface_provider.mojom";
 
+// TODO(beng): Determine who (if anyone) uses kRootUserID.
 const string kRootUserID = "505C0EE9-3013-43C0-82B0-A84F50CF8D84";
 const string kInheritUserID = "D26290E4-4485-4EAE-81A2-66D1EEB40A9D";
 
 const uint32 kInvalidInstanceID = 0;
 
+// TODO(beng): Evalute the utility of this enum. There are some inconsistencies
+//             in its use with BindInterface/StartService.
 enum ConnectResult {
-  // The connection was established successfully.
+  // The operation was established successfully.
   SUCCEEDED,
 
   // The name or user id supplied was malformed, or the service specified by
   // |name| could not be loaded.
   INVALID_ARGUMENT,
 
-  // The connection was blocked by policy. Either connections to |name| are
-  // forbidden from this app by the CapabilityFilter, or the service attempted
-  // to connect using a user id other than its own, |kInheritUserID| or
-  // |kRootUserID|.
+  // Policy prevented the successful completion of this operation. Either
+  // requests to bind to |name| are forbidden from the calling service by its
+  // manifest, or the service attempted to connect using a user id other than
+  // its own, |kInheritUserID| or |kRootUserID|.
   ACCESS_DENIED
 };
 
 // A collection of metadata that disambiguates instances in the service manager.
 struct Identity {
-  // A service: or exe: name identifying a service.
+  // A name identifying a service.
   string name;
 
-  // The user id of the target service instance to connect to. If no such
-  // instance exists, the service manager may start one. This user id will be
-  // passed to the new instance via Initialize().
+  // The user id of the target service instance to bind to. If no such instance
+  // exists, the service manager may start one. This user id will be passed to
+  // the new instance via Initialize().
   //
-  // When connecting to other services, services must generally pass
-  // kInheritUserID for this value, and the service manager will either connect
-  // to an existing instance matching the caller's user id, create a new
-  // instance matching the caller's user id, or connect to an existing instance
-  // running as kRootUserID. By default, services do not have the ability to set
-  // arbitrary values to this field, and doing so will result in a connection
-  // error on the remote service provider.
+  // When binding to other services, services must generally pass kInheritUserID
+  // for this value, and the service manager will either bind to an existing
+  // instance matching the caller's user id, create a new instance matching the
+  // caller's user id, or bind to an existing instance running as kRootUserID.
+  // By default, services do not have the ability to set arbitrary values to
+  // this field, and doing so will result in an error response.
   //
   // A service with the ability to launch other services with arbitrary user ids
-  // (e.g. a login service) may set this  value to something meaningful to it.
-  // The user id string is a valid guid of the form
-  // "%08X-%04X-%04X-%04X-%012llX", and (aside from the root user whose
-  // guid is defined above) intended to be not-guessable.
+  // (e.g. a login service) may set this value. The user id string is a valid
+  // guid of the form "%08X-%04X-%04X-%04X-%012llX", and (aside from the root
+  // user whose guid is defined above) intended to be not-guessable.
   //
-  // When a service is initialized or receives a connection from another
+  // When a service is initialized or receives a bind request from another
   // service, this value is always the resolved user id, never |kInheritUserID|.
   string user_id;
 
@@ -67,18 +68,85 @@
   SetPID(uint32 pid);
 };
 
-// Encapsulates establishing connections with other Services.
+// An interface that allows the holder to start other services & bind to
+// interfaces exposed by them.
 interface Connector {
-  // Typically, the service manager will start a process for a service the first
-  // time it receives a connection request for it. This struct allows a client
-  // to start the process itself and provide the service manager the pipes it
-  // needs to communicate with it. When this function is called, the client owns
-  // the lifetime of the child process it started, not the service manager. The
-  // service manager binds the |service| pipe, and when it closes destroys the
-  // associated  instance but the process stays alive.
+  // Asks the service manager to route a request to bind an implementation of
+  // the interface to a named service instance.
+  //
+  // A service's ability to bind interfaces exposed by another is controlled by
+  // policy set out in each service's manifest. See
+  // //services/service_manager/README.md for more information on manifests.
+  // If policy prevents the requesting service from binding the specified
+  // interface, the request pipe will be closed.
   //
   // Parameters:
   //
+  //  target
+  //    The identity of the service instance to route the request to. If no
+  //    instance exists, the service will be started.
+  //
+  //  interface_name
+  //    The name of the interface to be bound. If the target service does not
+  //    expose an interface of this name, the request pipe will be closed.
+  //
+  //  interface_pipe
+  //    A message pipe endpoint encapsulating a request for an interface named
+  //    |interface_name|.
+  //
+  // Response parameters:
+  //
+  //  result
+  //    Indicates the result of the BindInterface() operation.
+  //
+  //  identity
+  //    The fully resolved identity of the instance in the service manager, with
+  //    a resolved user id. Typically the client passes |kInheritUserID| as the
+  //    user id to BindInterface(), which will be resolved by the service
+  //    manager into a concrete user id.
+  //
+  BindInterface(Identity target,
+                string interface_name,
+                handle<message_pipe> interface_pipe) =>
+      (ConnectResult result, Identity user_id);
+
+  // Asks the service manager to create an instance for a service. No action is
+  // taken if an instance is already present. If the service is not yet running,
+  // it will be initialized and its OnStart() method will be called. A process
+  // may be allocated.
+  //
+  // Parameters:
+  //
+  //  target
+  //    The identity of the service to start.
+  //
+  // Response parameters:
+  //
+  //  result
+  //    Indicates the result of the StartService() operation.
+  //
+  //  identity
+  //    The fully resolved identity of the instance in the service manager, with
+  //    a resolved user id. Typically the client passes |kInheritUserID| as the
+  //    user id to BindInterface(), which will be resolved by the service
+  //    manager into a concrete user id.
+  //
+  StartService(Identity target) => (ConnectResult result, Identity identity);
+
+  // Typically, the service manager will start a process for a service the first
+  // time it receives a bind interface request for it, or when StartService() is
+  // called. This struct allows a client to start the process itself and provide
+  // the service manager the pipes it needs to communicate with it. When this
+  // function is called, the client owns the lifetime of the child process it
+  // started, not the service manager. The service manager binds the |service|
+  // pipe, and when it closes destroys the associated instance but the process
+  // stays alive.
+  //
+  // Parameters:
+  //
+  //  target
+  //    The identity of the service to create the instance for.
+  //
   //  service
   //    A pipe to an implementation of Service that the service manager can use
   //    to communicate with the service.
@@ -86,57 +154,13 @@
   //  pid_receiver_request
   //   Allows the client process launcher to tell the service manager the PID of
   //   the process it created (the pid isn't supplied directly here as the
-  //   process may not have been launched by the time Connect() is called.)
+  //   process may not have been launched by the time BindInterface() is
+  //   called.)
   //
-  StartService(Identity name,
-               handle<message_pipe> service,
-               PIDReceiver& pid_receiver_request);
-
-  // Requests a connection with another service. The service originating the
-  // request is referred to as the "source" and the one receiving the "target".
-  //
-  // The connection is embodied by a pair of message pipes binding the
-  // InterfaceProvider interface, which allows both the source and target
-  // services to export interfaces to one another. The interfaces bound via
-  // these InterfaceProviders are brokered by the service manager according to
-  // the security policy defined by each service in its manifest.
-  //
-  // If the target service is not running, the service manager will run it,
-  // calling its OnStart() method before completing the connection.
-  //
-  // Parameters:
-  //
-  //  target
-  //    Identifies the target service instance to connect to.
-  //
-  //  remote_interfaces
-  //    Allows the source service access to interface implementations exposed by
-  //    the target service. The interfaces accessible via this InterfaceProvider
-  //    are filtered by the security policy described by the source and target
-  //    service manifests.
-  //
-  // Response parameters:
-  //
-  //  result
-  //    Indicates the result of the Connect() operation.
-  //
-  //  user_id
-  //    The user id the service manager ran the target service as. Typically a
-  //    client passes |kInheritUserID| as the user id to Connect(), which is
-  //    resolved by the service manager into a valid user id returned through
-  //    this callback.
-  //
-  Connect(Identity target, InterfaceProvider&? remote_interfaces) =>
-      (ConnectResult result, string user_id);
-
-  // Variant of Connect() above. Will (gradually) replace it. Think of this like
-  // a combination of Connect() and InterfaceProvider::GetInteface() - requests
-  // a connection to a service and binds an interface in one step.
-  // TODO(beng): Update this comment once the implementation is complete.
-  BindInterface(Identity target,
-                string interface_name,
-                handle<message_pipe> interface_pipe) =>
-      (ConnectResult result, string user_id);
+  StartServiceWithProcess(Identity target,
+                          handle<message_pipe> service,
+                          PIDReceiver& pid_receiver_request) =>
+      (ConnectResult result, Identity identity);
 
   // Clones this Connector so it can be passed to another thread.
   Clone(Connector& request);
diff --git a/services/service_manager/public/interfaces/service.mojom b/services/service_manager/public/interfaces/service.mojom
index 207da8cd..a0f14f4 100644
--- a/services/service_manager/public/interfaces/service.mojom
+++ b/services/service_manager/public/interfaces/service.mojom
@@ -48,26 +48,6 @@
   OnStart(ServiceInfo info) => (Connector&? connector_request,
                                 associated ServiceControl&? control_request);
 
-  // Called when another service attempts to open a connection to this
-  // service. A service implements this method to complete the exchange
-  // of interface implementations with the remote service. See also
-  // documentation in service_manager.mojom for Connect(). The service
-  // originating the request is referred to as the "source" and the one
-  // receiving the "target".
-  //
-  // The Service must respond to acknowledge receipt of the request.
-  //
-  // Parameters:
-  //
-  //  source_info
-  //    Contains the source identity and interface provider specs.
-  //
-  //  interfaces
-  //    A request for an InterfaceProvider by which the source service may
-  //    seek to bind interface implementations exported by the target.
-  //
-  OnConnect(ServiceInfo source_info, InterfaceProvider&? interfaces) => ();
-
   // Called when a request to bind an interface is received from another
   // ("source") service. This is the result of that service calling
   // BindInterface() on a Connector. By the time this method is called, the
@@ -91,7 +71,6 @@
   //             the source's capability requirements to the target. This seems
   //             undesirable. The metadata supplied here should be germane to
   //             fulfilling this request and no more.
-  // TODO(beng): This should replace OnConnect().
   OnBindInterface(ServiceInfo source_info,
                   string interface_name,
                   handle<message_pipe> interface_pipe) => ();
diff --git a/services/service_manager/service_manager.cc b/services/service_manager/service_manager.cc
index 2a01504..d29b0c9 100644
--- a/services/service_manager/service_manager.cc
+++ b/services/service_manager/service_manager.cc
@@ -51,30 +51,6 @@
   return result == mojom::ConnectResult::SUCCEEDED;
 }
 
-bool RunConnectCallback(ConnectParams* params,
-                        mojom::ConnectResult result,
-                        const std::string& user_id) {
-  if (!params->connect_callback().is_null()) {
-    params->connect_callback().Run(result, user_id);
-    return true;
-  }
-  return false;
-}
-
-void RunBindInterfaceCallback(ConnectParams* params,
-                              mojom::ConnectResult result,
-                              const std::string& user_id) {
-  if (!params->bind_interface_callback().is_null())
-    params->bind_interface_callback().Run(result, user_id);
-}
-
-void RunCallback(ConnectParams* params,
-                 mojom::ConnectResult result,
-                 const std::string& user_id) {
-  if (!RunConnectCallback(params, result, user_id))
-    RunBindInterfaceCallback(params, result, user_id);
-}
-
 }  // namespace
 
 Identity CreateServiceManagerIdentity() {
@@ -152,36 +128,10 @@
     Stop();
   }
 
-  bool CallOnConnect(std::unique_ptr<ConnectParams>* in_params) {
-    if (!service_.is_bound()) {
-      RunConnectCallback(in_params->get(), mojom::ConnectResult::ACCESS_DENIED,
-                         identity_.user_id());
-      return false;
-    }
-
-    std::unique_ptr<ConnectParams> params(std::move(*in_params));
-    RunConnectCallback(params.get(), mojom::ConnectResult::SUCCEEDED,
-                       identity_.user_id());
-
-    InterfaceProviderSpecMap specs;
-    Instance* source =
-        service_manager_->GetExistingInstance(params->source());
-    if (source)
-      specs = source->interface_provider_specs_;
-
-    pending_service_connections_++;
-    service_->OnConnect(ServiceInfo(params->source(), specs),
-                        params->TakeRemoteInterfaces(),
-                        base::Bind(&Instance::OnConnectComplete,
-                                   base::Unretained(this)));
-    return true;
-  }
-
   bool CallOnBindInterface(std::unique_ptr<ConnectParams>* in_params) {
     if (!service_.is_bound()) {
-      RunBindInterfaceCallback(in_params->get(),
-                               mojom::ConnectResult::ACCESS_DENIED,
-                               identity_.user_id());
+      (*in_params)
+          ->set_response_data(mojom::ConnectResult::ACCESS_DENIED, identity_);
       return false;
     }
 
@@ -206,15 +156,11 @@
          << params->source().name() << " from binding interface: "
          << params->interface_name() << " exposed by: " << identity_.name();
       LOG(ERROR) << ss.str();
-      params->bind_interface_callback().Run(mojom::ConnectResult::ACCESS_DENIED,
-                                            identity_.user_id());
+      params->set_response_data(mojom::ConnectResult::ACCESS_DENIED, identity_);
       return false;
     }
 
-    if (!params->bind_interface_callback().is_null()) {
-      params->bind_interface_callback().Run(mojom::ConnectResult::SUCCEEDED,
-                                            identity_.user_id());
-    }
+    params->set_response_data(mojom::ConnectResult::SUCCEEDED, identity_);
 
     pending_service_connections_++;
     service_->OnBindInterface(
@@ -307,65 +253,67 @@
   };
 
   // mojom::Connector implementation:
-  void StartService(
-      const Identity& in_target,
-      mojo::ScopedMessagePipeHandle service_handle,
-      mojom::PIDReceiverRequest pid_receiver_request) override {
-    Identity target = in_target;
-    mojom::ConnectResult result =
-        ValidateConnectParams(&target, nullptr, nullptr);
-    if (!Succeeded(result))
-      return;
+   void BindInterface(const service_manager::Identity& in_target,
+                      const std::string& interface_name,
+                      mojo::ScopedMessagePipeHandle interface_pipe,
+                      const BindInterfaceCallback& callback) override {
+     Identity target = in_target;
+     mojom::ConnectResult result =
+         ValidateConnectParams(&target, nullptr, nullptr);
+     if (!Succeeded(result)) {
+       callback.Run(result, Identity());
+       return;
+     }
 
-    std::unique_ptr<ConnectParams> params(new ConnectParams);
-    params->set_source(identity_);
-    params->set_target(target);
+     std::unique_ptr<ConnectParams> params(new ConnectParams);
+     params->set_source(identity_);
+     params->set_target(target);
+     params->set_interface_request_info(interface_name,
+                                        std::move(interface_pipe));
+     params->set_start_service_callback(callback);
+     service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
+   }
 
-    mojom::ServicePtr service;
-    service.Bind(mojom::ServicePtrInfo(std::move(service_handle), 0));
-    params->set_client_process_info(std::move(service),
-                                    std::move(pid_receiver_request));
-    service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
-  }
+   void StartService(const Identity& in_target,
+                     const StartServiceCallback& callback) override {
+     Identity target = in_target;
+     mojom::ConnectResult result =
+         ValidateConnectParams(&target, nullptr, nullptr);
+     if (!Succeeded(result)) {
+       callback.Run(result, Identity());
+       return;
+     }
 
-  void Connect(const service_manager::Identity& in_target,
-               mojom::InterfaceProviderRequest remote_interfaces,
-               const ConnectCallback& callback) override {
-    Identity target = in_target;
-    mojom::ConnectResult result =
-        ValidateConnectParams(&target, nullptr, nullptr);
-    if (!Succeeded(result)) {
-      callback.Run(result, mojom::kInheritUserID);
-      return;
-    }
+     std::unique_ptr<ConnectParams> params(new ConnectParams);
+     params->set_source(identity_);
+     params->set_target(target);
+     params->set_start_service_callback(callback);
+     service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
+   }
 
-    std::unique_ptr<ConnectParams> params(new ConnectParams);
-    params->set_source(identity_);
-    params->set_target(target);
-    params->set_remote_interfaces(std::move(remote_interfaces));
-    params->set_connect_callback(callback);
-    service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
-  }
+   void StartServiceWithProcess(
+       const Identity& in_target,
+       mojo::ScopedMessagePipeHandle service_handle,
+       mojom::PIDReceiverRequest pid_receiver_request,
+       const StartServiceWithProcessCallback& callback) override {
+     Identity target = in_target;
+     mojom::ConnectResult result =
+         ValidateConnectParams(&target, nullptr, nullptr);
+     if (!Succeeded(result)) {
+       callback.Run(result, Identity());
+       return;
+     }
 
-  void BindInterface(const service_manager::Identity& in_target,
-                     const std::string& interface_name,
-                     mojo::ScopedMessagePipeHandle interface_pipe,
-                     const BindInterfaceCallback& callback) override {
-    Identity target = in_target;
-    mojom::ConnectResult result =
-        ValidateConnectParams(&target, nullptr, nullptr);
-    if (!Succeeded(result)) {
-      callback.Run(result, mojom::kInheritUserID);
-      return;
-    }
+     std::unique_ptr<ConnectParams> params(new ConnectParams);
+     params->set_source(identity_);
+     params->set_target(target);
 
-    std::unique_ptr<ConnectParams> params(new ConnectParams);
-    params->set_source(identity_);
-    params->set_target(target);
-    params->set_interface_request_info(interface_name,
-                                       std::move(interface_pipe));
-    params->set_bind_interface_callback(callback);
-    service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
+     mojom::ServicePtr service;
+     service.Bind(mojom::ServicePtrInfo(std::move(service_handle), 0));
+     params->set_client_process_info(std::move(service),
+                                     std::move(pid_receiver_request));
+     params->set_start_service_callback(callback);
+     service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
   }
 
   void Clone(mojom::ConnectorRequest request) override {
@@ -533,14 +481,6 @@
       OnServiceLost(service_manager_->GetWeakPtr());
   }
 
-  void EmptyConnectCallback(mojom::ConnectResult result,
-                            const std::string& user_id) {}
-  void BindCallbackWrapper(const BindInterfaceCallback& wrapped,
-                           mojom::ConnectResult result,
-                           const std::string& user_id) {
-    wrapped.Run(result, user_id);
-  }
-
   service_manager::ServiceManager* const service_manager_;
 
   // An id that identifies this instance. Distinct from pid, as a single process
@@ -560,7 +500,7 @@
   base::ProcessId pid_ = base::kNullProcessId;
   State state_;
 
-  // The number of outstanding OnConnect requests which are in flight.
+  // The number of outstanding OnBindInterface requests which are in flight.
   int pending_service_connections_ = 0;
 
   base::WeakPtrFactory<Instance> weak_factory_;
@@ -852,14 +792,12 @@
 bool ServiceManager::ConnectToExistingInstance(
     std::unique_ptr<ConnectParams>* params) {
   Instance* instance = GetExistingInstance((*params)->target());
-  if (instance) {
-    if ((*params)->HasInterfaceRequestInfo()) {
-      instance->CallOnBindInterface(params);
-      return true;
-    }
-    return instance->CallOnConnect(params);
-  }
-  return false;
+  if (!instance)
+    return false;
+
+  if ((*params)->HasInterfaceRequestInfo())
+    instance->CallOnBindInterface(params);
+  return true;
 }
 
 ServiceManager::Instance* ServiceManager::CreateInstance(
@@ -944,7 +882,8 @@
   // If name resolution failed, we drop the connection.
   if (!result) {
     LOG(ERROR) << "Failed to resolve service name: " << params->target().name();
-    RunCallback(params.get(), mojom::ConnectResult::INVALID_ARGUMENT, "");
+    params->set_response_data(mojom::ConnectResult::INVALID_ARGUMENT,
+                              Identity());
     return;
   }
 
@@ -1011,7 +950,8 @@
       LOG(ERROR)
           << "Error: The catalog was unable to read a manifest for service \""
           << result->name << "\".";
-      RunCallback(params.get(), mojom::ConnectResult::ACCESS_DENIED, "");
+      params->set_response_data(mojom::ConnectResult::ACCESS_DENIED,
+                                Identity());
       return;
     }
 
@@ -1049,19 +989,17 @@
 
       if (!instance->StartWithFilePath(package_path)) {
         OnInstanceError(instance);
-        RunCallback(params.get(), mojom::ConnectResult::INVALID_ARGUMENT, "");
+        params->set_response_data(mojom::ConnectResult::INVALID_ARGUMENT,
+                                  Identity());
         return;
       }
     }
   }
 
-  // Now that the instance has a Service, we can connect to it.
-  if (params->HasInterfaceRequestInfo()) {
+  params->set_response_data(mojom::ConnectResult::SUCCEEDED,
+                            instance->identity());
+  if (params->HasInterfaceRequestInfo())
     instance->CallOnBindInterface(&params);
-  } else {
-    bool connected = instance->CallOnConnect(&params);
-    DCHECK(connected);
-  }
 }
 
 base::WeakPtr<ServiceManager> ServiceManager::GetWeakPtr() {
diff --git a/services/service_manager/service_manager.h b/services/service_manager/service_manager.h
index ecba992..3596d8e 100644
--- a/services/service_manager/service_manager.h
+++ b/services/service_manager/service_manager.h
@@ -188,8 +188,6 @@
   DISALLOW_COPY_AND_ASSIGN(ServiceManager);
 };
 
-mojom::Connector::ConnectCallback EmptyConnectCallback();
-
 }  // namespace service_manager
 
 #endif  // SERVICES_SERVICE_MANAGER_SERVICE_MANAGER_H_
diff --git a/services/service_manager/standalone/context.cc b/services/service_manager/standalone/context.cc
index 5b38d528..99860361 100644
--- a/services/service_manager/standalone/context.cc
+++ b/services/service_manager/standalone/context.cc
@@ -156,13 +156,9 @@
 void Context::Run(const std::string& name) {
   service_manager_->SetInstanceQuitCallback(base::Bind(&OnInstanceQuit, name));
 
-  mojom::InterfaceProviderPtr remote_interfaces;
-  mojom::InterfaceProviderPtr local_interfaces;
-
   std::unique_ptr<ConnectParams> params(new ConnectParams);
   params->set_source(CreateServiceManagerIdentity());
   params->set_target(Identity(name, mojom::kRootUserID));
-  params->set_remote_interfaces(mojo::MakeRequest(&remote_interfaces));
   service_manager_->Connect(std::move(params));
 }
 
diff --git a/services/service_manager/tests/connect/connect_test_app.cc b/services/service_manager/tests/connect/connect_test_app.cc
index ad0a26e6..6203415 100644
--- a/services/service_manager/tests/connect/connect_test_app.cc
+++ b/services/service_manager/tests/connect/connect_test_app.cc
@@ -11,9 +11,9 @@
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_runner.h"
@@ -24,8 +24,14 @@
 
 namespace {
 
-void QuitLoop(base::RunLoop* loop) {
+void QuitLoop(base::RunLoop* loop,
+              mojom::ConnectResult* out_result,
+              Identity* out_resolved_identity,
+              mojom::ConnectResult result,
+              const Identity& resolved_identity) {
   loop->Quit();
+  *out_result = result;
+  *out_resolved_identity = resolved_identity;
 }
 
 void ReceiveString(std::string* string,
@@ -61,31 +67,30 @@
     standalone_bindings_.set_connection_error_handler(
         base::Bind(&ConnectTestApp::OnConnectionError,
                    base::Unretained(this)));
+    registry_.AddInterface<test::mojom::ConnectTestService>(this);
+    registry_.AddInterface<test::mojom::StandaloneApp>(this);
+    registry_.AddInterface<test::mojom::BlockedInterface>(this);
+    registry_.AddInterface<test::mojom::UserIdTest>(this);
   }
-
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<test::mojom::ConnectTestService>(this);
-    registry->AddInterface<test::mojom::StandaloneApp>(this);
-    registry->AddInterface<test::mojom::BlockedInterface>(this);
-    registry->AddInterface<test::mojom::UserIdTest>(this);
-
-    test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
-    state->connection_remote_name = remote_info.identity.name();
-    state->connection_remote_userid = remote_info.identity.user_id();
-    state->initialize_local_name = context()->identity().name();
-    state->initialize_userid = context()->identity().user_id();
-
-    context()->connector()->BindInterface(remote_info.identity, &caller_);
-    caller_->ConnectionAccepted(std::move(state));
-
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<test::mojom::ConnectTestService>:
   void Create(const Identity& remote_identity,
               test::mojom::ConnectTestServiceRequest request) override {
     bindings_.AddBinding(this, std::move(request));
+    test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
+    state->connection_remote_name = remote_identity.name();
+    state->connection_remote_userid = remote_identity.user_id();
+    state->initialize_local_name = context()->identity().name();
+    state->initialize_userid = context()->identity().user_id();
+
+    context()->connector()->BindInterface(remote_identity, &caller_);
+    caller_->ConnectionAccepted(std::move(state));
   }
 
   // InterfaceFactory<test::mojom::StandaloneApp>:
@@ -118,13 +123,11 @@
   void ConnectToAllowedAppInBlockedPackage(
       const ConnectToAllowedAppInBlockedPackageCallback& callback) override {
     base::RunLoop run_loop;
-    std::unique_ptr<Connection> connection =
-        context()->connector()->Connect("connect_test_a");
-    connection->SetConnectionLostClosure(
-        base::Bind(&ConnectTestApp::OnConnectionBlocked,
-                   base::Unretained(this), callback, &run_loop));
     test::mojom::ConnectTestServicePtr test_service;
-    connection->GetInterface(&test_service);
+    context()->connector()->BindInterface("connect_test_a", &test_service);
+    test_service.set_connection_error_handler(
+        base::Bind(&ConnectTestApp::OnConnectionBlocked, base::Unretained(this),
+                   callback, &run_loop));
     test_service->GetTitle(
         base::Bind(&ConnectTestApp::OnGotTitle, base::Unretained(this),
                    callback, &run_loop));
@@ -138,10 +141,9 @@
   }
   void ConnectToClassInterface(
       const ConnectToClassInterfaceCallback& callback) override {
-    std::unique_ptr<Connection> connection =
-        context()->connector()->Connect("connect_test_class_app");
     test::mojom::ClassInterfacePtr class_interface;
-    connection->GetInterface(&class_interface);
+    context()->connector()->BindInterface("connect_test_class_app",
+                                          &class_interface);
     std::string ping_response;
     {
       base::RunLoop loop;
@@ -151,7 +153,7 @@
       loop.Run();
     }
     test::mojom::ConnectTestServicePtr service;
-    connection->GetInterface(&service);
+    context()->connector()->BindInterface("connect_test_class_app", &service);
     std::string title_response;
     {
       base::RunLoop loop;
@@ -172,17 +174,19 @@
   void ConnectToClassAppAsDifferentUser(
       const service_manager::Identity& target,
       const ConnectToClassAppAsDifferentUserCallback& callback) override {
-    std::unique_ptr<Connection> connection =
-        context()->connector()->Connect(target);
+    context()->connector()->StartService(target);
+    mojom::ConnectResult result;
+    Identity resolved_identity;
     {
       base::RunLoop loop;
-      connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
+      Connector::TestApi test_api(context()->connector());
+      test_api.SetStartServiceCallback(
+          base::Bind(&QuitLoop, &loop, &result, &resolved_identity));
       base::MessageLoop::ScopedNestableTaskAllower allow(
           base::MessageLoop::current());
       loop.Run();
     }
-    callback.Run(static_cast<int32_t>(connection->GetResult()),
-                 connection->GetRemoteIdentity());
+    callback.Run(static_cast<int32_t>(result), resolved_identity);
   }
 
   void OnConnectionBlocked(
@@ -205,6 +209,7 @@
       base::MessageLoop::current()->QuitWhenIdle();
   }
 
+  BinderRegistry registry_;
   mojo::BindingSet<test::mojom::ConnectTestService> bindings_;
   mojo::BindingSet<test::mojom::StandaloneApp> standalone_bindings_;
   mojo::BindingSet<test::mojom::BlockedInterface> blocked_bindings_;
diff --git a/services/service_manager/tests/connect/connect_test_class_app.cc b/services/service_manager/tests/connect/connect_test_class_app.cc
index 8e19e61..f5a26ca 100644
--- a/services/service_manager/tests/connect/connect_test_class_app.cc
+++ b/services/service_manager/tests/connect/connect_test_class_app.cc
@@ -8,11 +8,12 @@
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
 #include "services/service_manager/public/cpp/service_runner.h"
 #include "services/service_manager/public/interfaces/connector.mojom.h"
 #include "services/service_manager/tests/connect/connect_test.mojom.h"
@@ -28,31 +29,38 @@
       public test::mojom::ConnectTestService,
       public test::mojom::ClassInterface {
  public:
-  ConnectTestClassApp() {}
+  ConnectTestClassApp()
+      : ref_factory_(base::Bind(&ConnectTestClassApp::HandleQuit,
+                                base::Unretained(this))) {
+    bindings_.set_connection_error_handler(base::Bind(
+        &ConnectTestClassApp::HandleInterfaceClose, base::Unretained(this)));
+    class_interface_bindings_.set_connection_error_handler(base::Bind(
+        &ConnectTestClassApp::HandleInterfaceClose, base::Unretained(this)));
+    registry_.AddInterface<test::mojom::ConnectTestService>(this);
+    registry_.AddInterface<test::mojom::ClassInterface>(this);
+  }
   ~ConnectTestClassApp() override {}
 
  private:
   // service_manager::Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<test::mojom::ConnectTestService>(this);
-    registry->AddInterface<test::mojom::ClassInterface>(this);
-    inbound_connections_.insert(registry);
-    registry->AddConnectionLostClosure(
-        base::Bind(&ConnectTestClassApp::OnConnectionError,
-                   base::Unretained(this), registry));
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<test::mojom::ConnectTestService>:
   void Create(const Identity& remote_identity,
               test::mojom::ConnectTestServiceRequest request) override {
+    refs_.push_back(ref_factory_.CreateRef());
     bindings_.AddBinding(this, std::move(request));
   }
 
   // InterfaceFactory<test::mojom::ClassInterface>:
   void Create(const Identity& remote_identity,
               test::mojom::ClassInterfaceRequest request) override {
+    refs_.push_back(ref_factory_.CreateRef());
     class_interface_bindings_.AddBinding(this, std::move(request));
   }
 
@@ -69,17 +77,15 @@
     callback.Run("PONG");
   }
 
-  void OnConnectionError(InterfaceRegistry* registry) {
-    auto it = inbound_connections_.find(registry);
-    DCHECK(it != inbound_connections_.end());
-    inbound_connections_.erase(it);
-    if (inbound_connections_.empty())
-      context()->QuitNow();
-  }
+  void HandleQuit() { context()->QuitNow(); }
 
-  std::set<InterfaceRegistry*> inbound_connections_;
+  void HandleInterfaceClose() { refs_.pop_back(); }
+
+  BinderRegistry registry_;
   mojo::BindingSet<test::mojom::ConnectTestService> bindings_;
   mojo::BindingSet<test::mojom::ClassInterface> class_interface_bindings_;
+  ServiceContextRefFactory ref_factory_;
+  std::vector<std::unique_ptr<ServiceContextRef>> refs_;
 
   DISALLOW_COPY_AND_ASSIGN(ConnectTestClassApp);
 };
diff --git a/services/service_manager/tests/connect/connect_test_package.cc b/services/service_manager/tests/connect/connect_test_package.cc
index 974e387..2494479de 100644
--- a/services/service_manager/tests/connect/connect_test_package.cc
+++ b/services/service_manager/tests/connect/connect_test_package.cc
@@ -16,9 +16,9 @@
 #include "base/threading/simple_thread.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_runner.h"
@@ -30,6 +30,19 @@
 // the package's manifest and are thus registered with the PackageManager.
 
 namespace service_manager {
+namespace {
+
+void QuitLoop(base::RunLoop* loop,
+              mojom::ConnectResult* out_result,
+              Identity* out_resolved_identity,
+              mojom::ConnectResult result,
+              const Identity& resolved_identity) {
+  loop->Quit();
+  *out_result = result;
+  *out_resolved_identity = resolved_identity;
+}
+
+}  // namespace
 
 using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback;
 
@@ -60,30 +73,29 @@
     bindings_.set_connection_error_handler(
         base::Bind(&ProvidedService::OnConnectionError,
                    base::Unretained(this)));
+    registry_.AddInterface<test::mojom::ConnectTestService>(this);
+    registry_.AddInterface<test::mojom::BlockedInterface>(this);
+    registry_.AddInterface<test::mojom::UserIdTest>(this);
   }
-
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<test::mojom::ConnectTestService>(this);
-    registry->AddInterface<test::mojom::BlockedInterface>(this);
-    registry->AddInterface<test::mojom::UserIdTest>(this);
-
-    test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
-    state->connection_remote_name = remote_info.identity.name();
-    state->connection_remote_userid = remote_info.identity.user_id();
-    state->initialize_local_name = context()->identity().name();
-    state->initialize_userid = context()->identity().user_id();
-
-    context()->connector()->BindInterface(remote_info.identity, &caller_);
-    caller_->ConnectionAccepted(std::move(state));
-
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<test::mojom::ConnectTestService>:
   void Create(const Identity& remote_identity,
               test::mojom::ConnectTestServiceRequest request) override {
     bindings_.AddBinding(this, std::move(request));
+    test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New());
+    state->connection_remote_name = remote_identity.name();
+    state->connection_remote_userid = remote_identity.user_id();
+    state->initialize_local_name = context()->identity().name();
+    state->initialize_userid = context()->identity().user_id();
+
+    context()->connector()->BindInterface(remote_identity, &caller_);
+    caller_->ConnectionAccepted(std::move(state));
   }
 
   // InterfaceFactory<test::mojom::BlockedInterface>:
@@ -116,17 +128,19 @@
   void ConnectToClassAppAsDifferentUser(
       const service_manager::Identity& target,
       const ConnectToClassAppAsDifferentUserCallback& callback) override {
-    std::unique_ptr<Connection> connection =
-        context()->connector()->Connect(target);
+    context()->connector()->StartService(target);
+    mojom::ConnectResult result;
+    Identity resolved_identity;
     {
       base::RunLoop loop;
-      connection->AddConnectionCompletedClosure(loop.QuitClosure());
+      Connector::TestApi test_api(context()->connector());
+      test_api.SetStartServiceCallback(
+          base::Bind(&QuitLoop, &loop, &result, &resolved_identity));
       base::MessageLoop::ScopedNestableTaskAllower allow(
           base::MessageLoop::current());
       loop.Run();
     }
-    callback.Run(static_cast<int32_t>(connection->GetResult()),
-                 connection->GetRemoteIdentity());
+    callback.Run(static_cast<int32_t>(result), resolved_identity);
   }
 
   // base::SimpleThread:
@@ -147,6 +161,7 @@
   const std::string title_;
   mojom::ServiceRequest request_;
   test::mojom::ExposedInterfacePtr caller_;
+  BinderRegistry registry_;
   mojo::BindingSet<test::mojom::ConnectTestService> bindings_;
   mojo::BindingSet<test::mojom::BlockedInterface> blocked_bindings_;
   mojo::BindingSet<test::mojom::UserIdTest> user_id_test_bindings_;
@@ -172,13 +187,14 @@
                    base::Unretained(this));
     bindings_.set_connection_error_handler(error_handler);
     service_factory_bindings_.set_connection_error_handler(error_handler);
+    registry_.AddInterface<ServiceFactory>(this);
+    registry_.AddInterface<test::mojom::ConnectTestService>(this);
   }
-
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<ServiceFactory>(this);
-    registry->AddInterface<test::mojom::ConnectTestService>(this);
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   bool OnServiceManagerConnectionLost() override {
@@ -226,6 +242,7 @@
 
   std::vector<std::unique_ptr<Service>> delegates_;
   mojo::BindingSet<mojom::ServiceFactory> service_factory_bindings_;
+  BinderRegistry registry_;
   mojo::BindingSet<test::mojom::ConnectTestService> bindings_;
   std::list<std::unique_ptr<ProvidedService>> provided_services_;
 
diff --git a/services/service_manager/tests/connect/connect_test_singleton_app.cc b/services/service_manager/tests/connect/connect_test_singleton_app.cc
index b9928d3..108225c 100644
--- a/services/service_manager/tests/connect/connect_test_singleton_app.cc
+++ b/services/service_manager/tests/connect/connect_test_singleton_app.cc
@@ -15,12 +15,6 @@
   ~ConnectTestSingletonApp() override {}
 
  private:
-  // service_manager::Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    return true;
-  }
-
   DISALLOW_COPY_AND_ASSIGN(ConnectTestSingletonApp);
 };
 
diff --git a/services/service_manager/tests/connect/connect_unittest.cc b/services/service_manager/tests/connect/connect_unittest.cc
index e4f978c..c3b2abf6 100644
--- a/services/service_manager/tests/connect/connect_unittest.cc
+++ b/services/service_manager/tests/connect/connect_unittest.cc
@@ -16,8 +16,8 @@
 #include "base/run_loop.h"
 #include "base/test/test_suite.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_test.h"
 #include "services/service_manager/public/interfaces/service_manager.mojom.h"
 #include "services/service_manager/tests/connect/connect_test.mojom.h"
@@ -65,6 +65,19 @@
   loop->Quit();
 }
 
+void StartServiceResponse(base::RunLoop* quit_loop,
+                          mojom::ConnectResult* out_result,
+                          Identity* out_resolved_identity,
+                          mojom::ConnectResult result,
+                          const Identity& resolved_identity) {
+  if (quit_loop)
+    quit_loop->Quit();
+  if (out_result)
+    *out_result = result;
+  if (out_resolved_identity)
+    *out_resolved_identity = resolved_identity;
+}
+
 void QuitLoop(base::RunLoop* loop) {
   loop->Quit();
 }
@@ -79,14 +92,6 @@
   ~ConnectTest() override {}
 
  protected:
-  std::unique_ptr<Connection> ConnectTo(const Identity& target) {
-    std::unique_ptr<Connection> connection = connector()->Connect(target);
-    base::RunLoop loop;
-    connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
-    loop.Run();
-    return connection;
-  }
-
   void CompareConnectionState(
       const std::string& connection_local_name,
       const std::string& connection_remote_name,
@@ -105,18 +110,22 @@
   class TestService : public test::ServiceTestClient {
    public:
     explicit TestService(ConnectTest* connect_test)
-        : test::ServiceTestClient(connect_test),
-          connect_test_(connect_test) {}
+        : test::ServiceTestClient(connect_test), connect_test_(connect_test) {
+      registry_.AddInterface<test::mojom::ExposedInterface>(connect_test_);
+    }
     ~TestService() override {}
 
    private:
-    bool OnConnect(const ServiceInfo& remote_info,
-                   InterfaceRegistry* registry) override {
-      registry->AddInterface<test::mojom::ExposedInterface>(connect_test_);
-      return true;
+    void OnBindInterface(
+        const ServiceInfo& source_info,
+        const std::string& interface_name,
+        mojo::ScopedMessagePipeHandle interface_pipe) override {
+      registry_.BindInterface(source_info.identity, interface_name,
+                              std::move(interface_pipe));
     }
 
     ConnectTest* connect_test_;
+    BinderRegistry registry_;
 
     DISALLOW_COPY_AND_ASSIGN(TestService);
   };
@@ -129,9 +138,7 @@
     // package app's manifest and register aliases for the applications it
     // provides.
     test::mojom::ConnectTestServicePtr root_service;
-    std::unique_ptr<Connection> connection =
-        connector()->Connect(kTestPackageName);
-    connection->GetInterface(&root_service);
+    connector()->BindInterface(kTestPackageName, &root_service);
     base::RunLoop run_loop;
     std::string root_name;
     root_service->GetTitle(
@@ -161,34 +168,29 @@
 
 // Ensure the connection was properly established and that a round trip
 // method call/response is completed.
-TEST_F(ConnectTest, Connect) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppName);
+TEST_F(ConnectTest, BindInterface) {
   test::mojom::ConnectTestServicePtr service;
-  connection->GetInterface(&service);
+  connector()->BindInterface(kTestAppName, &service);
   base::RunLoop run_loop;
   std::string title;
   service->GetTitle(base::Bind(&ReceiveOneString, &title, &run_loop));
   run_loop.Run();
   EXPECT_EQ("APP", title);
-  EXPECT_FALSE(connection->IsPending());
-  EXPECT_EQ(connection->GetRemoteIdentity().name(), kTestAppName);
 }
 
 TEST_F(ConnectTest, Instances) {
   Identity identity_a(kTestAppName, mojom::kInheritUserID, "A");
-  std::unique_ptr<Connection> connection_a1 = ConnectTo(identity_a);
-  std::unique_ptr<Connection> connection_a2 = ConnectTo(identity_a);
   std::string instance_a1, instance_a2;
   test::mojom::ConnectTestServicePtr service_a1;
   {
-    connection_a1->GetInterface(&service_a1);
+    connector()->BindInterface(identity_a, &service_a1);
     base::RunLoop loop;
     service_a1->GetInstance(base::Bind(&ReceiveOneString, &instance_a1, &loop));
     loop.Run();
   }
   test::mojom::ConnectTestServicePtr service_a2;
   {
-    connection_a2->GetInterface(&service_a2);
+    connector()->BindInterface(identity_a, &service_a2);
     base::RunLoop loop;
     service_a2->GetInstance(base::Bind(&ReceiveOneString, &instance_a2, &loop));
     loop.Run();
@@ -196,11 +198,10 @@
   EXPECT_EQ(instance_a1, instance_a2);
 
   Identity identity_b(kTestAppName, mojom::kInheritUserID, "B");
-  std::unique_ptr<Connection> connection_b = ConnectTo(identity_b);
   std::string instance_b;
   test::mojom::ConnectTestServicePtr service_b;
   {
-    connection_b->GetInterface(&service_b);
+    connector()->BindInterface(identity_b, &service_b);
     base::RunLoop loop;
     service_b->GetInstance(base::Bind(&ReceiveOneString, &instance_b, &loop));
     loop.Run();
@@ -212,10 +213,9 @@
 // BlockedInterface should not be exposed to this application because it is not
 // in our CapabilityFilter whitelist.
 TEST_F(ConnectTest, BlockedInterface) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppName);
   base::RunLoop run_loop;
   test::mojom::BlockedInterfacePtr blocked;
-  connection->GetInterface(&blocked);
+  connector()->BindInterface(kTestAppName, &blocked);
   blocked.set_connection_error_handler(base::Bind(&QuitLoop, &run_loop));
   std::string title = "unchanged";
   blocked->GetTitleBlocked(base::Bind(&ReceiveOneString, &title, &run_loop));
@@ -225,16 +225,18 @@
 
 // Connects to an app provided by a package.
 TEST_F(ConnectTest, PackagedApp) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppAName);
   test::mojom::ConnectTestServicePtr service_a;
-  connection->GetInterface(&service_a);
+  connector()->BindInterface(kTestAppAName, &service_a);
+  Connector::TestApi test_api(connector());
+  Identity resolved_identity;
+  test_api.SetStartServiceCallback(
+      base::Bind(&StartServiceResponse, nullptr, nullptr, &resolved_identity));
   base::RunLoop run_loop;
   std::string a_name;
   service_a->GetTitle(base::Bind(&ReceiveOneString, &a_name, &run_loop));
   run_loop.Run();
   EXPECT_EQ("A", a_name);
-  EXPECT_FALSE(connection->IsPending());
-  EXPECT_EQ(connection->GetRemoteIdentity().name(), kTestAppAName);
+  EXPECT_EQ(resolved_identity.name(), kTestAppAName);
 }
 
 // Ask the target application to attempt to connect to a third application
@@ -243,9 +245,8 @@
 // allowed regardless of the target's CapabilityFilter with respect to the
 // package.
 TEST_F(ConnectTest, BlockedPackage) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppName);
   test::mojom::StandaloneAppPtr standalone_app;
-  connection->GetInterface(&standalone_app);
+  connector()->BindInterface(kTestAppName, &standalone_app);
   base::RunLoop run_loop;
   std::string title;
   standalone_app->ConnectToAllowedAppInBlockedPackage(
@@ -257,10 +258,9 @@
 // BlockedInterface should not be exposed to this application because it is not
 // in our CapabilityFilter whitelist.
 TEST_F(ConnectTest, PackagedApp_BlockedInterface) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppAName);
   base::RunLoop run_loop;
   test::mojom::BlockedInterfacePtr blocked;
-  connection->GetInterface(&blocked);
+  connector()->BindInterface(kTestAppAName, &blocked);
   blocked.set_connection_error_handler(base::Bind(&QuitLoop, &run_loop));
   run_loop.Run();
 }
@@ -268,20 +268,21 @@
 // Connection to another application provided by the same package, blocked
 // because it's not in the capability filter whitelist.
 TEST_F(ConnectTest, BlockedPackagedApplication) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppBName);
   test::mojom::ConnectTestServicePtr service_b;
-  connection->GetInterface(&service_b);
+  connector()->BindInterface(kTestAppBName, &service_b);
+  Connector::TestApi test_api(connector());
+  mojom::ConnectResult result;
+  test_api.SetStartServiceCallback(
+      base::Bind(&StartServiceResponse, nullptr, &result, nullptr));
   base::RunLoop run_loop;
-  connection->SetConnectionLostClosure(base::Bind(&QuitLoop, &run_loop));
+  service_b.set_connection_error_handler(run_loop.QuitClosure());
   run_loop.Run();
-  EXPECT_FALSE(connection->IsPending());
-  EXPECT_EQ(mojom::ConnectResult::ACCESS_DENIED, connection->GetResult());
+  EXPECT_EQ(mojom::ConnectResult::ACCESS_DENIED, result);
 }
 
 TEST_F(ConnectTest, CapabilityClasses) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppName);
   test::mojom::StandaloneAppPtr standalone_app;
-  connection->GetInterface(&standalone_app);
+  connector()->BindInterface(kTestAppName, &standalone_app);
   std::string string1, string2;
   base::RunLoop loop;
   standalone_app->ConnectToClassInterface(
@@ -295,19 +296,16 @@
   // We not be able to bind a ClassInterfacePtr since the connect_unittest app
   // does not explicitly request the "class" capability from
   // connect_test_class_app. This test will hang if it is bound.
-  std::unique_ptr<Connection> connection =
-      connector()->Connect(kTestClassAppName);
   test::mojom::ClassInterfacePtr class_interface;
-  connection->GetInterface(&class_interface);
+  connector()->BindInterface(kTestClassAppName, &class_interface);
   base::RunLoop loop;
   class_interface.set_connection_error_handler(base::Bind(&QuitLoop, &loop));
   loop.Run();
 }
 
 TEST_F(ConnectTest, ConnectAsDifferentUser_Allowed) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppName);
   test::mojom::UserIdTestPtr user_id_test;
-  connection->GetInterface(&user_id_test);
+  connector()->BindInterface(kTestAppName, &user_id_test);
   mojom::ConnectResult result;
   Identity target(kTestClassAppName, base::GenerateGUID());
   Identity result_identity;
@@ -323,9 +321,8 @@
 }
 
 TEST_F(ConnectTest, ConnectAsDifferentUser_Blocked) {
-  std::unique_ptr<Connection> connection = connector()->Connect(kTestAppAName);
   test::mojom::UserIdTestPtr user_id_test;
-  connection->GetInterface(&user_id_test);
+  connector()->BindInterface(kTestAppAName, &user_id_test);
   mojom::ConnectResult result;
   Identity target(kTestClassAppName, base::GenerateGUID());
   Identity result_identity;
@@ -345,7 +342,7 @@
 // process specifications. This is the only one for blocking.
 TEST_F(ConnectTest, ConnectToClientProcess_Blocked) {
   base::Process process;
-  std::unique_ptr<service_manager::Connection> connection =
+  mojom::ConnectResult result =
       service_manager::test::LaunchAndConnectToProcess(
 #if defined(OS_WIN)
           "connect_test_exe.exe",
@@ -355,7 +352,7 @@
           service_manager::Identity("connect_test_exe",
                                     service_manager::mojom::kInheritUserID),
           connector(), &process);
-  EXPECT_EQ(connection->GetResult(), mojom::ConnectResult::ACCESS_DENIED);
+  EXPECT_EQ(result, mojom::ConnectResult::ACCESS_DENIED);
 }
 
 // Verifies that a client with the "all_users" capability class can receive
@@ -367,25 +364,28 @@
   // synthetic user id for all-user singleton instances).
   const std::string singleton_userid = base::GenerateGUID();
   Identity singleton_id(kTestSingletonAppName, singleton_userid);
-  std::unique_ptr<Connection> connection = connector()->Connect(singleton_id);
+  connector()->StartService(singleton_id);
+  Identity first_resolved_identity;
   {
     base::RunLoop loop;
-    connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
+    Connector::TestApi test_api(connector());
+    test_api.SetStartServiceCallback(base::Bind(
+        &StartServiceResponse, &loop, nullptr, &first_resolved_identity));
     loop.Run();
-    EXPECT_NE(connection->GetRemoteIdentity().user_id(), singleton_userid);
+    EXPECT_NE(first_resolved_identity.user_id(), singleton_userid);
   }
   // This connects using the current client's user_id. It should be bound to the
   // same service started above, with the same service manager-generated user
   // id.
-  std::unique_ptr<Connection> inherit_connection =
-      connector()->Connect(kTestSingletonAppName);
+  connector()->StartService(kTestSingletonAppName);
   {
     base::RunLoop loop;
-    inherit_connection->AddConnectionCompletedClosure(
-        base::Bind(&QuitLoop, &loop));
+    Connector::TestApi test_api(connector());
+    Identity resolved_identity;
+    test_api.SetStartServiceCallback(
+        base::Bind(&StartServiceResponse, &loop, nullptr, &resolved_identity));
     loop.Run();
-    EXPECT_EQ(inherit_connection->GetRemoteIdentity().user_id(),
-              connection->GetRemoteIdentity().user_id());
+    EXPECT_EQ(resolved_identity.user_id(), first_resolved_identity.user_id());
   }
 }
 
diff --git a/services/service_manager/tests/lifecycle/app_client.cc b/services/service_manager/tests/lifecycle/app_client.cc
index 5e9467e..1ec9b3b 100644
--- a/services/service_manager/tests/lifecycle/app_client.cc
+++ b/services/service_manager/tests/lifecycle/app_client.cc
@@ -5,20 +5,22 @@
 #include "services/service_manager/tests/lifecycle/app_client.h"
 
 #include "base/macros.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
 
 namespace service_manager {
 namespace test {
 
-AppClient::AppClient() {}
+AppClient::AppClient() {
+  registry_.AddInterface<mojom::LifecycleControl>(this);
+}
 
 AppClient::~AppClient() {}
 
-bool AppClient::OnConnect(const ServiceInfo& remote_info,
-                          InterfaceRegistry* registry) {
-  registry->AddInterface<mojom::LifecycleControl>(this);
-  return true;
+void AppClient::OnBindInterface(const ServiceInfo& source_info,
+                                const std::string& interface_name,
+                                mojo::ScopedMessagePipeHandle interface_pipe) {
+  registry_.BindInterface(source_info.identity, interface_name,
+                          std::move(interface_pipe));
 }
 
 bool AppClient::OnServiceManagerConnectionLost() {
diff --git a/services/service_manager/tests/lifecycle/app_client.h b/services/service_manager/tests/lifecycle/app_client.h
index 9d8baad..34100bf 100644
--- a/services/service_manager/tests/lifecycle/app_client.h
+++ b/services/service_manager/tests/lifecycle/app_client.h
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_runner.h"
@@ -29,8 +30,9 @@
   void set_runner(ServiceRunner* runner) { runner_ = runner; }
 
   // Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override;
   bool OnServiceManagerConnectionLost() override;
 
   // InterfaceFactory<LifecycleControl>:
@@ -49,6 +51,7 @@
   void BindingLost();
 
   ServiceRunner* runner_ = nullptr;
+  BinderRegistry registry_;
   mojo::BindingSet<mojom::LifecycleControl> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(AppClient);
diff --git a/services/service_manager/tests/service_manager/service_manager_unittest.cc b/services/service_manager/tests/service_manager/service_manager_unittest.cc
index 08b3e94..bf79e683 100644
--- a/services/service_manager/tests/service_manager/service_manager_unittest.cc
+++ b/services/service_manager/tests/service_manager/service_manager_unittest.cc
@@ -24,8 +24,8 @@
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_test.h"
 #include "services/service_manager/public/interfaces/constants.mojom.h"
@@ -43,7 +43,9 @@
       public test::mojom::CreateInstanceTest {
  public:
   explicit ServiceManagerTestClient(test::ServiceTest* test)
-      : test::ServiceTestClient(test), binding_(this) {}
+      : test::ServiceTestClient(test), binding_(this) {
+    registry_.AddInterface<test::mojom::CreateInstanceTest>(this);
+  }
   ~ServiceManagerTestClient() override {}
 
   const Identity& target_identity() const { return target_identity_; }
@@ -55,10 +57,11 @@
 
  private:
   // test::ServiceTestClient:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<test::mojom::CreateInstanceTest>(this);
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<test::mojom::CreateInstanceTest>:
@@ -79,6 +82,7 @@
   service_manager::Identity target_identity_;
   std::unique_ptr<base::RunLoop> wait_for_target_identity_loop_;
 
+  BinderRegistry registry_;
   mojo::Binding<test::mojom::CreateInstanceTest> binding_;
 
   DISALLOW_COPY_AND_ASSIGN(ServiceManagerTestClient);
@@ -187,11 +191,9 @@
                                      service_manager::mojom::kInheritUserID);
     connector()->StartService(target, std::move(client),
                               MakeRequest(&receiver));
-    std::unique_ptr<service_manager::Connection> connection =
-        connector()->Connect(target);
-    connection->AddConnectionCompletedClosure(
-        base::Bind(&ServiceManagerTest::OnConnectionCompleted,
-                   base::Unretained(this)));
+    Connector::TestApi test_api(connector());
+    test_api.SetStartServiceCallback(base::Bind(
+        &ServiceManagerTest::OnConnectionCompleted, base::Unretained(this)));
 
     base::LaunchOptions options;
 #if defined(OS_WIN)
@@ -255,7 +257,7 @@
     }
   }
 
-  void OnConnectionCompleted() {}
+  void OnConnectionCompleted(mojom::ConnectResult, const Identity&) {}
 
   ServiceManagerTestClient* service_;
   mojo::Binding<mojom::ServiceManagerListener> binding_;
@@ -333,11 +335,9 @@
         &OnServiceFailedToStartCallback,
         &failed_to_start, loop.QuitClosure()));
 
-    std::unique_ptr<Connection> embedder_connection =
-        connector()->Connect("service_manager_unittest_embedder");
+    connector()->StartService("service_manager_unittest_embedder");
     loop.Run();
     EXPECT_FALSE(failed_to_start);
-    EXPECT_FALSE(embedder_connection->IsPending());
     EXPECT_EQ(1, start_count);
     EXPECT_EQ("service_manager_unittest_embedder", service_name);
   }
@@ -355,11 +355,9 @@
         &failed_to_start, loop.QuitClosure()));
 
     // Connect to the packaged singleton service.
-    std::unique_ptr<Connection> singleton_connection =
-        connector()->Connect("service_manager_unittest_singleton");
+    connector()->StartService("service_manager_unittest_singleton");
     loop.Run();
     EXPECT_FALSE(failed_to_start);
-    EXPECT_FALSE(singleton_connection->IsPending());
     EXPECT_EQ(1, start_count);
     EXPECT_EQ("service_manager_unittest_singleton", service_name);
   }
diff --git a/services/service_manager/tests/service_manager/target.cc b/services/service_manager/tests/service_manager/target.cc
index bbfd5e7..509c893 100644
--- a/services/service_manager/tests/service_manager/target.cc
+++ b/services/service_manager/tests/service_manager/target.cc
@@ -7,7 +7,6 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "services/service_manager/public/c/main.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
diff --git a/services/service_manager/tests/shutdown/shutdown_client_app.cc b/services/service_manager/tests/shutdown/shutdown_client_app.cc
index 9dd6942..bdac97a8 100644
--- a/services/service_manager/tests/shutdown/shutdown_client_app.cc
+++ b/services/service_manager/tests/shutdown/shutdown_client_app.cc
@@ -6,9 +6,9 @@
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
 #include "services/service_manager/public/cpp/service_context.h"
 #include "services/service_manager/public/cpp/service_runner.h"
@@ -22,15 +22,18 @@
       public mojom::ShutdownTestClientController,
       public mojom::ShutdownTestClient {
  public:
-  ShutdownClientApp() {}
+  ShutdownClientApp() {
+    registry_.AddInterface<mojom::ShutdownTestClientController>(this);
+  }
   ~ShutdownClientApp() override {}
 
  private:
   // service_manager::Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<mojom::ShutdownTestClientController>(this);
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<mojom::ShutdownTestClientController>:
@@ -60,6 +63,7 @@
     callback.Run();
   }
 
+  BinderRegistry registry_;
   mojo::BindingSet<mojom::ShutdownTestClientController> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(ShutdownClientApp);
diff --git a/services/service_manager/tests/shutdown/shutdown_service_app.cc b/services/service_manager/tests/shutdown/shutdown_service_app.cc
index 95134f7..1e1c8c7 100644
--- a/services/service_manager/tests/shutdown/shutdown_service_app.cc
+++ b/services/service_manager/tests/shutdown/shutdown_service_app.cc
@@ -5,9 +5,10 @@
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_info.h"
 #include "services/service_manager/public/cpp/service_runner.h"
 #include "services/service_manager/tests/shutdown/shutdown_unittest.mojom.h"
 
@@ -21,15 +22,18 @@
       public InterfaceFactory<mojom::ShutdownTestService>,
       public mojom::ShutdownTestService {
  public:
-  ShutdownServiceApp() {}
+  ShutdownServiceApp() {
+    registry_.AddInterface<mojom::ShutdownTestService>(this);
+  }
   ~ShutdownServiceApp() override {}
 
  private:
   // service_manager::Service:
-  bool OnConnect(const ServiceInfo& remote_info,
-                 InterfaceRegistry* registry) override {
-    registry->AddInterface<mojom::ShutdownTestService>(this);
-    return true;
+  void OnBindInterface(const ServiceInfo& source_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override {
+    registry_.BindInterface(source_info.identity, interface_name,
+                            std::move(interface_pipe));
   }
 
   // InterfaceFactory<mojom::ShutdownTestService>:
@@ -42,6 +46,7 @@
   void SetClient(mojom::ShutdownTestClientPtr client) override {}
   void ShutDown() override { g_app->Quit(); }
 
+  BinderRegistry registry_;
   mojo::BindingSet<mojom::ShutdownTestService> bindings_;
 
   DISALLOW_COPY_AND_ASSIGN(ShutdownServiceApp);
diff --git a/services/service_manager/tests/util.cc b/services/service_manager/tests/util.cc
index 081ce6c..b881f17 100644
--- a/services/service_manager/tests/util.cc
+++ b/services/service_manager/tests/util.cc
@@ -17,7 +17,6 @@
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/interfaces/connector.mojom.h"
 #include "services/service_manager/public/interfaces/service_factory.mojom.h"
@@ -28,13 +27,17 @@
 
 namespace {
 
-void QuitLoop(base::RunLoop* loop) {
+void GrabConnectResult(base::RunLoop* loop,
+                       mojom::ConnectResult* out_result,
+                       mojom::ConnectResult result,
+                       const Identity& resolved_identity) {
   loop->Quit();
+  *out_result = result;
 }
 
 }  // namespace
 
-std::unique_ptr<Connection> LaunchAndConnectToProcess(
+mojom::ConnectResult LaunchAndConnectToProcess(
     const std::string& target_exe_name,
     const Identity& target,
     service_manager::Connector* connector,
@@ -70,11 +73,12 @@
   service_manager::mojom::PIDReceiverPtr receiver;
 
   connector->StartService(target, std::move(client), MakeRequest(&receiver));
-  std::unique_ptr<service_manager::Connection> connection =
-      connector->Connect(target);
+  mojom::ConnectResult result;
   {
     base::RunLoop loop;
-    connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop));
+    Connector::TestApi test_api(connector);
+    test_api.SetStartServiceCallback(
+        base::Bind(&GrabConnectResult, &loop, &result));
     base::MessageLoop::ScopedNestableTaskAllower allow(
         base::MessageLoop::current());
     loop.Run();
@@ -92,7 +96,7 @@
   pending_process.Connect(
       process->Handle(),
       mojo::edk::ConnectionParams(platform_channel_pair.PassServerHandle()));
-  return connection;
+  return result;
 }
 
 }  // namespace test
diff --git a/services/service_manager/tests/util.h b/services/service_manager/tests/util.h
index 6fe6bc3..e11c18b 100644
--- a/services/service_manager/tests/util.h
+++ b/services/service_manager/tests/util.h
@@ -8,22 +8,23 @@
 #include <memory>
 #include <string>
 
+#include "services/service_manager/public/interfaces/connector.mojom.h"
+
 namespace base {
 class Process;
 }
 
 namespace service_manager {
-class Connection;
 class Connector;
 class Identity;
 
 namespace test {
 
 // Starts the process @ |target_exe_name| and connects to it as |target| using
-// |connector|, returning the connection & the process.
+// |connector|, returning a ConnectResult for the StartService() call.
 // This blocks until the connection is established/rejected by the service
 // manager.
-std::unique_ptr<Connection> LaunchAndConnectToProcess(
+service_manager::mojom::ConnectResult LaunchAndConnectToProcess(
     const std::string& target_exe_name,
     const Identity& target,
     service_manager::Connector* connector,
diff --git a/services/tracing/public/cpp/provider.cc b/services/tracing/public/cpp/provider.cc
index 12e27bbb..c89aed2 100644
--- a/services/tracing/public/cpp/provider.cc
+++ b/services/tracing/public/cpp/provider.cc
@@ -17,7 +17,6 @@
 #include "base/time/time.h"
 #include "base/trace_event/trace_config.h"
 #include "base/trace_event/trace_event.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/tracing/public/cpp/switches.h"
 #include "services/tracing/public/interfaces/constants.mojom.h"
diff --git a/services/ui/demo/mus_demo_unittests.cc b/services/ui/demo/mus_demo_unittests.cc
index 9fdb810..e89c167f 100644
--- a/services/ui/demo/mus_demo_unittests.cc
+++ b/services/ui/demo/mus_demo_unittests.cc
@@ -40,7 +40,7 @@
 }  // namespace
 
 TEST_F(MusDemoTest, CheckMusDemoDraws) {
-  connector()->Connect("mus_demo");
+  connector()->StartService("mus_demo");
 
   ::ui::mojom::WindowServerTestPtr test_interface;
   connector()->BindInterface(ui::mojom::kServiceName, &test_interface);
diff --git a/services/ui/display/output_protection.h b/services/ui/display/output_protection.h
index 48185289..eafd2cb 100644
--- a/services/ui/display/output_protection.h
+++ b/services/ui/display/output_protection.h
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "base/macros.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/ui/public/interfaces/display/output_protection.mojom.h"
 
diff --git a/services/ui/display/screen_manager_ozone_internal.h b/services/ui/display/screen_manager_ozone_internal.h
index 7032bdbb..61c9920 100644
--- a/services/ui/display/screen_manager_ozone_internal.h
+++ b/services/ui/display/screen_manager_ozone_internal.h
@@ -11,7 +11,6 @@
 
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/ui/display/screen_manager.h"
 #include "services/ui/display/viewport_metrics.h"
diff --git a/services/ui/ime/ime_server_impl.cc b/services/ui/ime/ime_server_impl.cc
index 19c89b5b..7d26f0e 100644
--- a/services/ui/ime/ime_server_impl.cc
+++ b/services/ui/ime/ime_server_impl.cc
@@ -17,7 +17,7 @@
 void IMEServerImpl::Init(service_manager::Connector* connector,
                          bool is_test_config) {
   if (is_test_config)
-    connector->Connect("test_ime_driver");
+    connector->StartService("test_ime_driver");
   // For non test configs we assume a client registers with us.
 }
 
diff --git a/services/ui/ime/ime_unittest.cc b/services/ui/ime/ime_unittest.cc
index 582521f..f33275a6 100644
--- a/services/ui/ime/ime_unittest.cc
+++ b/services/ui/ime/ime_unittest.cc
@@ -56,7 +56,7 @@
   void SetUp() override {
     ServiceTest::SetUp();
     // test_ime_driver will register itself as the current IMEDriver.
-    connector()->Connect("test_ime_driver");
+    connector()->StartService("test_ime_driver");
     connector()->BindInterface(ui::mojom::kServiceName, &ime_server_);
   }
 
diff --git a/services/ui/input_devices/input_device_server.h b/services/ui/input_devices/input_device_server.h
index 0e858b4..1e7d91c 100644
--- a/services/ui/input_devices/input_device_server.h
+++ b/services/ui/input_devices/input_device_server.h
@@ -8,7 +8,6 @@
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/interface_factory.h"
 #include "services/ui/public/interfaces/input_devices/input_device_server.mojom.h"
 #include "ui/events/devices/device_data_manager.h"
diff --git a/services/ui/service.cc b/services/ui/service.cc
index aa4aa441..b7ff9691 100644
--- a/services/ui/service.cc
+++ b/services/ui/service.cc
@@ -18,7 +18,6 @@
 #include "services/catalog/public/cpp/resource_loader.h"
 #include "services/catalog/public/interfaces/constants.mojom.h"
 #include "services/service_manager/public/c/main.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/interface_registry.h"
 #include "services/service_manager/public/cpp/service_context.h"
@@ -58,7 +57,6 @@
 #include "ui/ozone/public/ozone_platform.h"
 #endif
 
-using service_manager::Connection;
 using mojo::InterfaceRequest;
 using ui::mojom::WindowServerTest;
 using ui::mojom::WindowTreeHostFactory;
diff --git a/services/ui/ws/drag_controller_unittest.cc b/services/ui/ws/drag_controller_unittest.cc
index 4714ebea8..7bc192c0 100644
--- a/services/ui/ws/drag_controller_unittest.cc
+++ b/services/ui/ws/drag_controller_unittest.cc
@@ -155,7 +155,7 @@
     window->PerformOnDragDropStart(
         std::unordered_map<std::string, std::vector<uint8_t>>());
     drag_operation_ = base::MakeUnique<DragController>(
-        this, this, window->window(), window, PointerEvent::kMousePointerId,
+        this, this, window->window(), window, MouseEvent::kMousePointerId,
         std::unordered_map<std::string, std::vector<uint8_t>>(),
         drag_operations);
 
@@ -627,7 +627,7 @@
 
 TEST_F(DragControllerTest, IgnoreEventsFromOtherPointers) {
   std::unique_ptr<DragTestWindow> window = BuildWindow();
-  // This starts the operation with PointerEvent::kMousePointerId.
+  // This starts the operation with MouseEvent::kMousePointerId.
   StartDragOperation(window.get(), ui::mojom::kDropEffectMove);
 
   // Ignore events from pointer 5.
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index 670e9977..a4710df 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -466,7 +466,7 @@
         ui::ET_POINTER_EXITED, event.location(), event.root_location(),
         event.flags(), 0 /* changed_button_flags */,
         ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE,
-                           ui::PointerEvent::kMousePointerId),
+                           ui::MouseEvent::kMousePointerId),
         event.time_stamp());
     DispatchToPointerTarget(pointer_targets_[pointer_id], exit_event);
   }
diff --git a/services/ui/ws/gpu_host.cc b/services/ui/ws/gpu_host.cc
index db35498e..85ac3aa 100644
--- a/services/ui/ws/gpu_host.cc
+++ b/services/ui/ws/gpu_host.cc
@@ -14,7 +14,6 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "mojo/public/cpp/system/platform_handle.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/ui/common/server_gpu_memory_buffer_manager.h"
 #include "services/ui/ws/gpu_client.h"
 #include "services/ui/ws/gpu_host_delegate.h"
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc
index d7bad78..66d1e915 100644
--- a/services/ui/ws/window_manager_state.cc
+++ b/services/ui/ws/window_manager_state.cc
@@ -184,7 +184,7 @@
     DragTargetConnection* source_connection,
     const std::unordered_map<std::string, std::vector<uint8_t>>& drag_data,
     uint32_t drag_operation) {
-  int32_t drag_pointer = PointerEvent::kMousePointerId;
+  int32_t drag_pointer = MouseEvent::kMousePointerId;
   if (in_flight_event_details_ &&
       in_flight_event_details_->event->IsPointerEvent()) {
     drag_pointer =
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index b47276b..d012b886 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -10,7 +10,6 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/ui/ws/display.h"
 #include "services/ui/ws/display_manager.h"
 #include "services/ui/ws/frame_generator.h"
diff --git a/services/ui/ws/window_server_service_test_base.h b/services/ui/ws/window_server_service_test_base.h
index e6be41d..8cff44c 100644
--- a/services/ui/ws/window_server_service_test_base.h
+++ b/services/ui/ws/window_server_service_test_base.h
@@ -6,7 +6,6 @@
 #define SERVICES_UI_WS_WINDOW_SERVER_SERVICE_TEST_BASE_H_
 
 #include "base/macros.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/service_test.h"
 
 namespace ui {
diff --git a/services/ui/ws/window_tree_client_unittest.cc b/services/ui/ws/window_tree_client_unittest.cc
index d70250c..06f6762 100644
--- a/services/ui/ws/window_tree_client_unittest.cc
+++ b/services/ui/ws/window_tree_client_unittest.cc
@@ -24,7 +24,6 @@
 #include "services/ui/ws/test_change_tracker.h"
 #include "services/ui/ws/window_server_service_test_base.h"
 
-using service_manager::Connection;
 using mojo::InterfaceRequest;
 using service_manager::Service;
 using ui::mojom::WindowDataPtr;
diff --git a/sql/recovery.cc b/sql/recovery.cc
index a805c520..64eefa5 100644
--- a/sql/recovery.cc
+++ b/sql/recovery.cc
@@ -126,6 +126,9 @@
   // successfully deleted.
   RECOVERY_SUCCESS_AUTORECOVERDB_NOTADB_DELETE,
 
+  // Failed to find required [meta.version] information.
+  RECOVERY_FAILED_AUTORECOVERDB_META_VERSION,
+
   // Add new items before this one, always keep this one at the end.
   RECOVERY_EVENT_MAX,
 };
@@ -602,8 +605,9 @@
 // results indicate that everything is working reasonably.
 //
 // static
-void Recovery::RecoverDatabase(Connection* db,
-                               const base::FilePath& db_path) {
+std::unique_ptr<Recovery> Recovery::BeginRecoverDatabase(
+    Connection* db,
+    const base::FilePath& db_path) {
   std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path);
   if (!recovery) {
     // Close the underlying sqlite* handle.  Windows does not allow deleting
@@ -620,7 +624,7 @@
           probe_db.AttachDatabase(db_path, "corrupt") ||
           probe_db.GetErrorCode() != SQLITE_NOTADB) {
         RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_BEGIN);
-        return;
+        return nullptr;
       }
     }
 
@@ -629,7 +633,7 @@
     // recoverable _with_ manual intervention).  Clear away the broken database.
     if (!sql::Connection::Delete(db_path)) {
       RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_DELETE);
-      return;
+      return nullptr;
     }
 
     // Windows deletion is complicated by file scanners and malware - sometimes
@@ -639,18 +643,18 @@
       Connection probe_db;
       if (!probe_db.Open(db_path)) {
         RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_REOPEN);
-        return;
+        return nullptr;
       }
       if (!probe_db.Execute("PRAGMA auto_vacuum")) {
         RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NOTADB_QUERY);
-        return;
+        return nullptr;
       }
     }
 
     // The rest of the recovery code could be run on the re-opened database, but
     // the database is empty, so there would be no point.
     RecordRecoveryEvent(RECOVERY_SUCCESS_AUTORECOVERDB_NOTADB_DELETE);
-    return;
+    return nullptr;
   }
 
 #if DCHECK_IS_ON()
@@ -682,7 +686,7 @@
       !SchemaCopyHelper(recovery->db(), "CREATE UNIQUE INDEX ")) {
     // No RecordRecoveryEvent() here because SchemaCopyHelper() already did.
     Recovery::Rollback(std::move(recovery));
-    return;
+    return nullptr;
   }
 
   // Run auto-recover against each table, skipping the sequence table.  This is
@@ -698,13 +702,13 @@
       if (!recovery->AutoRecoverTable(name.c_str(), &rows_recovered)) {
         RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_TABLE);
         Recovery::Rollback(std::move(recovery));
-        return;
+        return nullptr;
       }
     }
     if (!s.Succeeded()) {
       RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_NAMESELECT);
       Recovery::Rollback(std::move(recovery));
-      return;
+      return nullptr;
     }
   }
 
@@ -715,7 +719,7 @@
     if (!recovery->AutoRecoverTable("sqlite_sequence", &rows_recovered)) {
       RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_SEQUENCE);
       Recovery::Rollback(std::move(recovery));
-      return;
+      return nullptr;
     }
   }
 
@@ -728,10 +732,37 @@
   if (!recovery->db()->Execute(kCreateMetaItems)) {
     RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_AUX);
     Recovery::Rollback(std::move(recovery));
-    return;
+    return nullptr;
   }
 
   RecordRecoveryEvent(RECOVERY_SUCCESS_AUTORECOVERDB);
+  return recovery;
+}
+
+void Recovery::RecoverDatabase(Connection* db, const base::FilePath& db_path) {
+  std::unique_ptr<sql::Recovery> recovery = BeginRecoverDatabase(db, db_path);
+
+  // ignore_result() because BeginRecoverDatabase() and Recovered() already
+  // provide suitable histogram coverage.
+  if (recovery)
+    ignore_result(Recovery::Recovered(std::move(recovery)));
+}
+
+void Recovery::RecoverDatabaseWithMetaVersion(Connection* db,
+                                              const base::FilePath& db_path) {
+  std::unique_ptr<sql::Recovery> recovery = BeginRecoverDatabase(db, db_path);
+  if (!recovery)
+    return;
+
+  int version = 0;
+  if (!recovery->SetupMeta() || !recovery->GetMetaVersionNumber(&version)) {
+    sql::Recovery::Unrecoverable(std::move(recovery));
+    RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVERDB_META_VERSION);
+    return;
+  }
+
+  // ignore_result() because BeginRecoverDatabase() and Recovered() already
+  // provide suitable histogram coverage.
   ignore_result(Recovery::Recovered(std::move(recovery)));
 }
 
diff --git a/sql/recovery.h b/sql/recovery.h
index efc69cbc..e5e4abf8 100644
--- a/sql/recovery.h
+++ b/sql/recovery.h
@@ -156,18 +156,28 @@
   bool GetMetaVersionNumber(int* version_number);
 
   // Attempt to recover the database by creating a new database with schema from
-  // |db|, then copying over as much data as possible.  After this call, the
-  // |db| handle will be poisoned (though technically remaining open) so that
-  // future calls will return errors until the handle is re-opened.
-  //
-  // If a corrupt database contains tables without unique indices, the resulting
-  // table may contain duplication.  If this is not acceptable, the client
-  // should use the manual process as described in the example at the top of the
-  // file, cleaning up data at the appropriate points.
+  // |db|, then copying over as much data as possible.  If successful, the
+  // recovery handle is returned to allow the caller to make additional changes,
+  // such as validating constraints not expressed in the schema.
   //
   // In case of SQLITE_NOTADB, the database is deemed unrecoverable and deleted.
+  static std::unique_ptr<Recovery> BeginRecoverDatabase(
+      Connection* db,
+      const base::FilePath& db_path) WARN_UNUSED_RESULT;
+
+  // Call BeginRecoverDatabase() to recover the database, then commit the
+  // changes using Recovered().  After this call, the |db| handle will be
+  // poisoned (though technically remaining open) so that future calls will
+  // return errors until the handle is re-opened.
   static void RecoverDatabase(Connection* db, const base::FilePath& db_path);
 
+  // Variant on RecoverDatabase() which requires that the database have a valid
+  // meta table with a version value.  The meta version value is used by some
+  // clients to make assertions about the database schema.  If this information
+  // cannot be determined, the database is considered unrecoverable.
+  static void RecoverDatabaseWithMetaVersion(Connection* db,
+                                             const base::FilePath& db_path);
+
   // Returns true for SQLite errors which RecoverDatabase() can plausibly fix.
   // This does not guarantee that RecoverDatabase() will successfully recover
   // the database.
diff --git a/sql/recovery_unittest.cc b/sql/recovery_unittest.cc
index 111a610..75268822 100644
--- a/sql/recovery_unittest.cc
+++ b/sql/recovery_unittest.cc
@@ -834,6 +834,54 @@
   EXPECT_EQ("", GetSchema(&db()));
 }
 
+// Allow callers to validate the database between recovery and commit.
+TEST_F(SQLRecoveryTest, BeginRecoverDatabase) {
+  // Create a table with a broken index.
+  ASSERT_TRUE(db().Execute("CREATE TABLE t (id INTEGER PRIMARY KEY, c TEXT)"));
+  ASSERT_TRUE(db().Execute("CREATE UNIQUE INDEX t_id ON t (id)"));
+  ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (1, 'hello world')"));
+  ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (2, 'testing')"));
+  ASSERT_TRUE(db().Execute("INSERT INTO t VALUES (3, 'nope')"));
+
+  // Inject corruption into the index.
+  db().Close();
+  const char kDeleteSql[] = "DELETE FROM t WHERE id = 3";
+  ASSERT_TRUE(sql::test::CorruptTableOrIndex(db_path(), "t_id", kDeleteSql));
+  ASSERT_TRUE(Reopen());
+
+  // id as read from index.
+  const char kSelectIndexIdSql[] = "SELECT id FROM t INDEXED BY t_id";
+  EXPECT_EQ("1,2,3", ExecuteWithResults(&db(), kSelectIndexIdSql, "|", ","));
+
+  // id as read from table.
+  const char kSelectTableIdSql[] = "SELECT id FROM t NOT INDEXED";
+  EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectTableIdSql, "|", ","));
+
+  // Run recovery code, then rollback.  Database remains the same.
+  {
+    std::unique_ptr<sql::Recovery> recovery =
+        sql::Recovery::BeginRecoverDatabase(&db(), db_path());
+    ASSERT_TRUE(recovery);
+    sql::Recovery::Rollback(std::move(recovery));
+  }
+  db().Close();
+  ASSERT_TRUE(Reopen());
+  EXPECT_EQ("1,2,3", ExecuteWithResults(&db(), kSelectIndexIdSql, "|", ","));
+  EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectTableIdSql, "|", ","));
+
+  // Run recovery code, then commit.  The failing row is dropped.
+  {
+    std::unique_ptr<sql::Recovery> recovery =
+        sql::Recovery::BeginRecoverDatabase(&db(), db_path());
+    ASSERT_TRUE(recovery);
+    ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
+  }
+  db().Close();
+  ASSERT_TRUE(Reopen());
+  EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectIndexIdSql, "|", ","));
+  EXPECT_EQ("1,2", ExecuteWithResults(&db(), kSelectTableIdSql, "|", ","));
+}
+
 // Test histograms recorded when the invalid database cannot be attached.
 TEST_F(SQLRecoveryTest, AttachFailure) {
   // Create a valid database, then write junk over the header.  This should lead
diff --git a/storage/browser/database/OWNERS b/storage/browser/database/OWNERS
new file mode 100644
index 0000000..07618c5
--- /dev/null
+++ b/storage/browser/database/OWNERS
@@ -0,0 +1,4 @@
+pwnall@chromium.org
+
+# TEAM: storage-dev@chromium.org
+# COMPONENT: Blink>Storage>WebSQL
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 055ecb5..c84463e 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1495,6 +1495,10 @@
 crbug.com/521124 crbug.com/410145 [ Win7 ] fast/css/font-weight-1.html [ Pass Failure ]
 crbug.com/521124 crbug.com/410145 [ Win7 ] virtual/sharedarraybuffer/fast/css/font-weight-1.html [ Pass Failure ]
 
+crbug.com/710946 inspector-protocol/runtime/runtime-callFunctionOn-async.html [ NeedsManualRebaseline ]
+crbug.com/710946 inspector-protocol/runtime/runtime-evaluate-async.html [ NeedsManualRebaseline ]
+crbug.com/710946 inspector-protocol/runtime/runtime-runScript-async.html [ NeedsManualRebaseline ]
+
 # Temporary, until we stop use_system_harfbuzz on Linux including non-official builds
 crbug.com/462689 [ Linux ] fast/text/unicode-variation-selector.html [ Failure ]
 
@@ -1872,6 +1876,7 @@
 crbug.com/710226 [ Win Mac10.9 Mac10.10 Mac10.11 Mac10.12 ] external/wpt/cssom-view/MediaQueryList-001.html [ Failure ]
 
 # ====== New tests from wpt-importer added here ======
+crbug.com/626703 external/wpt/css/selectors4/focus-within-shadow-006.html [ Failure ]
 crbug.com/626703 [ Android Linux Win ] external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/flexbox/flexbox-baseline-multi-item-vert-001b.html [ Failure ]
 crbug.com/626703 external/wpt/cssom-view/matchMedia.xht [ Timeout ]
 crbug.com/626703 external/wpt/css/css-display-3/display-contents-dynamic-before-after-001.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 9c54a29e..104475c 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -27055,6 +27055,18 @@
      {}
     ]
    ],
+   "css/selectors4/focus-within-shadow-006.html": [
+    [
+     "/css/selectors4/focus-within-shadow-006.html",
+     [
+      [
+       "/css/selectors4/focus-within-shadow-001-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/selectors4/of-type-selectors.xhtml": [
     [
      "/css/selectors4/of-type-selectors.xhtml",
@@ -38598,6 +38610,96 @@
      {}
     ]
    ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-none-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-self-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "content-security-policy/frame-ancestors/frame-ancestors-url-block-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "content-security-policy/frame-ancestors/support/frame-ancestors-and-x-frame-options.sub.html": [
     [
      {}
@@ -49733,11 +49835,31 @@
      {}
     ]
    ],
+   "cssom-view/cssom-getBoundingClientRect-002-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom-view/cssom-view/media-query-list-interface-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom-view/cssom-view/window-interface-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cssom-view/elementFromPoint-expected.txt": [
     [
      {}
     ]
    ],
+   "cssom-view/elementFromPosition-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cssom-view/elementsFromPoint-expected.txt": [
     [
      {}
@@ -49748,6 +49870,11 @@
      {}
     ]
    ],
+   "cssom-view/offsetParent_element_test-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cssom-view/scrollingElement-expected.txt": [
     [
      {}
@@ -49983,11 +50110,56 @@
      {}
     ]
    ],
+   "cssom/CSSStyleRule-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cssom/css-style-attribute-modifications-expected.txt": [
     [
      {}
     ]
    ],
+   "cssom/cssom-fontfacerule-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/index-002-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/inline-style-001-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/interfaces-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/medialist-interfaces-001-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/medialist-interfaces-002-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/medialist-interfaces-004-expected.txt": [
+    [
+     {}
+    ]
+   ],
+   "cssom/selectorSerialize-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cssom/serialize-values-expected.txt": [
     [
      {}
@@ -49998,6 +50170,11 @@
      {}
     ]
    ],
+   "cssom/style-sheet-interfaces-001-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "cssom/stylesheet-same-origin.css": [
     [
      {}
@@ -50228,6 +50405,11 @@
      {}
     ]
    ],
+   "cssom/ttwf-cssom-doc-ext-load-count-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "custom-elements/adopted-callback-expected.txt": [
     [
      {}
@@ -66098,11 +66280,21 @@
      {}
     ]
    ],
+   "service-workers/service-worker/register-link-element.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/register-wait-forever-in-install-worker.https-expected.txt": [
     [
      {}
     ]
    ],
+   "service-workers/service-worker/registration.https-expected.txt": [
+    [
+     {}
+    ]
+   ],
    "service-workers/service-worker/resource-timing.https-expected.txt": [
     [
      {}
@@ -89059,15 +89251,15 @@
      {}
     ]
    ],
-   "media-capabilities/idlharness.html": [
+   "media-capabilities/decodingInfo.html": [
     [
-     "/media-capabilities/idlharness.html",
+     "/media-capabilities/decodingInfo.html",
      {}
     ]
    ],
-   "media-capabilities/query.html": [
+   "media-capabilities/idlharness.html": [
     [
-     "/media-capabilities/query.html",
+     "/media-capabilities/idlharness.html",
      {}
     ]
    ],
@@ -102537,6 +102729,12 @@
      {}
     ]
    ],
+   "web-animations/interfaces/Animation/idlharness.html": [
+    [
+     "/web-animations/interfaces/Animation/idlharness.html",
+     {}
+    ]
+   ],
    "web-animations/interfaces/Animation/oncancel.html": [
     [
      "/web-animations/interfaces/Animation/oncancel.html",
@@ -102771,12 +102969,30 @@
      {}
     ]
    ],
+   "web-animations/timing-model/animations/canceling-an-animation.html": [
+    [
+     "/web-animations/timing-model/animations/canceling-an-animation.html",
+     {}
+    ]
+   ],
    "web-animations/timing-model/animations/current-time.html": [
     [
      "/web-animations/timing-model/animations/current-time.html",
      {}
     ]
    ],
+   "web-animations/timing-model/animations/finishing-an-animation.html": [
+    [
+     "/web-animations/timing-model/animations/finishing-an-animation.html",
+     {}
+    ]
+   ],
+   "web-animations/timing-model/animations/pausing-an-animation.html": [
+    [
+     "/web-animations/timing-model/animations/pausing-an-animation.html",
+     {}
+    ]
+   ],
    "web-animations/timing-model/animations/playing-an-animation.html": [
     [
      "/web-animations/timing-model/animations/playing-an-animation.html",
@@ -102813,12 +103029,6 @@
      {}
     ]
    ],
-   "web-nfc/idlharness.https.html": [
-    [
-     "/web-nfc/idlharness.https.html",
-     {}
-    ]
-   ],
    "webmessaging/Channel_postMessage_DataCloneErr.htm": [
     [
      "/webmessaging/Channel_postMessage_DataCloneErr.htm",
@@ -109428,10 +109638,18 @@
    "888d3e58d3d094b767067e16494803af432ee057",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block-expected.txt": [
+   "3111314ca9589e553a81bceb340dda251e3bc3a5",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html": [
    "e96b19c03463de925f03a666a173e948c0908302",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block-expected.txt": [
+   "998121ac3b7aa1650765732ce60997c89da8aa09",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-self-block.html": [
    "816ef071086019d9abed995370cb39a8542f3322",
    "testharness"
@@ -109444,38 +109662,74 @@
    "928e1285169b1d137550f67c083c6ba4eb532b6c",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block-expected.txt": [
+   "215913ff317ebac84ce6d2dbc7f60b68fb85a641",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-url-block.html": [
    "46a056e57129f76eabf6b53b833a24b1a861ed91",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block-expected.txt": [
+   "3111314ca9589e553a81bceb340dda251e3bc3a5",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-none-block.html": [
    "486eaffb8f7c9e28861adeef5e2af6777be73ee6",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block-expected.txt": [
+   "998121ac3b7aa1650765732ce60997c89da8aa09",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-self-block.html": [
    "9c40ca204dae2de593f46b723dc7e6bfa8f8e8fd",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow-expected.txt": [
+   "4d1561c84798d85eac541e1ae872b0d290f12590",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-star-allow.html": [
    "03ea8e9bd6c19aff4ceac59b178b1ef065afeedc",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow-expected.txt": [
+   "215913ff317ebac84ce6d2dbc7f60b68fb85a641",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-allow.html": [
    "f7a44723534d82a650cf8853d6cb114b46f1b535",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block-expected.txt": [
+   "215913ff317ebac84ce6d2dbc7f60b68fb85a641",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-same-url-block.html": [
    "37ead57a4f508fd817541ecb2b2576b7fe65532f",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block-expected.txt": [
+   "4b282eae4435842fa3777ceff7d78d538385711a",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-sandboxed-cross-url-block.html": [
    "4aee1e3833591c74694a3c960bd32c1047a8546f",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block-expected.txt": [
+   "3111314ca9589e553a81bceb340dda251e3bc3a5",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-none-block.html": [
    "2a831ff6c6a9b0a7c63b427105a077ffedbb46e1",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block-expected.txt": [
+   "998121ac3b7aa1650765732ce60997c89da8aa09",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-self-block.html": [
    "332a0a289180b90d14bdb1f4b13c8225b9a810f5",
    "testharness"
@@ -109488,10 +109742,18 @@
    "d8aa43dbab2fd38dd1b7b3ac004dddbf20b3a247",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block-expected.txt": [
+   "215913ff317ebac84ce6d2dbc7f60b68fb85a641",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-cross-url-block.html": [
    "e3ab2ece1d6db2be49a25a0f46c98d3fd07fa1e7",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block-expected.txt": [
+   "3111314ca9589e553a81bceb340dda251e3bc3a5",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-none-block.html": [
    "035865df4a43600910890fed3856fadaf05fd7b7",
    "testharness"
@@ -109508,10 +109770,18 @@
    "c5d24d65811915fff1fafff89f29c6287abaf6d8",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block-expected.txt": [
+   "215913ff317ebac84ce6d2dbc7f60b68fb85a641",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-same-in-same-url-block.html": [
    "c6d7b2b67f933e00feadefa00263cc3b17443395",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-none-block-expected.txt": [
+   "45414ef3eda575ddab318619c29eb32f2f53ef52",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-none-block.html": [
    "b5d0f5f0923f8c1e3400d91f6194f665d7a30a97",
    "testharness"
@@ -109524,10 +109794,18 @@
    "635dd6a6ae1cc8f51fad8b9c0cdcaf7d2b8322b4",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-self-block-expected.txt": [
+   "ac2b4ae241595d763fd07b270e4324cb734e3518",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-self-block.html": [
    "31b16e7e4c7113ec27cba6c0b880b2472fbc174b",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin-expected.txt": [
+   "2f5ef349f841bdcd8820c9b57e44c7553327869b",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-star-allow-crossorigin.html": [
    "6af460fa2c57111abbc8f3ceeb09b31993821b22",
    "testharness"
@@ -109540,6 +109818,10 @@
    "e0921d30fdb2e9739497849133e93d49486cd417",
    "testharness"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-url-block-expected.txt": [
+   "8088d89859ba7cd7bfe43acf8d893472e7f7a0f9",
+   "support"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-url-block.html": [
    "f7b54ddb5688e4706d078538af1f16f2b82d3375",
    "testharness"
@@ -129980,6 +130262,10 @@
    "99c5fcb361ae4903b4e87315dfb8ba80f0296037",
    "reftest"
   ],
+  "css/selectors4/focus-within-shadow-006.html": [
+   "41341130ccf5756ba0bfe12bf9f7f22da8ad7fe0",
+   "reftest"
+  ],
   "css/selectors4/hover-001-manual.html": [
    "ce45f6b6f483ae52c241acff168573a0907ca031",
    "manual"
@@ -132392,6 +132678,10 @@
    "7118495560adadebcca98e6add47a74669f87788",
    "testharness"
   ],
+  "cssom-view/cssom-getBoundingClientRect-002-expected.txt": [
+   "3a77f2a2a04d37ae64ca7c4fb1a47534faa8bdee",
+   "support"
+  ],
   "cssom-view/cssom-getBoundingClientRect-002.html": [
    "8dfaa313b4abad30281d07ce22ac06a61754cc06",
    "testharness"
@@ -132408,10 +132698,18 @@
    "8fb3e3327f8f657e2215c91c75f49fd739c15c57",
    "testharness"
   ],
+  "cssom-view/cssom-view/media-query-list-interface-expected.txt": [
+   "e10c7bbf158a0652b0ee64b7f16408bad7f3b774",
+   "support"
+  ],
   "cssom-view/cssom-view/media-query-list-interface.xht": [
    "3f867c6e608d318d870d3269b9eb886955c119fc",
    "testharness"
   ],
+  "cssom-view/cssom-view/window-interface-expected.txt": [
+   "2d90834d824a27b9aada1b977630dfbb3879f215",
+   "support"
+  ],
   "cssom-view/cssom-view/window-interface.xht": [
    "47aee3e273f90c1f1eb08884afecdef8a96630c5",
    "testharness"
@@ -132428,6 +132726,10 @@
    "e22ae99aa1fba51807aec245b810db5d584ac037",
    "testharness"
   ],
+  "cssom-view/elementFromPosition-expected.txt": [
+   "40e5741bd552d42fd81b876f74332b8c281454fd",
+   "support"
+  ],
   "cssom-view/elementFromPosition.html": [
    "d90dff8b15ec2977f341a7add9c7d627b62d9d0f",
    "testharness"
@@ -132472,6 +132774,10 @@
    "ad44e3f4ba132bfb4a522b14a4ff5356dbbbad14",
    "testharness"
   ],
+  "cssom-view/offsetParent_element_test-expected.txt": [
+   "055aaddbbf5a444b0b5971f7e018a2934ad725ae",
+   "support"
+  ],
   "cssom-view/offsetParent_element_test.html": [
    "6e7579de7add0162ac99f3326f070bbd6051932b",
    "testharness"
@@ -132724,6 +133030,10 @@
    "8d8b435c2398c7a9de5fd57584240e24b45b80bc",
    "testharness"
   ],
+  "cssom/CSSStyleRule-expected.txt": [
+   "b6699c0ffd77348cb238e7885f789f84c5194f5f",
+   "support"
+  ],
   "cssom/CSSStyleRule.html": [
    "b7cfe3da8454d5c64a25c440e0776c80d8c3a751",
    "testharness"
@@ -132776,6 +133086,10 @@
    "c064661df74571d374f49a693f3263fcf138e670",
    "testharness"
   ],
+  "cssom/cssom-fontfacerule-expected.txt": [
+   "05cbaaccfc39fad2c6ecb579d66f9df02c7521ff",
+   "support"
+  ],
   "cssom/cssom-fontfacerule.html": [
    "965a8f6289fa5c6e34bfd447de3b8ef86573fea1",
    "testharness"
@@ -132804,6 +133118,10 @@
    "ab9e9f102f5909d9b5587f2c0ea54c0c6b59868d",
    "testharness"
   ],
+  "cssom/index-002-expected.txt": [
+   "ff8799530548cd7dd1ab3c497f507aa6e62d8b17",
+   "support"
+  ],
   "cssom/index-002.html": [
    "fe12bc0005ccfccfafd4f23644b28fbb5f5e33d1",
    "testharness"
@@ -132812,18 +133130,34 @@
    "f55d9bc5b2e25b1af5169ecc164f62b6a95abfe5",
    "testharness"
   ],
+  "cssom/inline-style-001-expected.txt": [
+   "854f4a7f81962431f6132acf5ff6b42ff3819c53",
+   "support"
+  ],
   "cssom/inline-style-001.html": [
    "377c8610bc597d47a93f70a9cf95b3c7657d8319",
    "testharness"
   ],
+  "cssom/interfaces-expected.txt": [
+   "337273323747da55e98d2fefdb1a15581b03b81e",
+   "support"
+  ],
   "cssom/interfaces.html": [
    "5876c88acd95d18166fdd049bdb3f09cdde4eb3f",
    "testharness"
   ],
+  "cssom/medialist-interfaces-001-expected.txt": [
+   "5b28fc21421358f35fe030552a13d3a44ebfcb3a",
+   "support"
+  ],
   "cssom/medialist-interfaces-001.html": [
    "dfaea262508d72d123006409174e3e21832a305f",
    "testharness"
   ],
+  "cssom/medialist-interfaces-002-expected.txt": [
+   "0e120d75caedff5879b4da464f4fe38333efe875",
+   "support"
+  ],
   "cssom/medialist-interfaces-002.html": [
    "114fac94342afe2e7fe432a67c4b0bbf03d24bc4",
    "testharness"
@@ -132832,6 +133166,10 @@
    "b9ddd611cc585202b1e76382666b04197af334b0",
    "testharness"
   ],
+  "cssom/medialist-interfaces-004-expected.txt": [
+   "435495326a27ba1596e043d89df62e6f66458ff6",
+   "support"
+  ],
   "cssom/medialist-interfaces-004.html": [
    "e3cdc88670ca46b3752fd8118d94dae2cc95258d",
    "testharness"
@@ -132840,6 +133178,10 @@
    "199039706289f577652b968706fc1251398acd1c",
    "testharness"
   ],
+  "cssom/selectorSerialize-expected.txt": [
+   "be841dc5ad7bb520ef21e922b0781d0e393bcb71",
+   "support"
+  ],
   "cssom/selectorSerialize.html": [
    "002777c7c598eb1131ab625365ee3fe08650e830",
    "testharness"
@@ -132868,6 +133210,10 @@
    "bd514834dbd48c267c16a4329af6fec7f6cbc081",
    "testharness"
   ],
+  "cssom/style-sheet-interfaces-001-expected.txt": [
+   "766e9c1b8a8daa003076511584bb695b1e1b5d66",
+   "support"
+  ],
   "cssom/style-sheet-interfaces-001.html": [
    "15509e87505d5a22d4f6dbbffcc90c24fcee642a",
    "testharness"
@@ -133064,6 +133410,10 @@
    "078e1dd6dd61d36cec239ed75d02051f61fe60a5",
    "support"
   ],
+  "cssom/ttwf-cssom-doc-ext-load-count-expected.txt": [
+   "8f765460a64800bc2ccc6d0067a3b9b65cc4d1b2",
+   "support"
+  ],
   "cssom/ttwf-cssom-doc-ext-load-count.html": [
    "800db5cd4f7342d8c4e5309d4035182ce42f7251",
    "testharness"
@@ -134609,7 +134959,7 @@
    "support"
   ],
   "dom/nodes/case-expected.txt": [
-   "04da91ce54c42bbd57496a60483553e45fd43947",
+   "77f3037f1d9f1da9bb8c51269af9564870099690",
    "support"
   ],
   "dom/nodes/case.html": [
@@ -136641,7 +136991,7 @@
    "testharness"
   ],
   "fetch/api/headers/headers-basic-expected.txt": [
-   "5cc5ace9951394fd264b9233cf32435cec55c57b",
+   "c7aa1da80c76986abd8e190ba07af702a4005565",
    "support"
   ],
   "fetch/api/headers/headers-basic.html": [
@@ -136681,7 +137031,7 @@
    "testharness"
   ],
   "fetch/api/headers/headers-record-expected.txt": [
-   "7dd187ab5cc9c185252088e470d9a4784fec14d0",
+   "d8d03a608ee0af8ba54c18dcc1e8040dbe4e86bd",
    "support"
   ],
   "fetch/api/headers/headers-record.html": [
@@ -151056,16 +151406,16 @@
    "7d6ceec9a74d5485a6f7d51504f22e5eaf81bfee",
    "support"
   ],
+  "media-capabilities/decodingInfo.html": [
+   "1d8f79cb9e47042aa7eff1b63fe72af4941830e2",
+   "testharness"
+  ],
   "media-capabilities/idlharness-expected.txt": [
-   "36a770de2f25ca3e03f92ff615db45b2b3edec59",
+   "c7e0888b13bbf83dc7fc9baa33f46b822b02133d",
    "support"
   ],
   "media-capabilities/idlharness.html": [
-   "d9a80463af2e0fc7bda0a4370a3ba0bbbb791897",
-   "testharness"
-  ],
-  "media-capabilities/query.html": [
-   "a83f2c7a7d9c38c707c4f96c3cd74f77185b7e43",
+   "dbaa12b0278165d9152815b9d391a198b0ba610e",
    "testharness"
   ],
   "media/2048x1360-random.jpg": [
@@ -162196,6 +162546,10 @@
    "864f5435fc40124dbe2c1ffb0e1942fee58228d2",
    "testharness"
   ],
+  "service-workers/service-worker/register-link-element.https-expected.txt": [
+   "b132376709325573bb909b51afc67e7c5c1ac669",
+   "support"
+  ],
   "service-workers/service-worker/register-link-element.https.html": [
    "fcd2a244ad1f12c954c231c479f89beaa3c145e6",
    "testharness"
@@ -162236,6 +162590,10 @@
    "73d662eafa93ca3dee4a4e5d34623cf069c2b8f8",
    "testharness"
   ],
+  "service-workers/service-worker/registration.https-expected.txt": [
+   "36309067df5ff56185b6618affe450f7c298daaf",
+   "support"
+  ],
   "service-workers/service-worker/registration.https.html": [
    "0a06c368a14c008c385c9df3cde35f090d96d58b",
    "testharness"
@@ -163973,7 +164331,7 @@
    "testharness"
   ],
   "streams/piping/pipe-through.js": [
-   "8960662dd6a59e4950c1e8ee86d0ea21de5b1bf7",
+   "bf2cebbca84051b446f728d92c065869207299f2",
    "support"
   ],
   "streams/piping/pipe-through.serviceworker.https-expected.txt": [
@@ -165464,6 +165822,10 @@
    "395dad4a877ef4af20649d6bcfece102a22b3059",
    "testharness"
   ],
+  "web-animations/interfaces/Animation/idlharness.html": [
+   "bf61e9cb3d009b4d5ccbd70ec7397842e2d521d2",
+   "testharness"
+  ],
   "web-animations/interfaces/Animation/oncancel.html": [
    "0477d2fef7fc64bbc969b29d4ba542574c4c3706",
    "testharness"
@@ -165489,7 +165851,7 @@
    "testharness"
   ],
   "web-animations/interfaces/Animation/ready.html": [
-   "f79ea4e2bfc3bc83a7ac96634cbb2d5f21f6c1f5",
+   "b23b76881f4d38c07710d0e59c1f6c8569de9060",
    "testharness"
   ],
   "web-animations/interfaces/Animation/reverse-expected.txt": [
@@ -165724,6 +166086,10 @@
    "53a4a6c6c6d07e00fecc50e5de831862e7bf4b2e",
    "testharness"
   ],
+  "web-animations/timing-model/animations/canceling-an-animation.html": [
+   "079bc0e0f7ea60b94999ed1b4f92c1aa2fc2c7bb",
+   "testharness"
+  ],
   "web-animations/timing-model/animations/current-time-expected.txt": [
    "a18dd6fac631dc2beee45b4f1f1a75ca1bed1e82",
    "support"
@@ -165732,8 +166098,16 @@
    "b1ea8e490cbfb69fd71b91a90e7e2d9ce99f42d3",
    "testharness"
   ],
+  "web-animations/timing-model/animations/finishing-an-animation.html": [
+   "570ec579c6118866b888b1384e21977c9cfb0ec0",
+   "testharness"
+  ],
+  "web-animations/timing-model/animations/pausing-an-animation.html": [
+   "a000d8f86fa62b90ec7a60c289066aaaa1758377",
+   "testharness"
+  ],
   "web-animations/timing-model/animations/playing-an-animation.html": [
-   "88ab1d42390d50bcdf513bb12159c0c15d6278ff",
+   "2b4f51977d43f9bf90c066bfcc57728ae096b6e9",
    "testharness"
   ],
   "web-animations/timing-model/animations/set-the-animation-start-time-expected.txt": [
@@ -165772,10 +166146,6 @@
    "66e2277c77e4bd7b2d8981a725fb5083a8f5e0f6",
    "testharness"
   ],
-  "web-nfc/idlharness.https.html": [
-   "b44413f6709ec74f6fc809726d0e988c127ef02d",
-   "testharness"
-  ],
   "webmessaging/Channel_postMessage_DataCloneErr.htm": [
    "a62fdac80932ca059c8853ca9a9f8edd13926f86",
    "testharness"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-shadow-006.html b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-shadow-006.html
new file mode 100644
index 0000000..39a2f70
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/selectors4/focus-within-shadow-006.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<meta charset="utf-8">
+<title>Selectors Level 4: focus-within with shadow DOM</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/selectors-4/#focus-within-pseudo">
+<link rel="help" href="https://dom.spec.whatwg.org/#shadow-trees">
+<link rel="match" href="focus-within-shadow-001-ref.html">
+<meta name="flags" content="dom">
+<meta name="assert" content="Checks that ':focus-within' is propagated to the flat tree ancestors, even if it comes from a slotted element.">
+<style>
+  /* Suppress things that cannot be reproduced in the reference file */
+  :focus {
+    outline: none;
+  }
+  :focus-within {
+      border-color: green;
+  }
+</style>
+<p>Test passes if there is a green rectangle below.</p>
+
+<div id="log"></div>
+<script>
+  if (!document.body.attachShadow)
+    document.getElementById("log").innerHTML = "<strong>Skip this test, shadow DOM is not supported.</strong>";
+</script>
+
+<div id="shadow-host">
+  <div id="focusme" tabindex="1"></div>
+</div>
+
+<script>
+  var shadowHost = document.getElementById("shadow-host");
+  shadowHost.attachShadow({ mode: "open"}).innerHTML =
+    "<style>" +
+    "  #shadow-div:focus-within { border: solid 15px green; }" +
+    "</style>" +
+    "<div id='shadow-div'>" +
+    "  <slot></slot>" +
+    "</div>";
+  var focusme = document.getElementById("focusme");
+  focusme.focus();
+  document.documentElement.classList.remove("reftest-wait");
+</script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt
index cb261c6..9b1cbbf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through-expected.txt
@@ -6,5 +6,6 @@
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
 PASS pipeThrough should mark a real promise from a fake readable as handled 
+PASS pipeThrough should not be fooled by an object whose instanceof Promise returns true 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt
index cb261c6..9b1cbbf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.dedicatedworker-expected.txt
@@ -6,5 +6,6 @@
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
 PASS pipeThrough should mark a real promise from a fake readable as handled 
+PASS pipeThrough should not be fooled by an object whose instanceof Promise returns true 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js
index 9299fce..bc4ac909 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.js
@@ -118,4 +118,30 @@
 
 }, 'pipeThrough should mark a real promise from a fake readable as handled');
 
+test(() => {
+  let thenCalled = false
+  let catchCalled = false;
+  const dummy = {
+    pipeTo() {
+      const fakePromise = Object.create(Promise.prototype);
+      fakePromise.then = () => {
+        thenCalled = true;
+      };
+      fakePromise.catch = () => {
+        catchCalled = true;
+      };
+      assert_true(fakePromise instanceof Promise, 'fakePromise fools instanceof');
+      return fakePromise;
+    }
+  };
+
+  // An incorrect implementation which uses an internal method to mark the promise as handled will throw or crash here.
+  ReadableStream.prototype.pipeThrough.call(dummy, { });
+
+  // An incorrect implementation that tries to mark the promise as handled by calling .then() or .catch() on the object
+  // will fail these tests.
+  assert_false(thenCalled, 'then should not be called');
+  assert_false(catchCalled, 'catch should not be called');
+}, 'pipeThrough should not be fooled by an object whose instanceof Promise returns true');
+
 done();
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt
index cbfe250..4bf888f6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.serviceworker.https-expected.txt
@@ -7,5 +7,6 @@
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
 PASS pipeThrough should mark a real promise from a fake readable as handled 
+PASS pipeThrough should not be fooled by an object whose instanceof Promise returns true 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt
index cb261c6..9b1cbbf 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/streams/piping/pipe-through.sharedworker-expected.txt
@@ -6,5 +6,6 @@
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise object 
 PASS pipeThrough can handle calling a pipeTo that returns a non-promise thenable object 
 PASS pipeThrough should mark a real promise from a fake readable as handled 
+PASS pipeThrough should not be fooled by an object whose instanceof Promise returns true 
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt
new file mode 100644
index 0000000..92f829e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness-expected.txt
@@ -0,0 +1,43 @@
+This is a testharness.js-based test.
+PASS Animation interface automated IDL tests 
+FAIL Animation interface: existence and properties of interface object assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface object length assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface object name assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: existence and properties of interface prototype object assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute id assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute effect assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute timeline assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute startTime assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute currentTime assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute playbackRate assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute playState assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute ready assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute finished assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute onfinish assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: attribute oncancel assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: operation cancel() assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: operation finish() assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: operation play() assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: operation pause() assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation interface: operation reverse() assert_own_property: self does not have own property "Animation" expected property "Animation" missing
+FAIL Animation must be primary interface of new Animation() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Stringification of new Animation() assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "id" with the proper type (0) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "effect" with the proper type (1) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "timeline" with the proper type (2) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "startTime" with the proper type (3) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "currentTime" with the proper type (4) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "playbackRate" with the proper type (5) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "playState" with the proper type (6) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "ready" with the proper type (7) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "finished" with the proper type (8) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "onfinish" with the proper type (9) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "oncancel" with the proper type (10) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "cancel" with the proper type (11) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "finish" with the proper type (12) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "play" with the proper type (13) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "pause" with the proper type (14) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+FAIL Animation interface: new Animation() must inherit property "reverse" with the proper type (15) assert_equals: Unexpected exception when evaluating object expected null but got object "ReferenceError: Animation is not defined"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness.html
new file mode 100644
index 0000000..213958f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/idlharness.html
@@ -0,0 +1,51 @@
+<!doctype html>
+<meta charset=utf-8>
+<title>Animation interface automated IDL tests</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/WebIDLParser.js"></script>
+<script src="/resources/idlharness.js"></script>
+<script src="../../testcommon.js"></script>
+<div id="log"></div>
+<script type="text/plain" id="Animation-IDL">
+enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" };
+
+[Constructor (optional AnimationEffectReadOnly? effect = null,
+              optional AnimationTimeline? timeline)]
+interface Animation : EventTarget {
+             attribute DOMString                id;
+             attribute AnimationEffectReadOnly? effect;
+             attribute AnimationTimeline?       timeline;
+             attribute double?                  startTime;
+             attribute double?                  currentTime;
+             attribute double                   playbackRate;
+    readonly attribute AnimationPlayState       playState;
+    readonly attribute Promise<Animation>       ready;
+    readonly attribute Promise<Animation>       finished;
+             attribute EventHandler             onfinish;
+             attribute EventHandler             oncancel;
+    void cancel ();
+    void finish ();
+    void play ();
+    void pause ();
+    void reverse ();
+};
+</script>
+<script>
+'use strict';
+
+test(function(t) {
+  const idlArray = new IdlArray();
+
+  idlArray.add_untested_idls('interface AnimationTimeline {};');
+  idlArray.add_untested_idls('interface EventHandler {};');
+  idlArray.add_untested_idls('interface EventTarget {};');
+  idlArray.add_idls(
+    document.getElementById('Animation-IDL').textContent);
+
+  // const animation = createDiv(t).animate(null);
+  idlArray.add_objects( { Animation: ['new Animation()'] } );
+  idlArray.test();
+});
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/ready.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/ready.html
index 86595c3..b61a3c49 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/ready.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/interfaces/Animation/ready.html
@@ -12,7 +12,7 @@
 
 promise_test(function(t) {
   var div = createDiv(t);
-  var animation = div.animate({}, 100 * MS_PER_SEC);
+  var animation = div.animate(null, 100 * MS_PER_SEC);
   var originalReadyPromise = animation.ready;
   var pauseReadyPromise;
 
@@ -35,7 +35,7 @@
 
 promise_test(function(t) {
   var div = createDiv(t);
-  var animation = div.animate({}, 100 * MS_PER_SEC);
+  var animation = div.animate(null, 100 * MS_PER_SEC);
 
   return animation.ready.then(function() {
     var promiseBeforeCallingPlay = animation.ready;
@@ -48,7 +48,7 @@
 
 promise_test(function(t) {
   var div = createDiv(t);
-  var animation = div.animate({}, 100 * MS_PER_SEC);
+  var animation = div.animate(null, 100 * MS_PER_SEC);
 
   return animation.ready.then(function(resolvedAnimation) {
     assert_equals(resolvedAnimation, animation,
@@ -57,40 +57,5 @@
   });
 }, 'The ready promise is fulfilled with its Animation');
 
-promise_test(function(t) {
-  var div = createDiv(t);
-  var animation = div.animate({}, 100 * MS_PER_SEC);
-
-  var retPromise = animation.ready.then(function() {
-    assert_unreached('ready promise was fulfilled');
-  }).catch(function(err) {
-    assert_equals(err.name, 'AbortError',
-                  'ready promise is rejected with AbortError');
-  });
-
-  animation.cancel();
-
-  return retPromise;
-}, 'ready promise is rejected when a play-pending animation is cancelled by'
-   + ' calling cancel()');
-
-promise_test(function(t) {
-  var div = createDiv(t);
-  var animation = div.animate({}, 100 * MS_PER_SEC);
-  return animation.ready.then(function() {
-    animation.pause();
-    // Set up listeners on pause-pending ready promise
-    var retPromise = animation.ready.then(function() {
-      assert_unreached('ready promise was fulfilled');
-    }).catch(function(err) {
-      assert_equals(err.name, 'AbortError',
-                    'ready promise is rejected with AbortError');
-    });
-    animation.cancel();
-    return retPromise;
-  });
-}, 'ready promise is rejected when a pause-pending animation is cancelled by'
-   + ' calling cancel()');
-
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/canceling-an-animation-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/canceling-an-animation-expected.txt
new file mode 100644
index 0000000..65d504e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/canceling-an-animation-expected.txt
@@ -0,0 +1,8 @@
+This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = The user aborted a request.
+PASS A play-pending ready promise should be rejected when the animation is canceled 
+PASS A pause-pending ready promise should be rejected when the animation is canceled 
+PASS When an animation is canceled, it should create a resolved Promise 
+PASS The ready promise should be replaced when the animation is canceled 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/canceling-an-animation.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/canceling-an-animation.html
new file mode 100644
index 0000000..5aa7de2b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/canceling-an-animation.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Canceling an animation</title>
+<link rel="help"
+    href="https://w3c.github.io/web-animations/#canceling-an-animation-section">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+"use strict";
+
+promise_test(function(t) {
+  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  const retPromise = animation.ready.then(() => {
+    assert_unreached('ready promise was fulfilled');
+  }).catch(err => {
+    assert_equals(err.name, 'AbortError',
+                  'ready promise is rejected with AbortError');
+  });
+
+  animation.cancel();
+
+  return retPromise;
+}, 'A play-pending ready promise should be rejected when the animation is'
+   + ' canceled');
+
+promise_test(function(t) {
+  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  return animation.ready.then(() => {
+    animation.pause();
+    // Set up listeners on pause-pending ready promise
+    var retPromise = animation.ready.then(function() {
+      assert_unreached('ready promise was fulfilled');
+    }).catch(err => {
+      assert_equals(err.name, 'AbortError',
+                    'ready promise is rejected with AbortError');
+    });
+    animation.cancel();
+    return retPromise;
+  });
+}, 'A pause-pending ready promise should be rejected when the animation is'
+   + ' canceled');
+
+promise_test(function(t) {
+  const animation = createDiv(t).animate(null);
+  animation.cancel();
+  return animation.ready.then(function(p) {
+    assert_equals(p, animation);
+  });
+}, 'When an animation is canceled, it should create a resolved Promise');
+
+test(function(t) {
+  const animation = createDiv(t).animate(null);
+  const promise = animation.ready;
+  animation.cancel();
+  assert_not_equals(animation.ready, promise);
+}, 'The ready promise should be replaced when the animation is canceled');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/finishing-an-animation.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/finishing-an-animation.html
new file mode 100644
index 0000000..4890bd1b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/finishing-an-animation.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Finishing an animation</title>
+<link rel="help"
+  href="https://w3c.github.io/web-animations/#finishing-an-animation-section">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+promise_test(function(t) {
+  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  const promise = animation.ready;
+  let readyResolved = false;
+
+  animation.finish();
+  animation.ready.then(() => { readyResolved = true; });
+
+  return animation.finished.then(p => {
+    assert_equals(p, animation);
+    assert_equals(animation.ready, promise);
+    assert_true(readyResolved);
+  });
+}, 'A pending ready promise should be resolved and not replaced when the'
+   + ' animation is finished');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/pausing-an-animation.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/pausing-an-animation.html
new file mode 100644
index 0000000..9a4da2e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/pausing-an-animation.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Pausing an animation</title>
+<link rel="help"
+  href="https://w3c.github.io/web-animations/#finishing-an-animation-section">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../../testcommon.js"></script>
+<body>
+<div id="log"></div>
+<script>
+'use strict';
+
+promise_test(function(t) {
+  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  const promise = animation.ready;
+  animation.pause();
+  return promise.then(p => {
+    assert_equals(p, animation);
+    assert_equals(animation.ready, promise);
+    assert_equals(animation.playState, 'paused');
+  });
+}, 'A pending ready promise should be resolved and not replaced when the'
+   + ' animation is paused');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/playing-an-animation.html b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/playing-an-animation.html
index 185e206..1cf109d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/playing-an-animation.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/web-animations/timing-model/animations/playing-an-animation.html
@@ -36,5 +36,24 @@
   assert_times_equal(animation.currentTime, 100 * MS_PER_SEC);
 }, 'Playing a finished and reversed animation seeks to end');
 
+test(function(t) {
+  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  animation.cancel();
+  const promise = animation.ready;
+  animation.play();
+  assert_not_equals(animation.ready, promise);
+}, 'The ready promise should be replaced if the animation is not already'
+   + ' pending');
+
+promise_test(function(t) {
+  const animation = createDiv(t).animate(null, 100 * MS_PER_SEC);
+  const promise = animation.ready;
+  return promise.then(p => {
+    assert_equals(p, animation);
+    assert_equals(animation.ready, promise);
+  });
+}, 'A pending ready promise should be resolved and not replaced when the'
+   + ' animation enters the running state');
+
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt
index 755e1dc..95c4aff0 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-callFunctionOn-async-expected.txt
@@ -109,10 +109,6 @@
         }
         exceptionId : 0
         lineNumber : 0
-        stackTrace : {
-            callFrames : [
-            ]
-        }
         text : Uncaught (in promise)
     }
     result : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-async-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-async-expected.txt
index 7e42eac8..a903a5f 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-async-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-evaluate-async-expected.txt
@@ -23,10 +23,6 @@
         exceptionId : 0
         lineNumber : 0
         scriptId : 
-        stackTrace : {
-            callFrames : [
-            ]
-        }
         text : Uncaught (in promise)
     }
     result : {
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-runScript-async-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-runScript-async-expected.txt
index 47b1742..e719a27 100644
--- a/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-runScript-async-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/runtime/runtime-runScript-async-expected.txt
@@ -142,10 +142,6 @@
         }
         exceptionId : 0
         lineNumber : 0
-        stackTrace : {
-            callFrames : [
-            ]
-        }
         text : Uncaught (in promise)
     }
     result : {
diff --git a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html
index 2a64972..585f8af 100644
--- a/third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html
+++ b/third_party/WebKit/LayoutTests/webaudio/Panner/panner-distance-clamping.html
@@ -17,12 +17,12 @@
       var audit = Audit.createTaskRunner();
 
       audit.defineTask("ref-distance-error", function (taskDone) {
-        testDistanceLimits({name: "refDistance"});
+        testDistanceLimits({name: "refDistance", isZeroAllowed: true});
         taskDone();
       });
 
       audit.defineTask("max-distance-error", function (taskDone) {
-        testDistanceLimits({name: "maxDistance"});
+        testDistanceLimits({name: "maxDistance", isZeroAllowed: false});
         taskDone();
       });
 
@@ -39,11 +39,19 @@
           new PannerNode(context, nodeOptions);
         }).throw("RangeError");
 
-        success = Should(prefix + "0})", function () {
-          var nodeOptions = {};
-          nodeOptions[attrName] = 0;
-          new PannerNode(context, nodeOptions);
-        }).throw("RangeError") && success;
+        if (options.isZeroAllowed) {
+          success = Should(prefix + "0})", function () {
+            var nodeOptions = {};
+            nodeOptions[attrName] = 0;
+            new PannerNode(context, nodeOptions);
+          }).notThrow() && success;
+        } else {
+          success = Should(prefix + "0})", function () {
+            var nodeOptions = {};
+            nodeOptions[attrName] = 0;
+            new PannerNode(context, nodeOptions);
+          }).throw("RangeError") && success;
+        }
 
         // The smallest representable positive single float.
         var leastPositiveDoubleFloat = 4.9406564584124654e-324;
@@ -61,9 +69,15 @@
           panner[attrName] = -1;
         }).throw("RangeError") && success;
 
-        success = Should(prefix + "0", function () {
-          panner[attrName] = 0;
-        }).throw("RangeError") && success;
+        if (options.isZeroAllowed) {
+          success = Should(prefix + "0", function () {
+            panner[attrName] = 0;
+          }).notThrow() && success;
+        } else {
+          success = Should(prefix + "0", function () {
+            panner[attrName] = 0;
+          }).throw("RangeError") && success;
+        }
 
         success = Should(prefix + leastPositiveDoubleFloat, function () {
           panner[attrName] = leastPositiveDoubleFloat;
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp
index e08b11f..4074bca1 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.cpp
@@ -5,7 +5,6 @@
 #include "bindings/core/v8/ScriptState.h"
 
 #include "bindings/core/v8/V8Binding.h"
-#include "core/dom/ExecutionContext.h"
 
 namespace blink {
 
@@ -65,8 +64,4 @@
   return ScriptValue(this, v8_value);
 }
 
-ExecutionContext* ScriptState::GetExecutionContext() const {
-  return ExecutionContext::From(this);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
index 2e2ea9f..be40f2d 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptState.h
@@ -17,7 +17,6 @@
 namespace blink {
 
 class DOMWrapperWorld;
-class ExecutionContext;
 class ScriptValue;
 
 // ScriptState is an abstraction class that holds all information about script
@@ -136,8 +135,6 @@
 
   v8::Isolate* GetIsolate() const { return isolate_; }
   DOMWrapperWorld& World() const { return *world_; }
-  // DEPRECATED: Use ExecutionContext::From instead
-  virtual ExecutionContext* GetExecutionContext() const;
 
   // This can return an empty handle if the v8::Context is gone.
   v8::Local<v8::Context> GetContext() const {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp
index 902a2fd..88173956 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp
@@ -26,10 +26,6 @@
                                              PassRefPtr<DOMWrapperWorld> world)
     : ScriptState(context, std::move(world)) {}
 
-ExecutionContext* ScriptStateForTesting::GetExecutionContext() const {
-  return execution_context_;
-}
-
 V8TestingScope::V8TestingScope()
     : holder_(DummyPageHolder::Create()),
       handle_scope_(GetIsolate()),
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h
index f4effdb..1e6ae842 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h
@@ -24,11 +24,8 @@
  public:
   static PassRefPtr<ScriptStateForTesting> Create(v8::Local<v8::Context>,
                                                   PassRefPtr<DOMWrapperWorld>);
-  ExecutionContext* GetExecutionContext() const override;
-
  private:
   ScriptStateForTesting(v8::Local<v8::Context>, PassRefPtr<DOMWrapperWorld>);
-  Persistent<ExecutionContext> execution_context_;
 };
 
 class V8TestingScope {
diff --git a/third_party/WebKit/Source/core/OWNERS b/third_party/WebKit/Source/core/OWNERS
index 6c8eed29..3190ca49 100644
--- a/third_party/WebKit/Source/core/OWNERS
+++ b/third_party/WebKit/Source/core/OWNERS
@@ -12,6 +12,8 @@
 chrishtr@chromium.org
 dcheng@chromium.org
 dglazkov@chromium.org
+# dtapuska reviews input-related changes
+dtapuska@chromium.org
 dgozman@chromium.org
 dominicc@chromium.org
 dpranke@chromium.org
@@ -48,7 +50,6 @@
 pfeldman@chromium.org
 pkasting@chromium.org
 rego@igalia.com
-# rbyers reviews input related changes (eg. event handling, mouse cursors, touch hit testing, scrolling coordinator)
 rbyers@chromium.org
 rob.buis@samsung.com
 robhogan@gmail.com
diff --git a/third_party/WebKit/Source/core/testing/Internals.h b/third_party/WebKit/Source/core/testing/Internals.h
index 5a28123..cbe4354 100644
--- a/third_party/WebKit/Source/core/testing/Internals.h
+++ b/third_party/WebKit/Source/core/testing/Internals.h
@@ -54,6 +54,7 @@
 class DocumentMarker;
 class Element;
 class ExceptionState;
+class ExecutionContext;
 class GCObservation;
 class HTMLInputElement;
 class HTMLMediaElement;
diff --git a/third_party/WebKit/Source/core/testing/v8/WebCoreTestSupport.cpp b/third_party/WebKit/Source/core/testing/v8/WebCoreTestSupport.cpp
index 1c56c81..f66ead6 100644
--- a/third_party/WebKit/Source/core/testing/v8/WebCoreTestSupport.cpp
+++ b/third_party/WebKit/Source/core/testing/v8/WebCoreTestSupport.cpp
@@ -50,7 +50,7 @@
   blink::ScriptState* scriptState = blink::ScriptState::From(context);
   v8::Local<v8::Object> global = scriptState->GetContext()->Global();
   blink::ExecutionContext* executionContext =
-      scriptState->GetExecutionContext();
+      blink::ExecutionContext::From(scriptState);
   if (executionContext->IsDocument()) {
     return blink::ToV8(blink::Internals::Create(executionContext), global,
                        scriptState->GetIsolate());
@@ -89,7 +89,7 @@
       type, scriptState, prototypeObject, interfaceObject);
 
   blink::ExecutionContext* executionContext =
-      scriptState->GetExecutionContext();
+      blink::ExecutionContext::From(scriptState);
   blink::OriginTrialContext* originTrialContext =
       blink::OriginTrialContext::From(
           executionContext, blink::OriginTrialContext::kDontCreateIfNotExists);
@@ -110,7 +110,8 @@
 
   blink::ScriptState* scriptState = blink::ScriptState::From(context);
   blink::ScriptState::Scope scope(scriptState);
-  blink::Document* document = ToDocument(scriptState->GetExecutionContext());
+  blink::Document* document =
+      ToDocument(blink::ExecutionContext::From(scriptState));
   DCHECK(document);
   blink::LocalFrame* frame = document->GetFrame();
   // Should the document have been detached, the page is assumed being destroyed
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 725b981e..2fe6ff0 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -443,6 +443,7 @@
   "front_end/sass/SASSProcessor.js",
   "front_end/sass/SASSSourceMapFactory.js",
   "front_end/sass/SASSSupport.js",
+  "front_end/screencast/InputModel.js",
   "front_end/screencast/module.json",
   "front_end/screencast/ScreencastApp.js",
   "front_end/screencast/screencastView.css",
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png
index abab09a9..9e40e19 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png
index 947338be..3d23b09 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/smallIcons_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
index edecedd..747c4f3b 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -4,7 +4,7 @@
     "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "checkboxCheckmark.svg": "f039bf85cee42ad5c30ca3bfdce7912a",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
-    "smallIcons.svg": "54000a76145196864f9dabac90afd2bf",
+    "smallIcons.svg": "55c46735baa910dbe8f6b9602eb2f464",
     "mediumIcons.svg": "e63ac6385b0a6efb783d9838517e5e44",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "treeoutlineTriangles.svg": "017d2f89437df0afc6b9cd5ff43735d9",
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg
index 55a7d36..ef36848 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/smallIcons.svg
@@ -1,162 +1,758 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="90" height="90" id="svg4185" version="1.1" inkscape:version="0.48.4 r9939" sodipodi:docname="smallIcons.svg">
-  <metadata id="metadata4459">
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="90"
+   height="90"
+   id="svg4185"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="smallIcons.svg">
+  <metadata
+     id="metadata4459">
     <rdf:RDF>
-      <cc:Work rdf:about="">
+      <cc:Work
+         rdf:about="">
         <dc:format>image/svg+xml</dc:format>
-        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
       </cc:Work>
     </rdf:RDF>
   </metadata>
-  <defs id="defs4457"/>
-  <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1278" inkscape:window-height="746" id="namedview4455" showgrid="true" inkscape:zoom="2.6222222" inkscape:cx="46.759258" inkscape:cy="55.570823" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="svg4185">
-    <inkscape:grid type="xygrid" id="grid4461" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true" spacingx="10px" spacingy="10px"/>
+  <defs
+     id="defs4457" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1986"
+     inkscape:window-height="1353"
+     id="namedview4455"
+     showgrid="true"
+     inkscape:zoom="10.488889"
+     inkscape:cx="52.875124"
+     inkscape:cy="43.09204"
+     inkscape:window-x="201"
+     inkscape:window-y="36"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg4185">
+    <inkscape:grid
+       type="xygrid"
+       id="grid4461"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="10px"
+       spacingy="10px" />
   </sodipodi:namedview>
-  <g id="g4187">
-    <path transform="translate(-80,-20)" d="m 80,20.995 c 0,-0.54974 0.45566,-0.9954 0.9954,-0.9954 h 8.0092 c 0.54974,0 0.9954,0.45566 0.9954,0.9954 v 8.0092 c 0,0.54974 -0.45566,0.9954 -0.9954,0.9954 H 80.9954 C 80.44566,29.9996 80,29.54394 80,29.0042 z m 5.1233,4.7444 c 2.5673,-0.42788 3.6267,-1.193 3.6267,-3.7398 h -1.5 c 0,1.6199 -0.44058,1.9381 -2.3733,2.2602 -2.5673,0.42788 -3.6267,1.193 -3.6267,3.7398 h 1.5 c 0,-1.6199 0.44058,-1.9381 2.3733,-2.2602 z" id="path4191" inkscape:connector-curvature="0"/>
+  <g
+     id="g4187">
+    <path
+       transform="translate(-80,-20)"
+       d="m 80,20.995 c 0,-0.54974 0.45566,-0.9954 0.9954,-0.9954 h 8.0092 c 0.54974,0 0.9954,0.45566 0.9954,0.9954 v 8.0092 c 0,0.54974 -0.45566,0.9954 -0.9954,0.9954 H 80.9954 C 80.44566,29.9996 80,29.54394 80,29.0042 z m 5.1233,4.7444 c 2.5673,-0.42788 3.6267,-1.193 3.6267,-3.7398 h -1.5 c 0,1.6199 -0.44058,1.9381 -2.3733,2.2602 -2.5673,0.42788 -3.6267,1.193 -3.6267,3.7398 h 1.5 c 0,-1.6199 0.44058,-1.9381 2.3733,-2.2602 z"
+       id="path4191"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(20,0)" id="g4193">
-    <path transform="translate(-128,-109)" d="m 131.65,116.21 -1.44,-2.03 -1.21,1.21 2.55,3.61 6.45,-7.67 -1.12,-1.33 z" id="path4197" inkscape:connector-curvature="0"/>
+  <g
+     transform="translate(20,0)"
+     id="g4193">
+    <path
+       transform="translate(-128,-109)"
+       d="m 131.65,116.21 -1.44,-2.03 -1.21,1.21 2.55,3.61 6.45,-7.67 -1.12,-1.33 z"
+       id="path4197"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(0,20)" id="g4199">
-    <path transform="translate(-40,-19)" d="m 46.5,25 c 0,0.55 0.45,1 1,1 0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1 -0.55,0 -1,0.45 -1,1" id="path4203" inkscape:connector-curvature="0" style="fill:#bababa"/><path transform="translate(-40,-19)" d="m 45.75,21.75 -3.5,3.25 3.5,3.25" id="path4205" inkscape:connector-curvature="0" style="fill:none;stroke:#bababa;stroke-width:1.5"/>
+  <g
+     transform="translate(0,20)"
+     id="g4199">
+    <path
+       transform="translate(-40,-19)"
+       d="m 46.5,25 c 0,0.55 0.45,1 1,1 0.55,0 1,-0.45 1,-1 0,-0.55 -0.45,-1 -1,-1 -0.55,0 -1,0.45 -1,1"
+       id="path4203"
+       inkscape:connector-curvature="0"
+       style="fill:#bababa" />
+    <path
+       transform="translate(-40,-19)"
+       d="m 45.75,21.75 -3.5,3.25 3.5,3.25"
+       id="path4205"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#bababa;stroke-width:1.5" />
   </g>
-  <g transform="translate(20,20)" id="g4207">
-    <path transform="translate(-177,-98)" d="m 184.5,100.43 -0.93,-0.93 -2.57,2.57 -2.57,-2.57 -0.93,0.93 2.57,2.57 -2.57,2.57 0.93,0.93 2.57,-2.57 2.57,2.57 0.93,-0.93 -2.57,-2.57 2.57,-2.57 z" id="path4211" inkscape:connector-curvature="0" style="fill-opacity:0.23999999"/><path transform="translate(-177,-98)" d="M 184.5,99.93 183.57,99 181,101.57 178.43,99 l -0.93,0.93 2.57,2.57 -2.57,2.57 0.93,0.93 2.57,-2.57 2.57,2.57 0.93,-0.93 -2.57,-2.57 2.57,-2.57 z" id="path4213" inkscape:connector-curvature="0" style="fill:#676767"/>
+  <g
+     transform="translate(20,20)"
+     id="g4207">
+    <path
+       transform="translate(-177,-98)"
+       d="m 184.5,100.43 -0.93,-0.93 -2.57,2.57 -2.57,-2.57 -0.93,0.93 2.57,2.57 -2.57,2.57 0.93,0.93 2.57,-2.57 2.57,2.57 0.93,-0.93 -2.57,-2.57 2.57,-2.57 z"
+       id="path4211"
+       inkscape:connector-curvature="0"
+       style="fill-opacity:0.23999999" />
+    <path
+       transform="translate(-177,-98)"
+       d="M 184.5,99.93 183.57,99 181,101.57 178.43,99 l -0.93,0.93 2.57,2.57 -2.57,2.57 0.93,0.93 2.57,-2.57 2.57,2.57 0.93,-0.93 -2.57,-2.57 2.57,-2.57 z"
+       id="path4213"
+       inkscape:connector-curvature="0"
+       style="fill:#676767" />
   </g>
-  <g transform="translate(40,0)" id="g4215">
-    <path transform="translate(-100,0)" d="m 103.25,-4.7795e-7 c -0.7,0 -1.25,0.49999999795 -1.25,1.24999997795 v 7.5 c 0,0.7 0.5,1.25 1.25,1.25 h 3.5 c 0.7,0 1.25,-0.5 1.25,-1.25 v -7.5 C 108,0.54999952 107.5,-4.7795e-7 106.75,-4.7795e-7 z M 103,0.99999952 h 4 V 7.9999995 h -4 z m 2,7.24999998 c 0.4,0 0.75,0.3 0.75,0.75 0,0.4 -0.3,0.75 -0.75,0.75 -0.4,0 -0.75,-0.3 -0.75,-0.75 0,-0.4 0.3,-0.75 0.75,-0.75 z" id="path4219" inkscape:connector-curvature="0"/>
+  <g
+     transform="translate(40,0)"
+     id="g4215">
+    <path
+       transform="translate(-100,0)"
+       d="m 103.25,-4.7795e-7 c -0.7,0 -1.25,0.49999999795 -1.25,1.24999997795 v 7.5 c 0,0.7 0.5,1.25 1.25,1.25 h 3.5 c 0.7,0 1.25,-0.5 1.25,-1.25 v -7.5 C 108,0.54999952 107.5,-4.7795e-7 106.75,-4.7795e-7 z M 103,0.99999952 h 4 V 7.9999995 h -4 z m 2,7.24999998 c 0.4,0 0.75,0.3 0.75,0.75 0,0.4 -0.3,0.75 -0.75,0.75 -0.4,0 -0.75,-0.3 -0.75,-0.75 0,-0.4 0.3,-0.75 0.75,-0.75 z"
+       id="path4219"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(40,20)" id="g4221">
-    <path transform="translate(-20,0)" d="m 25,-4.7795e-7 c -2.76,0 -5,2.23999997795 -5,4.99999997795 0,2.76 2.24,5 5,5 2.76,0 5,-2.24 5,-5 C 30,2.2399995 27.76,-4.7795e-7 25,-4.7795e-7" id="path4225" inkscape:connector-curvature="0" style="fill:url(#sprite6_a)"/><path transform="translate(-20,0)" d="m 20.36,5 c 0,2.56 2.08,4.64 4.64,4.64 2.56,0 4.64,-2.08 4.64,-4.64 0,-2.56 -2.08,-4.64 -4.64,-4.64 -2.56,0 -4.64,2.08 -4.64,4.64" id="path4227" inkscape:connector-curvature="0" style="fill:#eb3941"/><path transform="translate(-20,0)" d="m 23,3 4,4" id="path4229" inkscape:connector-curvature="0" style="stroke:#ffffff"/><path transform="translate(-20,0)" d="M 27,3 23,7" id="path4231" inkscape:connector-curvature="0" style="stroke:#ffffff"/><defs id="defs4233">
-        <linearGradient id="sprite6_b">
-          <stop stop-color="#d7687d" offset="0" id="stop4236"/>
-          <stop stop-color="#b21402" offset="1" id="stop4238"/>
-        </linearGradient>
-        <linearGradient id="sprite6_a" x2="24" gradientTransform="matrix(0,-0.41667,-0.41667,0,25,10)" gradientUnits="userSpaceOnUse" xlink:href="#sprite6_b"/>
-      </defs>
+  <g
+     transform="translate(40,20)"
+     id="g4221">
+    <path
+       transform="translate(-20,0)"
+       d="m 25,-4.7795e-7 c -2.76,0 -5,2.23999997795 -5,4.99999997795 0,2.76 2.24,5 5,5 2.76,0 5,-2.24 5,-5 C 30,2.2399995 27.76,-4.7795e-7 25,-4.7795e-7"
+       id="path4225"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite6_a)" />
+    <path
+       transform="translate(-20,0)"
+       d="m 20.36,5 c 0,2.56 2.08,4.64 4.64,4.64 2.56,0 4.64,-2.08 4.64,-4.64 0,-2.56 -2.08,-4.64 -4.64,-4.64 -2.56,0 -4.64,2.08 -4.64,4.64"
+       id="path4227"
+       inkscape:connector-curvature="0"
+       style="fill:#eb3941" />
+    <path
+       transform="translate(-20,0)"
+       d="m 23,3 4,4"
+       id="path4229"
+       inkscape:connector-curvature="0"
+       style="stroke:#ffffff" />
+    <path
+       transform="translate(-20,0)"
+       d="M 27,3 23,7"
+       id="path4231"
+       inkscape:connector-curvature="0"
+       style="stroke:#ffffff" />
+    <defs
+       id="defs4233">
+      <linearGradient
+         id="sprite6_b">
+        <stop
+           stop-color="#d7687d"
+           offset="0"
+           id="stop4236" />
+        <stop
+           stop-color="#b21402"
+           offset="1"
+           id="stop4238" />
+      </linearGradient>
+      <linearGradient
+         id="sprite6_a"
+         x2="24"
+         gradientTransform="matrix(0,-0.41667,-0.41667,0,25,10)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite6_b" />
+    </defs>
   </g>
-  <g transform="translate(0,40)" id="g4241">
-    <path transform="matrix(-0.89336,0,0,0.81469,170.27,-15.367)" d="m 186,20 -5,5 5,5 v -2 h 3 v -6 h -3.0004 z" id="path4245" inkscape:connector-curvature="0" style="fill:#adf2ad;stroke:#007200"/>
+  <path
+     style="fill:#adf2ad;stroke:#007200;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+     inkscape:connector-curvature="0"
+     id="path4245"
+     d="M 4.4998214,41.3 8.5,45.00025 4.4998214,48.7 l 0,-1.2 -3.0748614,0 0.07504,-5 3.0001787,0 z"
+     sodipodi:nodetypes="cccccccc" />
+  <g
+     transform="translate(20,40)"
+     id="g4247">
+    <path
+       transform="translate(-140,0)"
+       d="m 144.95,9.9997 c -2.7598,-0.03 -4.9797,-2.2899 -4.9497,-5.0497 0.03,-2.7598 2.2899,-4.9797 5.0497,-4.9497 2.7598,0.03 4.9797,2.2899 4.9497,5.0497 -0.03,2.7598 -2.2899,4.9797 -5.0497,4.9497 z"
+       id="path4251"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite8_a)" />
+    <path
+       transform="translate(-140,0)"
+       d="m 149.5,5.05 c -0.03,2.4898 -2.0599,4.4797 -4.5497,4.4497 -2.4898,-0.03 -4.4797,-2.0598 -4.4497,-4.5497 0.03,-2.4898 2.0599,-4.4797 4.5497,-4.4497 2.4898,0.03 4.4797,2.0598 4.4497,4.5497 z"
+       id="path4253"
+       inkscape:connector-curvature="0"
+       style="fill:#00be00" />
+    <path
+       transform="translate(-140,0)"
+       d="m 145.08,0.5303 c 1.9699,0.02 3.5498,1.0599 3.5398,2.3198 -0.01,1.26 -1.6199,2.2599 -3.5898,2.2399 -1.9699,-0.02 -3.5498,-1.0599 -3.5398,-2.3199 0.01,-1.2599 1.6199,-2.2598 3.5898,-2.2398 z"
+       id="path4255"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite8_b)" />
+    <path
+       transform="translate(-140,0)"
+       d="m 144.98,9.4097 c 1.6599,0.02 3.0098,-0.6799 3.0198,-1.5599 0.01,-0.8799 -1.3299,-1.6099 -2.9798,-1.6299 -1.6599,-0.02 -3.0098,0.68 -3.0198,1.5599 -0.01,0.88 1.3299,1.6099 2.9798,1.6299 z"
+       id="path4257"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite8_c)" />
+    <defs
+       id="defs4259">
+      <linearGradient
+         id="sprite8_j">
+        <stop
+           stop-color="#00d600"
+           stop-opacity="0"
+           offset="0"
+           id="stop4262" />
+        <stop
+           stop-color="#d8fc7b"
+           stop-opacity=".81"
+           offset="1"
+           id="stop4264" />
+      </linearGradient>
+      <linearGradient
+         id="sprite8_k">
+        <stop
+           stop-color="#00ba00"
+           offset="0"
+           id="stop4267" />
+        <stop
+           stop-color="#fff"
+           stop-opacity=".91"
+           offset="1"
+           id="stop4269" />
+      </linearGradient>
+      <linearGradient
+         id="sprite8_l">
+        <stop
+           stop-color="#00a104"
+           offset="0"
+           id="stop4272" />
+        <stop
+           stop-color="#00c605"
+           offset="1"
+           id="stop4274" />
+      </linearGradient>
+      <linearGradient
+         id="sprite8_c"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(-0.0048,0.4396,0.78038,0.00853,65.608,-94.834)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite8_j" />
+      <linearGradient
+         id="sprite8_b"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(0.00687,-0.62923,0.9267,0.01012,47.871,147.44)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite8_k" />
+      <linearGradient
+         id="sprite8_a"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(-0.01507,1.3791,-1.3006,-0.0142,282.66,-312.8)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite8_l" />
+    </defs>
   </g>
-  <g transform="translate(20,40)" id="g4247">
-    <path transform="translate(-140,0)" d="m 144.95,9.9997 c -2.7598,-0.03 -4.9797,-2.2899 -4.9497,-5.0497 0.03,-2.7598 2.2899,-4.9797 5.0497,-4.9497 2.7598,0.03 4.9797,2.2899 4.9497,5.0497 -0.03,2.7598 -2.2899,4.9797 -5.0497,4.9497 z" id="path4251" inkscape:connector-curvature="0" style="fill:url(#sprite8_a)"/><path transform="translate(-140,0)" d="m 149.5,5.05 c -0.03,2.4898 -2.0599,4.4797 -4.5497,4.4497 -2.4898,-0.03 -4.4797,-2.0598 -4.4497,-4.5497 0.03,-2.4898 2.0599,-4.4797 4.5497,-4.4497 2.4898,0.03 4.4797,2.0598 4.4497,4.5497 z" id="path4253" inkscape:connector-curvature="0" style="fill:#00be00"/><path transform="translate(-140,0)" d="m 145.08,0.5303 c 1.9699,0.02 3.5498,1.0599 3.5398,2.3198 -0.01,1.26 -1.6199,2.2599 -3.5898,2.2399 -1.9699,-0.02 -3.5498,-1.0599 -3.5398,-2.3199 0.01,-1.2599 1.6199,-2.2598 3.5898,-2.2398 z" id="path4255" inkscape:connector-curvature="0" style="fill:url(#sprite8_b)"/><path transform="translate(-140,0)" d="m 144.98,9.4097 c 1.6599,0.02 3.0098,-0.6799 3.0198,-1.5599 0.01,-0.8799 -1.3299,-1.6099 -2.9798,-1.6299 -1.6599,-0.02 -3.0098,0.68 -3.0198,1.5599 -0.01,0.88 1.3299,1.6099 2.9798,1.6299 z" id="path4257" inkscape:connector-curvature="0" style="fill:url(#sprite8_c)"/><defs id="defs4259">
-        <linearGradient id="sprite8_j">
-          <stop stop-color="#00d600" stop-opacity="0" offset="0" id="stop4262"/>
-          <stop stop-color="#d8fc7b" stop-opacity=".81" offset="1" id="stop4264"/>
-        </linearGradient>
-        <linearGradient id="sprite8_k">
-          <stop stop-color="#00ba00" offset="0" id="stop4267"/>
-          <stop stop-color="#fff" stop-opacity=".91" offset="1" id="stop4269"/>
-        </linearGradient>
-        <linearGradient id="sprite8_l">
-          <stop stop-color="#00a104" offset="0" id="stop4272"/>
-          <stop stop-color="#00c605" offset="1" id="stop4274"/>
-        </linearGradient>
-        <linearGradient id="sprite8_c" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(-0.0048,0.4396,0.78038,0.00853,65.608,-94.834)" gradientUnits="userSpaceOnUse" xlink:href="#sprite8_j"/>
-        <linearGradient id="sprite8_b" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(0.00687,-0.62923,0.9267,0.01012,47.871,147.44)" gradientUnits="userSpaceOnUse" xlink:href="#sprite8_k"/>
-        <linearGradient id="sprite8_a" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(-0.01507,1.3791,-1.3006,-0.0142,282.66,-312.8)" gradientUnits="userSpaceOnUse" xlink:href="#sprite8_l"/>
-      </defs>
+  <g
+     transform="translate(40,40)"
+     id="g4279">
+    <path
+       transform="translate(-80,0)"
+       d="m 85,-4.7795e-7 c -2.76,0 -5,2.23999997795 -5,4.99999997795 0,2.76 2.24,5 5,5 2.76,0 5,-2.24 5,-5 C 90,2.2399995 87.76,-4.7795e-7 85,-4.7795e-7"
+       id="path4283"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite9_a)" />
+    <path
+       transform="translate(-80,0)"
+       d="m 80.36,5 c 0,2.56 2.08,4.64 4.64,4.64 2.56,0 4.64,-2.08 4.64,-4.64 0,-2.56 -2.08,-4.64 -4.64,-4.64 -2.56,0 -4.64,2.08 -4.64,4.64"
+       id="path4285"
+       inkscape:connector-curvature="0"
+       style="fill:#2a53cd" />
+    <path
+       transform="translate(-80,0)"
+       d="m 83.93,2.14 c -0.03,-0.53 0.55,-0.97 1.06,-0.83 0.5,0.12 0.79,0.73 0.56,1.18 -0.2,0.44 -0.79,0.61 -1.2,0.36 C 84.09,2.71 83.93,2.43 83.93,2.14 z m 1.7,5.46 H 86.3 V 8.13 H 83.41 V 7.6 h 0.66 V 3.99 H 83.41 V 3.46 h 2.22 V 7.6 z"
+       id="path4287"
+       inkscape:connector-curvature="0"
+       style="fill:#ffffff" />
+    <defs
+       id="defs4289">
+      <linearGradient
+         id="sprite9_d">
+        <stop
+           stop-color="#606eda"
+           offset="0"
+           id="stop4292" />
+        <stop
+           stop-color="#021db2"
+           offset="1"
+           id="stop4294" />
+      </linearGradient>
+      <linearGradient
+         id="sprite9_a"
+         x1="113"
+         x2="127"
+         y1="104"
+         y2="104"
+         gradientTransform="matrix(0.71429,0,0,0.71429,-0.714,-69.286)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite9_d" />
+    </defs>
   </g>
-  <g transform="translate(40,40)" id="g4279">
-    <path transform="translate(-80,0)" d="m 85,-4.7795e-7 c -2.76,0 -5,2.23999997795 -5,4.99999997795 0,2.76 2.24,5 5,5 2.76,0 5,-2.24 5,-5 C 90,2.2399995 87.76,-4.7795e-7 85,-4.7795e-7" id="path4283" inkscape:connector-curvature="0" style="fill:url(#sprite9_a)"/><path transform="translate(-80,0)" d="m 80.36,5 c 0,2.56 2.08,4.64 4.64,4.64 2.56,0 4.64,-2.08 4.64,-4.64 0,-2.56 -2.08,-4.64 -4.64,-4.64 -2.56,0 -4.64,2.08 -4.64,4.64" id="path4285" inkscape:connector-curvature="0" style="fill:#2a53cd"/><path transform="translate(-80,0)" d="m 83.93,2.14 c -0.03,-0.53 0.55,-0.97 1.06,-0.83 0.5,0.12 0.79,0.73 0.56,1.18 -0.2,0.44 -0.79,0.61 -1.2,0.36 C 84.09,2.71 83.93,2.43 83.93,2.14 z m 1.7,5.46 H 86.3 V 8.13 H 83.41 V 7.6 h 0.66 V 3.99 H 83.41 V 3.46 h 2.22 V 7.6 z" id="path4287" inkscape:connector-curvature="0" style="fill:#ffffff"/><defs id="defs4289">
-        <linearGradient id="sprite9_d">
-          <stop stop-color="#606eda" offset="0" id="stop4292"/>
-          <stop stop-color="#021db2" offset="1" id="stop4294"/>
-        </linearGradient>
-        <linearGradient id="sprite9_a" x1="113" x2="127" y1="104" y2="104" gradientTransform="matrix(0.71429,0,0,0.71429,-0.714,-69.286)" gradientUnits="userSpaceOnUse" xlink:href="#sprite9_d"/>
-      </defs>
+  <g
+     transform="translate(60,0)"
+     id="g4297">
+    <path
+       transform="translate(-160,-20)"
+       d="m 160.45,20.467 v 9.079 h 5.373 l 3.5821,-4.5398 -3.5821,-4.5392 z"
+       id="path4301"
+       inkscape:connector-curvature="0"
+       style="fill:#698cfe;stroke:#4073f4;stroke-width:0.90799999" />
   </g>
-  <g transform="translate(60,0)" id="g4297">
-    <path transform="translate(-160,-20)" d="m 160.45,20.467 v 9.079 h 5.373 l 3.5821,-4.5398 -3.5821,-4.5392 z" id="path4301" inkscape:connector-curvature="0" style="fill:#698cfe;stroke:#4073f4;stroke-width:0.90799999"/>
+  <g
+     transform="translate(60,20)"
+     id="g4303">
+    <path
+       transform="translate(-140,-20)"
+       d="m 140.45,20.467 v 9.0791 h 5.3718 l 3.5813,-4.54 -3.5813,-4.5391 z"
+       id="path4307"
+       inkscape:connector-curvature="0"
+       style="fill:#ef9d0d;stroke:#a36c01;stroke-width:0.90799999" />
   </g>
-  <g transform="translate(60,20)" id="g4303">
-    <path transform="translate(-140,-20)" d="m 140.45,20.467 v 9.0791 h 5.3718 l 3.5813,-4.54 -3.5813,-4.5391 z" id="path4307" inkscape:connector-curvature="0" style="fill:#ef9d0d;stroke:#a36c01;stroke-width:0.90799999"/>
+  <g
+     transform="translate(60,40)"
+     id="g4309">
+    <path
+       transform="translate(-160,0)"
+       d="m 165,10 c -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 0,2.76 -2.24,5 -5,5 z"
+       id="path4313"
+       inkscape:connector-curvature="0"
+       style="fill:#e5a600" />
+    <path
+       transform="translate(-160,0)"
+       d="m 169.5,5 c 0,2.49 -2.01,4.5 -4.5,4.5 -2.49,0 -4.5,-2.01 -4.5,-4.5 0,-2.49 2.01,-4.5 4.5,-4.5 2.49,0 4.5,2.01 4.5,4.5 z"
+       id="path4315"
+       inkscape:connector-curvature="0"
+       style="fill:#ffbd00" />
+    <path
+       transform="translate(-160,0)"
+       d="m 165.03,0.53 c 1.97,0 3.56,1.02 3.56,2.28 0,1.26 -1.59,2.28 -3.56,2.28 -1.97,0 -3.56,-1.02 -3.56,-2.28 0,-1.26 1.59,-2.28 3.56,-2.28 z"
+       id="path4317"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite12_a)" />
+    <path
+       transform="translate(-160,0)"
+       d="m 164.99,9.42 c 1.66,0 3,-0.71 3,-1.59 0,-0.88 -1.34,-1.59 -3,-1.59 -1.66,0 -3,0.71 -3,1.59 0,0.88 1.34,1.59 3,1.59 z"
+       id="path4319"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite12_b)" />
+    <defs
+       id="defs4321">
+      <linearGradient
+         id="sprite12_l">
+        <stop
+           stop-color="#ffa801"
+           stop-opacity="0"
+           offset="0"
+           id="stop4324" />
+        <stop
+           stop-color="#f0fb3d"
+           offset="1"
+           id="stop4326" />
+      </linearGradient>
+      <linearGradient
+         id="sprite12_m">
+        <stop
+           stop-color="#ffbd00"
+           stop-opacity=".65"
+           offset="0"
+           id="stop4329" />
+        <stop
+           stop-color="#fff"
+           stop-opacity=".91"
+           offset="1"
+           id="stop4331" />
+      </linearGradient>
+      <linearGradient
+         id="sprite12_b"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(0,0.43966,0.78049,0,84.444,-93.924)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite12_l" />
+      <linearGradient
+         id="sprite12_a"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(0,-0.62931,0.92683,0,69.47,148.53)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite12_m" />
+    </defs>
   </g>
-  <g transform="translate(60,40)" id="g4309">
-    <path transform="translate(-160,0)" d="m 165,10 c -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 0,2.76 -2.24,5 -5,5 z" id="path4313" inkscape:connector-curvature="0" style="fill:#e5a600"/><path transform="translate(-160,0)" d="m 169.5,5 c 0,2.49 -2.01,4.5 -4.5,4.5 -2.49,0 -4.5,-2.01 -4.5,-4.5 0,-2.49 2.01,-4.5 4.5,-4.5 2.49,0 4.5,2.01 4.5,4.5 z" id="path4315" inkscape:connector-curvature="0" style="fill:#ffbd00"/><path transform="translate(-160,0)" d="m 165.03,0.53 c 1.97,0 3.56,1.02 3.56,2.28 0,1.26 -1.59,2.28 -3.56,2.28 -1.97,0 -3.56,-1.02 -3.56,-2.28 0,-1.26 1.59,-2.28 3.56,-2.28 z" id="path4317" inkscape:connector-curvature="0" style="fill:url(#sprite12_a)"/><path transform="translate(-160,0)" d="m 164.99,9.42 c 1.66,0 3,-0.71 3,-1.59 0,-0.88 -1.34,-1.59 -3,-1.59 -1.66,0 -3,0.71 -3,1.59 0,0.88 1.34,1.59 3,1.59 z" id="path4319" inkscape:connector-curvature="0" style="fill:url(#sprite12_b)"/><defs id="defs4321">
-        <linearGradient id="sprite12_l">
-          <stop stop-color="#ffa801" stop-opacity="0" offset="0" id="stop4324"/>
-          <stop stop-color="#f0fb3d" offset="1" id="stop4326"/>
-        </linearGradient>
-        <linearGradient id="sprite12_m">
-          <stop stop-color="#ffbd00" stop-opacity=".65" offset="0" id="stop4329"/>
-          <stop stop-color="#fff" stop-opacity=".91" offset="1" id="stop4331"/>
-        </linearGradient>
-        <linearGradient id="sprite12_b" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(0,0.43966,0.78049,0,84.444,-93.924)" gradientUnits="userSpaceOnUse" xlink:href="#sprite12_l"/>
-        <linearGradient id="sprite12_a" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(0,-0.62931,0.92683,0,69.47,148.53)" gradientUnits="userSpaceOnUse" xlink:href="#sprite12_m"/>
-      </defs>
+  <g
+     transform="translate(0,60)"
+     id="g4335">
+    <path
+       transform="translate(-120,0)"
+       d="m 125,10 c -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 0,2.76 -2.24,5 -5,5 z"
+       id="path4339"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite13_a)" />
+    <path
+       transform="translate(-120,0)"
+       d="m 129.5,5 c 0,2.49 -2.01,4.5 -4.5,4.5 -2.49,0 -4.5,-2.01 -4.5,-4.5 0,-2.49 2.01,-4.5 4.5,-4.5 2.49,0 4.5,2.01 4.5,4.5 z"
+       id="path4341"
+       inkscape:connector-curvature="0"
+       style="fill:#dd0000" />
+    <path
+       transform="translate(-120,0)"
+       d="m 125.03,0.53 c 1.97,0 3.56,1.02 3.56,2.28 0,1.26 -1.59,2.28 -3.56,2.28 -1.97,0 -3.56,-1.02 -3.56,-2.28 0,-1.26 1.59,-2.28 3.56,-2.28 z"
+       id="path4343"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite13_b)" />
+    <path
+       transform="translate(-120,0)"
+       d="m 125.03,9.47 c 1.66,0 3,-0.71 3,-1.59 0,-0.88 -1.34,-1.59 -3,-1.59 -1.66,0 -3,0.71 -3,1.59 0,0.88 1.34,1.59 3,1.59 z"
+       id="path4345"
+       inkscape:connector-curvature="0"
+       style="fill:url(#sprite13_c)" />
+    <defs
+       id="defs4347">
+      <linearGradient
+         id="sprite13_g">
+        <stop
+           stop-color="red"
+           stop-opacity="0"
+           offset="0"
+           id="stop4350" />
+        <stop
+           stop-color="#f0cb68"
+           stop-opacity=".71"
+           offset="1"
+           id="stop4352" />
+      </linearGradient>
+      <linearGradient
+         id="sprite13_h">
+        <stop
+           stop-color="#e60000"
+           stop-opacity=".65"
+           offset="0"
+           id="stop4355" />
+        <stop
+           stop-color="#fff"
+           stop-opacity=".91"
+           offset="1"
+           id="stop4357" />
+      </linearGradient>
+      <linearGradient
+         id="sprite13_i">
+        <stop
+           stop-color="#a10000"
+           offset="0"
+           id="stop4360" />
+        <stop
+           stop-color="#c60000"
+           offset="1"
+           id="stop4362" />
+      </linearGradient>
+      <linearGradient
+         id="sprite13_c"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(0,0.43966,0.78049,0,44.488,-93.88)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite13_g" />
+      <linearGradient
+         id="sprite13_b"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(0,-0.62931,0.92683,0,29.47,148.53)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite13_h" />
+      <linearGradient
+         id="sprite13_a"
+         x1="227.88"
+         x2="235.12"
+         y1="103.16"
+         y2="103.16"
+         gradientTransform="matrix(0,1.3793,-1.3008,0,259.08,-314.35)"
+         gradientUnits="userSpaceOnUse"
+         xlink:href="#sprite13_i" />
+    </defs>
   </g>
-  <g transform="translate(0,60)" id="g4335">
-    <path transform="translate(-120,0)" d="m 125,10 c -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 0,2.76 -2.24,5 -5,5 z" id="path4339" inkscape:connector-curvature="0" style="fill:url(#sprite13_a)"/><path transform="translate(-120,0)" d="m 129.5,5 c 0,2.49 -2.01,4.5 -4.5,4.5 -2.49,0 -4.5,-2.01 -4.5,-4.5 0,-2.49 2.01,-4.5 4.5,-4.5 2.49,0 4.5,2.01 4.5,4.5 z" id="path4341" inkscape:connector-curvature="0" style="fill:#dd0000"/><path transform="translate(-120,0)" d="m 125.03,0.53 c 1.97,0 3.56,1.02 3.56,2.28 0,1.26 -1.59,2.28 -3.56,2.28 -1.97,0 -3.56,-1.02 -3.56,-2.28 0,-1.26 1.59,-2.28 3.56,-2.28 z" id="path4343" inkscape:connector-curvature="0" style="fill:url(#sprite13_b)"/><path transform="translate(-120,0)" d="m 125.03,9.47 c 1.66,0 3,-0.71 3,-1.59 0,-0.88 -1.34,-1.59 -3,-1.59 -1.66,0 -3,0.71 -3,1.59 0,0.88 1.34,1.59 3,1.59 z" id="path4345" inkscape:connector-curvature="0" style="fill:url(#sprite13_c)"/><defs id="defs4347">
-        <linearGradient id="sprite13_g">
-          <stop stop-color="red" stop-opacity="0" offset="0" id="stop4350"/>
-          <stop stop-color="#f0cb68" stop-opacity=".71" offset="1" id="stop4352"/>
-        </linearGradient>
-        <linearGradient id="sprite13_h">
-          <stop stop-color="#e60000" stop-opacity=".65" offset="0" id="stop4355"/>
-          <stop stop-color="#fff" stop-opacity=".91" offset="1" id="stop4357"/>
-        </linearGradient>
-        <linearGradient id="sprite13_i">
-          <stop stop-color="#a10000" offset="0" id="stop4360"/>
-          <stop stop-color="#c60000" offset="1" id="stop4362"/>
-        </linearGradient>
-        <linearGradient id="sprite13_c" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(0,0.43966,0.78049,0,44.488,-93.88)" gradientUnits="userSpaceOnUse" xlink:href="#sprite13_g"/>
-        <linearGradient id="sprite13_b" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(0,-0.62931,0.92683,0,29.47,148.53)" gradientUnits="userSpaceOnUse" xlink:href="#sprite13_h"/>
-        <linearGradient id="sprite13_a" x1="227.88" x2="235.12" y1="103.16" y2="103.16" gradientTransform="matrix(0,1.3793,-1.3008,0,259.08,-314.35)" gradientUnits="userSpaceOnUse" xlink:href="#sprite13_i"/>
-      </defs>
+  <g
+     transform="translate(20,60)"
+     id="g4367">
+    <path
+       transform="translate(-60,-20)"
+       d="M 60,20 H 70 V 30 H 60 z"
+       id="path4371"
+       inkscape:connector-curvature="0"
+       style="fill:none" />
+    <path
+       transform="translate(-60,-20)"
+       d="M 67.5,22.5 V 20 H 60 v 7.5 h 2.5 V 30 H 70 V 22.5 z M 61,21 h 5.5 v 5.5 H 61 z m 2.5,6.5 h 4 v -4 H 69 V 29 h -5.5 z"
+       id="path4373"
+       inkscape:connector-curvature="0" />
+    <path
+       d="m 3.5,7.5 h 4 v -4 H 9 V 9 H 3.5 z"
+       id="path4375"
+       inkscape:connector-curvature="0"
+       style="fill-opacity:0.25" />
   </g>
-  <g transform="translate(20,60)" id="g4367">
-    <path transform="translate(-60,-20)" d="M 60,20 H 70 V 30 H 60 z" id="path4371" inkscape:connector-curvature="0" style="fill:none"/><path transform="translate(-60,-20)" d="M 67.5,22.5 V 20 H 60 v 7.5 h 2.5 V 30 H 70 V 22.5 z M 61,21 h 5.5 v 5.5 H 61 z m 2.5,6.5 h 4 v -4 H 69 V 29 h -5.5 z" id="path4373" inkscape:connector-curvature="0"/><path d="m 3.5,7.5 h 4 v -4 H 9 V 9 H 3.5 z" id="path4375" inkscape:connector-curvature="0" style="fill-opacity:0.25"/>
+  <g
+     id="g4383"
+     style="fill:#acf2ae;stroke:#007200;stroke-width:2.5769999"
+     transform="translate(40,60)">
+    <path
+       transform="matrix(0.29356,0,0,0.2909,-37.35,6.864)"
+       d="m 144.95,9.9997 c -2.7598,-0.03 -4.9797,-2.2899 -4.9497,-5.0497 0.03,-2.7598 2.2899,-4.9797 5.0497,-4.9497 2.7598,0.03 4.9797,2.2899 4.9497,5.0497 -0.03,2.7598 -2.2899,4.9797 -5.0497,4.9497 z"
+       id="path4385"
+       inkscape:connector-curvature="0" />
+    <path
+       transform="matrix(0.29356,0,0,0.2909,-37.35,6.864)"
+       d="m 149.5,5.05 c -0.03,2.4898 -2.0599,4.4797 -4.5497,4.4497 -2.4898,-0.03 -4.4797,-2.0598 -4.4497,-4.5497 0.03,-2.4898 2.0599,-4.4797 4.5497,-4.4497 2.4898,0.03 4.4797,2.0598 4.4497,4.5497 z"
+       id="path4387"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(40,60)" id="g4377">
-    <g id="g4381" style="stroke:#007200">
-        <g id="g4383" style="fill:#acf2ae;stroke-width:2.5769999">
-          <path transform="matrix(0.29356,0,0,0.2909,-37.35,6.864)" d="m 144.95,9.9997 c -2.7598,-0.03 -4.9797,-2.2899 -4.9497,-5.0497 0.03,-2.7598 2.2899,-4.9797 5.0497,-4.9497 2.7598,0.03 4.9797,2.2899 4.9497,5.0497 -0.03,2.7598 -2.2899,4.9797 -5.0497,4.9497 z" id="path4385" inkscape:connector-curvature="0"/>
-          <path transform="matrix(0.29356,0,0,0.2909,-37.35,6.864)" d="m 149.5,5.05 c -0.03,2.4898 -2.0599,4.4797 -4.5497,4.4497 -2.4898,-0.03 -4.4797,-2.0598 -4.4497,-4.5497 0.03,-2.4898 2.0599,-4.4797 4.5497,-4.4497 2.4898,0.03 4.4797,2.0598 4.4497,4.5497 z" id="path4387" inkscape:connector-curvature="0"/>
-        </g>
-        <path transform="matrix(0,-0.67745,-0.62037,0,20.72,128.46)" d="m 186,20 -5,5 5,5 v -2 h 3 v -6 h -3.0004 z" id="path4389" inkscape:connector-curvature="0" style="fill:#adf2ad;stroke-width:1.31599998"/>
-      </g>
+  <path
+     d="M 48.3126,62.499864 45.21075,66 42.1089,62.499864 l 1.24074,0 0,-1.919464 3.72222,0 0,1.919735 z"
+     id="path4389"
+     inkscape:connector-curvature="0"
+     style="fill:#adf2ad;stroke:#007200;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+     sodipodi:nodetypes="cccccccc" />
+  <path
+     d="m 66.5375,68.5145 c -0.0088,0.72431 -0.6047,1.3032 -1.3356,1.2945 -0.73092,-0.0087 -1.3151,-0.59922 -1.3063,-1.3236 0.0088,-0.7243 0.6047,-1.3032 1.3356,-1.2945 0.73092,0.0087 1.3151,0.59922 1.3063,1.3235 z"
+     id="path4397"
+     inkscape:connector-curvature="0"
+     style="fill:#acf2ae;stroke:#007200;stroke-width:0.75300002" />
+  <path
+     d="m 62.1084,63.500135 3.10185,-2.981685 3.10185,2.981685 -1.24074,0 0,1.999865 -3.72222,0 0,-2.000136 z"
+     id="path4399"
+     inkscape:connector-curvature="0"
+     style="fill:#adf2ad;stroke:#007200;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none"
+     sodipodi:nodetypes="cccccccc" />
+  <g
+     transform="translate(80,0)"
+     id="g4401">
+    <path
+       transform="translate(-20,-20)"
+       d="m 23.25,21.75 3.5,3.25 -3.5,3.25"
+       id="path4405"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#367cf1;stroke-width:1.5" />
   </g>
-  <g transform="translate(60,60)" id="g4391">
-    <g id="g4395" style="stroke:#007200">
-        <path d="M 6.5375,8.5145 C 6.5287,9.23881 5.9328,9.8177 5.2019,9.809 4.47098,9.8003 3.8868,9.20978 3.8956,8.4854 3.9044,7.7611 4.5003,7.1822 5.2312,7.1909 5.96212,7.1996 6.5463,7.79012 6.5375,8.5144 z" id="path4397" inkscape:connector-curvature="0" style="fill:#acf2ae;stroke-width:0.75300002"/>
-        <path transform="matrix(0,0.67745,0.62037,0,-10.299,-122.1)" d="m 186,20 -5,5 5,5 v -2 h 3 v -6 h -3.0004 z" id="path4399" inkscape:connector-curvature="0" style="fill:#adf2ad;stroke-width:1.31599998"/>
-      </g>
+  <g
+     transform="translate(80,20)"
+     id="g4407">
+    <path
+       transform="translate(-180,-20)"
+       d="m 186,20 -5,5 5,5 v -2 h 3 v -6 h -3 z"
+       id="path4411"
+       inkscape:connector-curvature="0"
+       style="fill:#4688f1" />
   </g>
-  <g transform="translate(80,0)" id="g4401">
-    <path transform="translate(-20,-20)" d="m 23.25,21.75 3.5,3.25 -3.5,3.25" id="path4405" inkscape:connector-curvature="0" style="fill:none;stroke:#367cf1;stroke-width:1.5"/>
+  <g
+     transform="translate(80,40)"
+     id="g4413">
+    <path
+       transform="matrix(-1,0,0,1,190,-19.955)"
+       d="m 186,19.955 -5,5 5,5.0225 0,-2.045 3,0.0225 0,-6 -3,0 z"
+       id="path4417"
+       inkscape:connector-curvature="0"
+       style="fill:#4688f1"
+       sodipodi:nodetypes="cccccccc" />
   </g>
-  <g transform="translate(80,20)" id="g4407">
-    <path transform="translate(-180,-20)" d="m 186,20 -5,5 5,5 v -2 h 3 v -6 h -3 z" id="path4411" inkscape:connector-curvature="0" style="fill:#4688f1"/>
+  <g
+     transform="translate(80,60)"
+     id="g4419">
+    <path
+       transform="translate(-20,-98)"
+       d="m 24,106 4,-7 h -8"
+       id="path4423"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(80,40)" id="g4413">
-    <path transform="matrix(-1,0,0,1,190,-19.955)" d="m 186,20 -5,5 5,5 v -2 h 3 v -6 h -3 z" id="path4417" inkscape:connector-curvature="0" style="fill:#4688f1"/>
+  <g
+     transform="translate(0,80)"
+     id="g4425">
+    <path
+       transform="translate(-4,-98)"
+       d="M 12,102 5,98 v 8"
+       id="path4429"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(80,60)" id="g4419">
-    <path transform="translate(-20,-98)" d="m 24,106 4,-7 h -8" id="path4423" inkscape:connector-curvature="0"/>
+  <g
+     transform="translate(20,80)"
+     id="g4431">
+    <path
+       transform="translate(-4,-111)"
+       d="m 8,111 4,7 H 4"
+       id="path4435"
+       inkscape:connector-curvature="0" />
   </g>
-  <g transform="translate(0,80)" id="g4425">
-    <path transform="translate(-4,-98)" d="M 12,102 5,98 v 8" id="path4429" inkscape:connector-curvature="0"/>
+  <g
+     transform="translate(40,80)"
+     id="g4437">
+    <path
+       transform="translate(0,-19)"
+       d="m 3.2503,21.75 3.5,3.25 -3.5,3.25"
+       id="path4441"
+       inkscape:connector-curvature="0"
+       style="fill:none;stroke:#939393;stroke-width:1.5" />
   </g>
-  <g transform="translate(20,80)" id="g4431">
-    <path transform="translate(-4,-111)" d="m 8,111 4,7 H 4" id="path4435" inkscape:connector-curvature="0"/>
+  <g
+     transform="translate(60,80)"
+     id="g4443">
+    <path
+       transform="translate(-60,0)"
+       d="m 61,9 4,-8 4,8 z"
+       id="path4447"
+       inkscape:connector-curvature="0"
+       style="stroke:#c19600;stroke-width:2;stroke-linejoin:round" />
+    <path
+       transform="translate(-60,0)"
+       d="m 61,9 4,-8 4,8 z"
+       id="path4449"
+       inkscape:connector-curvature="0"
+       style="fill:#f4bd00;stroke:#f5bd00;stroke-width:1.5;stroke-linejoin:round" />
+    <path
+       transform="translate(-60,0)"
+       d="m 63.75,2.75 h 2.5 v 2.5 L 65.75,7 h -1.5 l -0.5,-1.75 v -2.5 m 0,5.25 h 2.5 v 1.25 h -2.5"
+       id="path4451"
+       inkscape:connector-curvature="0"
+       style="fill:#ad8601" />
+    <path
+       transform="translate(-60,0)"
+       d="m 64,3 h 2 V 5.25 L 65.5,7 h -1 L 64,5.25 V 3 m 0,5 h 2 v 1 h -2"
+       id="path4453"
+       inkscape:connector-curvature="0"
+       style="fill:#ffffff" />
   </g>
-  <g transform="translate(40,80)" id="g4437">
-    <path transform="translate(0,-19)" d="m 3.2503,21.75 3.5,3.25 -3.5,3.25" id="path4441" inkscape:connector-curvature="0" style="fill:none;stroke:#939393;stroke-width:1.5"/>
-  </g>
-  <g transform="translate(60,80)" id="g4443">
-    <path transform="translate(-60,0)" d="m 61,9 4,-8 4,8 z" id="path4447" inkscape:connector-curvature="0" style="stroke:#c19600;stroke-width:2;stroke-linejoin:round"/><path transform="translate(-60,0)" d="m 61,9 4,-8 4,8 z" id="path4449" inkscape:connector-curvature="0" style="fill:#f4bd00;stroke:#f5bd00;stroke-width:1.5;stroke-linejoin:round"/><path transform="translate(-60,0)" d="m 63.75,2.75 h 2.5 v 2.5 L 65.75,7 h -1.5 l -0.5,-1.75 v -2.5 m 0,5.25 h 2.5 v 1.25 h -2.5" id="path4451" inkscape:connector-curvature="0" style="fill:#ad8601"/><path transform="translate(-60,0)" d="m 64,3 h 2 V 5.25 L 65.5,7 h -1 L 64,5.25 V 3 m 0,5 h 2 v 1 h -2" id="path4453" inkscape:connector-curvature="0" style="fill:#ffffff"/>
-  </g>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="3.0508475" y="98.386719" id="text5191" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193" x="3.0508475" y="98.386719">a</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="23.050848" y="98.386719" id="text5191-1" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-7" x="23.050848" y="98.386719">b</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="43.050846" y="98.386719" id="text5191-7" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-1" x="43.050846" y="98.386719">c</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="63.050854" y="98.386719" id="text5191-15" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-9" x="63.050854" y="98.386719">d</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="83.05085" y="98.386719" id="text5191-77" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-6" x="83.05085" y="98.386719">e</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="-7.0260201" y="87.817795" id="text5191-73" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-65" x="-7.0260201" y="87.817795">1</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="-6.8189888" y="67.880318" id="text5191-6" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-3" x="-6.8189888" y="67.880318">2</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="-6.7564888" y="47.991673" id="text5191-9" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-4" x="-6.7564888" y="47.991673">3</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="-6.9166451" y="27.993652" id="text5191-8" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-12" x="-6.9166451" y="27.993652">4</tspan></text>
-  <text xml:space="preserve" style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans" x="-7.1080513" y="8.0561762" id="text5191-93" sodipodi:linespacing="125%"><tspan sodipodi:role="line" id="tspan5193-90" x="-7.1080513" y="8.0561762">5</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="3.0508475"
+     y="98.386719"
+     id="text5191"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193"
+       x="3.0508475"
+       y="98.386719">a</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="23.050848"
+     y="98.386719"
+     id="text5191-1"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-7"
+       x="23.050848"
+       y="98.386719">b</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="43.050846"
+     y="98.386719"
+     id="text5191-7"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-1"
+       x="43.050846"
+       y="98.386719">c</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="63.050854"
+     y="98.386719"
+     id="text5191-15"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-9"
+       x="63.050854"
+       y="98.386719">d</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="83.05085"
+     y="98.386719"
+     id="text5191-77"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-6"
+       x="83.05085"
+       y="98.386719">e</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="-7.0260201"
+     y="87.817795"
+     id="text5191-73"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-65"
+       x="-7.0260201"
+       y="87.817795">1</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="-6.8189888"
+     y="67.880318"
+     id="text5191-6"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-3"
+       x="-6.8189888"
+       y="67.880318">2</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="-6.7564888"
+     y="47.991673"
+     id="text5191-9"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-4"
+       x="-6.7564888"
+       y="47.991673">3</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="-6.9166451"
+     y="27.993652"
+     id="text5191-8"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-12"
+       x="-6.9166451"
+       y="27.993652">4</tspan></text>
+  <text
+     xml:space="preserve"
+     style="font-size:8px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#cccccc;fill-opacity:1;stroke:none;font-family:Sans"
+     x="-7.1080513"
+     y="8.0561762"
+     id="text5191-93"
+     sodipodi:linespacing="125%"><tspan
+       sodipodi:role="line"
+       id="tspan5193-90"
+       x="-7.1080513"
+       y="8.0561762">5</tspan></text>
 </svg>
-
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
index edecedd..747c4f3b 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -4,7 +4,7 @@
     "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "checkboxCheckmark.svg": "f039bf85cee42ad5c30ca3bfdce7912a",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
-    "smallIcons.svg": "54000a76145196864f9dabac90afd2bf",
+    "smallIcons.svg": "55c46735baa910dbe8f6b9602eb2f464",
     "mediumIcons.svg": "e63ac6385b0a6efb783d9838517e5e44",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "treeoutlineTriangles.svg": "017d2f89437df0afc6b9cd5ff43735d9",
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
index 1662efc..bdd4fbc 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
@@ -142,8 +142,9 @@
     return this._protocolService.detach().then(_ => {
       this._auditRunning = false;
       this._updateButton();
-      if (this._inspectedURL !== SDK.targetManager.mainTarget().inspectedURL())
-        SDK.targetManager.mainTarget().pageAgent().navigate(this._inspectedURL);
+      var resourceTreeModel = SDK.targetManager.mainTarget().model(SDK.ResourceTreeModel);
+      if (resourceTreeModel && this._inspectedURL !== SDK.targetManager.mainTarget().inspectedURL())
+        resourceTreeModel.navigate(this._inspectedURL);
 
     });
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index cfb46ea..a6911fb7 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -135,7 +135,7 @@
         Runtime.experiments.enableForTest('liveSASS');
     }
 
-    Runtime.experiments.setDefaultExperiments(['persistenceValidation', 'persistence2']);
+    Runtime.experiments.setDefaultExperiments(['persistenceValidation', 'persistence2', 'continueToLocationMarkers']);
   }
 
   /**
diff --git a/third_party/WebKit/Source/devtools/front_end/screencast/InputModel.js b/third_party/WebKit/Source/devtools/front_end/screencast/InputModel.js
new file mode 100644
index 0000000..fc96e7e0
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/screencast/InputModel.js
@@ -0,0 +1,116 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+Screencast.InputModel = class extends SDK.SDKModel {
+  /**
+   * @param {!SDK.Target} target
+   */
+  constructor(target) {
+    super(target);
+    this._inputAgent = target.inputAgent();
+    /** @type {?number} */
+    this._activeTouchOffsetTop = null;
+    this._activeTouchParams = null;
+  }
+
+  /**
+   * @param {!Event} event
+   */
+  emitKeyEvent(event) {
+    var type;
+    switch (event.type) {
+      case 'keydown':
+        type = 'keyDown';
+        break;
+      case 'keyup':
+        type = 'keyUp';
+        break;
+      case 'keypress':
+        type = 'char';
+        break;
+      default:
+        return;
+    }
+
+    var text = event.type === 'keypress' ? String.fromCharCode(event.charCode) : undefined;
+    this._inputAgent.invoke_dispatchKeyEvent({
+      type: type,
+      modifiers: this._modifiersForEvent(event),
+      timestamp: event.timeStamp / 1000,
+      text: text,
+      unmodifiedText: text ? text.toLowerCase() : undefined,
+      keyIdentifier: event.keyIdentifier,
+      code: event.code,
+      key: event.key,
+      windowsVirtualKeyCode: event.keyCode,
+      nativeVirtualKeyCode: event.keyCode,
+      autoRepeat: false,
+      isKeypad: false,
+      isSystemKey: false
+    });
+  }
+
+  /**
+   * @param {!Event} event
+   * @param {number} offsetTop
+   * @param {number} zoom
+   */
+  emitTouchFromMouseEvent(event, offsetTop, zoom) {
+    var buttons = {0: 'none', 1: 'left', 2: 'middle', 3: 'right'};
+    var types = {
+      'mousedown': 'mousePressed',
+      'mouseup': 'mouseReleased',
+      'mousemove': 'mouseMoved',
+      'mousewheel': 'mouseWheel'
+    };
+    if (!(event.type in types) || !(event.which in buttons))
+      return;
+    if (event.type !== 'mousewheel' && buttons[event.which] === 'none')
+      return;
+
+    if (event.type === 'mousedown' || this._activeTouchOffsetTop === null)
+      this._activeTouchOffsetTop = offsetTop;
+
+    var x = Math.round(event.offsetX / zoom);
+    var y = Math.round(event.offsetY / zoom);
+    y = Math.round(y - this._activeTouchOffsetTop);
+    var params = {
+      type: types[event.type],
+      x: x,
+      y: y,
+      modifiers: this._modifiersForEvent(event),
+      timestamp: event.timeStamp / 1000,
+      button: buttons[event.which],
+      clickCount: 0
+    };
+    if (event.type === 'mousewheel') {
+      params.deltaX = event.wheelDeltaX / zoom;
+      params.deltaY = event.wheelDeltaY / zoom;
+    } else {
+      this._activeTouchParams = params;
+    }
+    if (event.type === 'mouseup')
+      this._activeTouchOffsetTop = null;
+    this._inputAgent.invoke_emulateTouchFromMouseEvent(params);
+  }
+
+  cancelTouch() {
+    if (this._activeTouchOffsetTop !== null) {
+      var params = this._activeTouchParams;
+      this._activeTouchParams = null;
+      params.type = 'mouseReleased';
+      this._inputAgent.invoke_emulateTouchFromMouseEvent(params);
+    }
+  }
+
+  /**
+   * @param {!Event} event
+   * @return {number}
+   */
+  _modifiersForEvent(event) {
+    return (event.altKey ? 1 : 0) | (event.ctrlKey ? 2 : 0) | (event.metaKey ? 4 : 0) | (event.shiftKey ? 8 : 0);
+  }
+};
+
+SDK.SDKModel.register(Screencast.InputModel, SDK.Target.Capability.Input, false);
diff --git a/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js b/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js
index 7e627659..91bbe66 100644
--- a/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js
+++ b/third_party/WebKit/Source/devtools/front_end/screencast/ScreencastView.js
@@ -37,10 +37,11 @@
    */
   constructor(screenCaptureModel) {
     super();
-    this._target = screenCaptureModel.target();
     this._screenCaptureModel = screenCaptureModel;
-    this._domModel = this._target.model(SDK.DOMModel);
-    this._resourceTreeModel = this._target.model(SDK.ResourceTreeModel);
+    this._domModel = screenCaptureModel.target().model(SDK.DOMModel);
+    this._resourceTreeModel = screenCaptureModel.target().model(SDK.ResourceTreeModel);
+    this._networkManager = screenCaptureModel.target().model(SDK.NetworkManager);
+    this._inputModel = screenCaptureModel.target().model(Screencast.InputModel);
 
     this.setMinimumSize(150, 150);
     this.registerRequiredCSS('screencast/screencastView.css');
@@ -221,7 +222,8 @@
       return;
 
     if (!this._inspectModeConfig || event.type === 'mousewheel') {
-      this._simulateTouchForMouseEvent(event);
+      if (this._inputModel)
+        this._inputModel.emitTouchFromMouseEvent(event, this._screenOffsetTop, this._screenZoom);
       event.preventDefault();
       if (event.type === 'mousedown')
         this._canvasElement.focus();
@@ -266,37 +268,8 @@
       return;
     }
 
-    var type;
-    switch (event.type) {
-      case 'keydown':
-        type = 'keyDown';
-        break;
-      case 'keyup':
-        type = 'keyUp';
-        break;
-      case 'keypress':
-        type = 'char';
-        break;
-      default:
-        return;
-    }
-
-    var text = event.type === 'keypress' ? String.fromCharCode(event.charCode) : undefined;
-    this._target.inputAgent().invoke_dispatchKeyEvent({
-      type: type,
-      modifiers: this._modifiersForEvent(event),
-      timestamp: event.timeStamp / 1000,
-      text: text,
-      unmodifiedText: text ? text.toLowerCase() : undefined,
-      keyIdentifier: event.keyIdentifier,
-      code: event.code,
-      key: event.key,
-      windowsVirtualKeyCode: event.keyCode,
-      nativeVirtualKeyCode: event.keyCode,
-      autoRepeat: false,
-      isKeypad: false,
-      isSystemKey: false
-    });
+    if (this._inputModel)
+      this._inputModel.emitKeyEvent(event);
     event.consume();
     this._canvasElement.focus();
   }
@@ -311,68 +284,9 @@
   /**
    * @param {!Event} event
    */
-  _simulateTouchForMouseEvent(event) {
-    const buttons = {0: 'none', 1: 'left', 2: 'middle', 3: 'right'};
-    const types = {
-      'mousedown': 'mousePressed',
-      'mouseup': 'mouseReleased',
-      'mousemove': 'mouseMoved',
-      'mousewheel': 'mouseWheel'
-    };
-    if (!(event.type in types) || !(event.which in buttons))
-      return;
-    if (event.type !== 'mousewheel' && buttons[event.which] === 'none')
-      return;
-
-    if (event.type === 'mousedown' || typeof this._eventScreenOffsetTop === 'undefined')
-      this._eventScreenOffsetTop = this._screenOffsetTop;
-
-    var modifiers =
-        (event.altKey ? 1 : 0) | (event.ctrlKey ? 2 : 0) | (event.metaKey ? 4 : 0) | (event.shiftKey ? 8 : 0);
-
-    var convertedPosition = this._zoomIntoScreenSpace(event);
-    convertedPosition.y = Math.round(convertedPosition.y - this._eventScreenOffsetTop);
-    var params = {
-      type: types[event.type],
-      x: convertedPosition.x,
-      y: convertedPosition.y,
-      modifiers: modifiers,
-      timestamp: event.timeStamp / 1000,
-      button: buttons[event.which],
-      clickCount: 0
-    };
-    if (event.type === 'mousewheel') {
-      params.deltaX = event.wheelDeltaX / this._screenZoom;
-      params.deltaY = event.wheelDeltaY / this._screenZoom;
-    } else {
-      this._eventParams = params;
-    }
-    if (event.type === 'mouseup')
-      delete this._eventScreenOffsetTop;
-    this._target.inputAgent().invoke_emulateTouchFromMouseEvent(params);
-  }
-
-  /**
-   * @param {!Event} event
-   */
   _handleBlurEvent(event) {
-    if (typeof this._eventScreenOffsetTop !== 'undefined') {
-      var params = this._eventParams;
-      delete this._eventParams;
-      params.type = 'mouseReleased';
-      this._target.inputAgent().invoke_emulateTouchFromMouseEvent(params);
-    }
-  }
-
-  /**
-   * @param {!Event} event
-   * @return {!{x: number, y: number}}
-   */
-  _zoomIntoScreenSpace(event) {
-    var position = {};
-    position.x = Math.round(event.offsetX / this._screenZoom);
-    position.y = Math.round(event.offsetY / this._screenZoom);
-    return position;
+    if (this._inputModel)
+      this._inputModel.cancelTouch();
   }
 
   /**
@@ -380,29 +294,13 @@
    * @return {!{x: number, y: number}}
    */
   _convertIntoScreenSpace(event) {
-    var position = this._zoomIntoScreenSpace(event);
-    position.y = Math.round(position.y - this._screenOffsetTop);
+    var position = {};
+    position.x = Math.round(event.offsetX / this._screenZoom);
+    position.y = Math.round(event.offsetY / this._screenZoom - this._screenOffsetTop);
     return position;
   }
 
   /**
-   * @param {!Event} event
-   * @return {number}
-   */
-  _modifiersForEvent(event) {
-    var modifiers = 0;
-    if (event.altKey)
-      modifiers = 1;
-    if (event.ctrlKey)
-      modifiers += 2;
-    if (event.metaKey)
-      modifiers += 4;
-    if (event.shiftKey)
-      modifiers += 8;
-    return modifiers;
-  }
-
-  /**
    * @override
    */
   onResize() {
@@ -709,43 +607,47 @@
 
   _createNavigationBar() {
     this._navigationBar = this.element.createChild('div', 'screencast-navigation');
-
     this._navigationBack = this._navigationBar.createChild('button', 'back');
     this._navigationBack.disabled = true;
-    this._navigationBack.addEventListener('click', this._navigateToHistoryEntry.bind(this, -1), false);
-
     this._navigationForward = this._navigationBar.createChild('button', 'forward');
     this._navigationForward.disabled = true;
-    this._navigationForward.addEventListener('click', this._navigateToHistoryEntry.bind(this, 1), false);
-
     this._navigationReload = this._navigationBar.createChild('button', 'reload');
-    this._navigationReload.addEventListener('click', this._navigateReload.bind(this), false);
-
     this._navigationUrl = this._navigationBar.createChild('input');
     this._navigationUrl.type = 'text';
-    this._navigationUrl.addEventListener('keyup', this._navigationUrlKeyUp.bind(this), true);
+    this._navigationProgressBar = new Screencast.ScreencastView.ProgressTracker(
+        this._resourceTreeModel, this._networkManager, this._navigationBar.createChild('div', 'progress'));
 
-    this._navigationProgressBar =
-        new Screencast.ScreencastView.ProgressTracker(this._navigationBar.createChild('div', 'progress'));
-
-    this._requestNavigationHistory();
-    SDK.targetManager.addEventListener(
-        SDK.TargetManager.Events.InspectedURLChanged, this._requestNavigationHistory, this);
+    if (this._resourceTreeModel) {
+      this._navigationBack.addEventListener('click', this._navigateToHistoryEntry.bind(this, -1), false);
+      this._navigationForward.addEventListener('click', this._navigateToHistoryEntry.bind(this, 1), false);
+      this._navigationReload.addEventListener('click', this._navigateReload.bind(this), false);
+      this._navigationUrl.addEventListener('keyup', this._navigationUrlKeyUp.bind(this), true);
+      this._requestNavigationHistory();
+      this._resourceTreeModel.addEventListener(
+          SDK.ResourceTreeModel.Events.MainFrameNavigated, this._requestNavigationHistory, this);
+      this._resourceTreeModel.addEventListener(
+          SDK.ResourceTreeModel.Events.CachedResourcesLoaded, this._requestNavigationHistory, this);
+    }
   }
 
+  /**
+   * @param {number} offset
+   */
   _navigateToHistoryEntry(offset) {
     var newIndex = this._historyIndex + offset;
     if (newIndex < 0 || newIndex >= this._historyEntries.length)
       return;
-    this._target.pageAgent().navigateToHistoryEntry(this._historyEntries[newIndex].id);
+    this._resourceTreeModel.navigateToHistoryEntry(this._historyEntries[newIndex]);
     this._requestNavigationHistory();
   }
 
   _navigateReload() {
-    if (this._resourceTreeModel)
-      this._resourceTreeModel.reloadPage();
+    this._resourceTreeModel.reloadPage();
   }
 
+  /**
+   * @param {!Event} event
+   */
   _navigationUrlKeyUp(event) {
     if (event.key !== 'Enter')
       return;
@@ -754,25 +656,22 @@
       return;
     if (!url.match(Screencast.ScreencastView._SchemeRegex))
       url = 'http://' + url;
-    this._target.pageAgent().navigate(url);
+    this._resourceTreeModel.navigate(url);
     this._canvasElement.focus();
   }
 
-  _requestNavigationHistory() {
-    this._target.pageAgent().getNavigationHistory(this._onNavigationHistory.bind(this));
-  }
-
-  _onNavigationHistory(error, currentIndex, entries) {
-    if (error)
+  async _requestNavigationHistory() {
+    var history = await this._resourceTreeModel.navigationHistory();
+    if (!history)
       return;
 
-    this._historyIndex = currentIndex;
-    this._historyEntries = entries;
+    this._historyIndex = history.currentIndex;
+    this._historyEntries = history.entries;
 
-    this._navigationBack.disabled = currentIndex === 0;
-    this._navigationForward.disabled = currentIndex === (entries.length - 1);
+    this._navigationBack.disabled = this._historyIndex === 0;
+    this._navigationForward.disabled = this._historyIndex === (this._historyEntries.length - 1);
 
-    var url = entries[currentIndex].url;
+    var url = this._historyEntries[this._historyIndex].url;
     var match = url.match(Screencast.ScreencastView._HttpRegex);
     if (match)
       url = match[1];
@@ -800,18 +699,21 @@
  */
 Screencast.ScreencastView.ProgressTracker = class {
   /**
+   * @param {?SDK.ResourceTreeModel} resourceTreeModel
+   * @param {?SDK.NetworkManager} networkManager
    * @param {!Element} element
    */
-  constructor(element) {
+  constructor(resourceTreeModel, networkManager, element) {
     this._element = element;
-
-    SDK.targetManager.addModelListener(
-        SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.MainFrameNavigated, this._onMainFrameNavigated, this);
-    SDK.targetManager.addModelListener(SDK.ResourceTreeModel, SDK.ResourceTreeModel.Events.Load, this._onLoad, this);
-    SDK.targetManager.addModelListener(
-        SDK.NetworkManager, SDK.NetworkManager.Events.RequestStarted, this._onRequestStarted, this);
-    SDK.targetManager.addModelListener(
-        SDK.NetworkManager, SDK.NetworkManager.Events.RequestFinished, this._onRequestFinished, this);
+    if (resourceTreeModel) {
+      resourceTreeModel.addEventListener(
+          SDK.ResourceTreeModel.Events.MainFrameNavigated, this._onMainFrameNavigated, this);
+      resourceTreeModel.addEventListener(SDK.ResourceTreeModel.Events.Load, this._onLoad, this);
+    }
+    if (networkManager) {
+      networkManager.addEventListener(SDK.NetworkManager.Events.RequestStarted, this._onRequestStarted, this);
+      networkManager.addEventListener(SDK.NetworkManager.Events.RequestFinished, this._onRequestFinished, this);
+    }
   }
 
   _onMainFrameNavigated() {
diff --git a/third_party/WebKit/Source/devtools/front_end/screencast/module.json b/third_party/WebKit/Source/devtools/front_end/screencast/module.json
index b6eb136a..7ae80c0a 100644
--- a/third_party/WebKit/Source/devtools/front_end/screencast/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/screencast/module.json
@@ -24,6 +24,7 @@
         "emulation"
     ],
     "scripts": [
+        "InputModel.js",
         "ScreencastApp.js",
         "ScreencastView.js"
     ],
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
index d49669a..5932d668 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/ResourceTreeModel.js
@@ -376,6 +376,31 @@
   }
 
   /**
+   * @param {string} url
+   */
+  navigate(url) {
+    this._agent.navigate(url, undefined, (error, frameId) => undefined);
+  }
+
+  /**
+   * @return {!Promise<?{currentIndex: number, entries: !Protocol.Page.NavigationEntry}>}
+   */
+  navigationHistory() {
+    return this._agent.getNavigationHistory((error, currentIndex, entries) => {
+      if (error)
+        return null;
+      return {currentIndex: currentIndex, entries: entries};
+    });
+  }
+
+  /**
+   * @param {!Protocol.Page.NavigationEntry} entry
+   */
+  navigateToHistoryEntry(entry) {
+    this._agent.navigateToHistoryEntry(entry.id);
+  }
+
+  /**
    * @param {function(string, ?string,!Array<!Protocol.Page.AppManifestError>)} callback
    */
   fetchAppManifest(callback) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
index 0865f0e..6cad69ee 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
@@ -210,10 +210,11 @@
   Tracing: 1 << 7,
   TouchEmulation: 1 << 8,
   Security: 1 << 9,
+  Input: 1 << 10,
 
   None: 0,
 
-  AllForTests: (1 << 10) - 1
+  AllForTests: (1 << 11) - 1
 };
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
index 9449346..74f4631 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
@@ -334,7 +334,7 @@
     var capabilities = SDK.Target.Capability.Browser | SDK.Target.Capability.DOM | SDK.Target.Capability.JS |
         SDK.Target.Capability.Log | SDK.Target.Capability.Network | SDK.Target.Capability.Target |
         SDK.Target.Capability.ScreenCapture | SDK.Target.Capability.Tracing | SDK.Target.Capability.TouchEmulation |
-        SDK.Target.Capability.Security;
+        SDK.Target.Capability.Security | SDK.Target.Capability.Input;
     if (Runtime.queryParam('isSharedWorker')) {
       capabilities = SDK.Target.Capability.Browser | SDK.Target.Capability.Log | SDK.Target.Capability.Network |
           SDK.Target.Capability.Target;
@@ -443,7 +443,7 @@
     if (type === 'iframe') {
       return SDK.Target.Capability.Browser | SDK.Target.Capability.DOM | SDK.Target.Capability.JS |
           SDK.Target.Capability.Log | SDK.Target.Capability.Network | SDK.Target.Capability.Target |
-          SDK.Target.Capability.Tracing | SDK.Target.Capability.TouchEmulation;
+          SDK.Target.Capability.Tracing | SDK.Target.Capability.TouchEmulation | SDK.Target.Capability.Input;
     }
     if (type === 'node')
       return SDK.Target.Capability.JS;
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
index 1d4627f2..de2ac73 100644
--- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
+++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -52,6 +52,14 @@
         'scroll', this._popoverHelper.hidePopover.bind(this._popoverHelper), true);
 
     this.textEditor.element.addEventListener('keydown', this._onKeyDown.bind(this), true);
+    this.textEditor.element.addEventListener('keyup', this._onKeyUp.bind(this), true);
+    this.textEditor.element.addEventListener('mousemove', this._onMouseMove.bind(this), false);
+    if (Runtime.experiments.isEnabled('continueToLocationMarkers')) {
+      this.textEditor.element.addEventListener('wheel', event => {
+        if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event))
+          event.preventDefault();
+      }, true);
+    }
 
     this.textEditor.addEventListener(
         SourceFrame.SourcesTextEditor.Events.GutterClick, this._handleGutterClick.bind(this), this);
@@ -165,8 +173,6 @@
       // We need SourcesTextEditor to be initialized prior to this call. @see crbug.com/499889
       setImmediate(() => {
         this._generateValuesInSource();
-        if (Runtime.experiments.isEnabled('continueToLocationMarkers'))
-          this._showContinueToLocations();
       });
     }
   }
@@ -470,13 +476,48 @@
     };
   }
 
+  /**
+   * @param {!KeyboardEvent} event
+   */
   _onKeyDown(event) {
     if (event.key === 'Escape') {
       if (this._popoverHelper.isPopoverVisible()) {
         this._popoverHelper.hidePopover();
         event.consume();
       }
+      return;
     }
+    if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event) && this._executionLocation) {
+      if (!this._continueToLocationShown) {
+        this._showContinueToLocations();
+        this._continueToLocationShown = true;
+      }
+    }
+  }
+
+  /**
+   * @param {!MouseEvent} event
+   */
+  _onMouseMove(event) {
+    if (this._executionLocation && UI.KeyboardShortcut.eventHasCtrlOrMeta(event)) {
+      if (!this._continueToLocationShown) {
+        this._showContinueToLocations();
+        this._continueToLocationShown = true;
+      }
+      return;
+    }
+  }
+
+  /**
+   * @param {!KeyboardEvent} event
+   */
+  _onKeyUp(event) {
+    if (UI.KeyboardShortcut.eventHasCtrlOrMeta(event))
+      return;
+    if (!this._continueToLocationShown)
+      return;
+    this._clearContinueToLocations();
+    this._continueToLocationShown = false;
   }
 
   /**
@@ -541,8 +582,10 @@
       // We need SourcesTextEditor to be initialized prior to this call. @see crbug.com/506566
       setImmediate(() => {
         this._generateValuesInSource();
-        if (Runtime.experiments.isEnabled('continueToLocationMarkers'))
-          this._showContinueToLocations();
+        if (Runtime.experiments.isEnabled('continueToLocationMarkers')) {
+          if (this._continueToLocationShown)
+            this._showContinueToLocations();
+        }
       });
     }
   }
@@ -571,6 +614,8 @@
   }
 
   _showContinueToLocations() {
+    if (!Runtime.experiments.isEnabled('continueToLocationMarkers'))
+      return;
     var executionContext = UI.context.flavor(SDK.ExecutionContext);
     if (!executionContext)
       return;
@@ -592,7 +637,6 @@
     var executionLocation = callFrame.location();
     debuggerModel.getPossibleBreakpoints(start, end, true)
         .then(locations => this.textEditor.operation(renderLocations.bind(this, locations)));
-
     /**
      * @param {!Array<!SDK.DebuggerModel.BreakLocation>} locations
      * @this {Sources.JavaScriptSourceFrame}
@@ -806,6 +850,8 @@
   }
 
   _clearContinueToLocations() {
+    if (!Runtime.experiments.isEnabled('continueToLocationMarkers'))
+      return;
     delete this._clearContinueToLocationsTimer;
     var bookmarks = this.textEditor.bookmarks(
         this.textEditor.fullRange(), Sources.JavaScriptSourceFrame.continueToLocationDecorationSymbol);
diff --git a/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css b/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
index e3632a8..27b5118 100644
--- a/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
+++ b/third_party/WebKit/Source/devtools/front_end/text_editor/cmdevtools.css
@@ -162,7 +162,7 @@
 
 .cm-continue-to-location {
     cursor: pointer;
-    opacity: 0.5;
+    opacity: 0.8;
     position: relative;
     top: 2px;
 }
diff --git a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
index a29f53e..4680fb9 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/generate_protocol_externs.py
@@ -52,6 +52,7 @@
     "CSS",
     "Emulation",
     "HeapProfiler",
+    "Page",
     "Profiler",
     "LayerTree",
     "Tracing"
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaConstraintsImpl.h b/third_party/WebKit/Source/modules/mediastream/MediaConstraintsImpl.h
index 0a013f98..99b882b6 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaConstraintsImpl.h
+++ b/third_party/WebKit/Source/modules/mediastream/MediaConstraintsImpl.h
@@ -39,6 +39,7 @@
 namespace blink {
 
 class Dictionary;
+class ExecutionContext;
 class MediaTrackConstraints;
 
 namespace MediaConstraintsImpl {
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaDevicesRequest.cpp b/third_party/WebKit/Source/modules/mediastream/MediaDevicesRequest.cpp
index fadef15b..556a7efa 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaDevicesRequest.cpp
+++ b/third_party/WebKit/Source/modules/mediastream/MediaDevicesRequest.cpp
@@ -41,7 +41,7 @@
 
 MediaDevicesRequest::MediaDevicesRequest(ScriptState* state,
                                          UserMediaController* controller)
-    : ContextLifecycleObserver(state->GetExecutionContext()),
+    : ContextLifecycleObserver(ExecutionContext::From(state)),
       controller_(controller),
       resolver_(ScriptPromiseResolver::Create(state)) {}
 
diff --git a/third_party/WebKit/Source/modules/permissions/Permissions.h b/third_party/WebKit/Source/modules/permissions/Permissions.h
index 4fe6793..c929b54 100644
--- a/third_party/WebKit/Source/modules/permissions/Permissions.h
+++ b/third_party/WebKit/Source/modules/permissions/Permissions.h
@@ -13,6 +13,7 @@
 namespace blink {
 
 class Dictionary;
+class ExecutionContext;
 class ScriptPromiseResolver;
 class ScriptState;
 
diff --git a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
index d7ffad3..6b6abe8 100644
--- a/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/PannerNode.cpp
@@ -748,7 +748,7 @@
 
 void PannerNode::setRefDistance(double distance,
                                 ExceptionState& exception_state) {
-  if (distance <= 0) {
+  if (distance < 0) {
     exception_state.ThrowDOMException(
         kV8RangeError, ExceptionMessages::IndexExceedsMinimumBound<double>(
                            "refDistance", distance, 0));
diff --git a/third_party/WebKit/Source/platform/audio/Distance.cpp b/third_party/WebKit/Source/platform/audio/Distance.cpp
index af25bef..99c5a022 100644
--- a/third_party/WebKit/Source/platform/audio/Distance.cpp
+++ b/third_party/WebKit/Source/platform/audio/Distance.cpp
@@ -67,11 +67,17 @@
 }
 
 double DistanceEffect::InverseGain(double distance) {
+  if (ref_distance_ == 0)
+    return 0;
+
   return ref_distance_ / (ref_distance_ + clampTo(rolloff_factor_, 0.0) *
                                               (distance - ref_distance_));
 }
 
 double DistanceEffect::ExponentialGain(double distance) {
+  if (ref_distance_ == 0)
+    return 0;
+
   return pow(distance / ref_distance_, -clampTo(rolloff_factor_, 0.0));
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
index c4c14299..89b5cb6f 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.cpp
@@ -399,13 +399,14 @@
     change_size_for_next_commit_ = false;
   }
 
+  compositor_has_pending_frame_ = true;
   sink_->SubmitCompositorFrame(current_local_surface_id_, std::move(frame));
 }
 
 void OffscreenCanvasFrameDispatcherImpl::DidReceiveCompositorFrameAck(
     const cc::ReturnedResourceArray& resources) {
   ReclaimResources(resources);
-  // TODO(fsamuel): Implement this.
+  compositor_has_pending_frame_ = false;
 }
 
 void OffscreenCanvasFrameDispatcherImpl::SetNeedsBeginFrame(
@@ -419,10 +420,19 @@
 void OffscreenCanvasFrameDispatcherImpl::OnBeginFrame(
     const cc::BeginFrameArgs& begin_frame_args) {
   DCHECK(Client());
+
   // TODO(eseckler): Set correct |latest_confirmed_sequence_number|.
   current_begin_frame_ack_ = cc::BeginFrameAck(
       begin_frame_args.source_id, begin_frame_args.sequence_number,
       begin_frame_args.sequence_number, false);
+
+  if (compositor_has_pending_frame_ ||
+      (begin_frame_args.type == cc::BeginFrameArgs::MISSED &&
+       base::TimeTicks::Now() > begin_frame_args.deadline)) {
+    sink_->BeginFrameDidNotSwap(current_begin_frame_ack_);
+    return;
+  }
+
   Client()->BeginFrame();
   // TODO(eseckler): Tell |m_sink| if we did not draw during the BeginFrame.
   current_begin_frame_ack_.sequence_number =
diff --git a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
index 108a22a..9bfbbbb 100644
--- a/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
+++ b/third_party/WebKit/Source/platform/graphics/OffscreenCanvasFrameDispatcherImpl.h
@@ -64,6 +64,7 @@
   int height_;
   bool change_size_for_next_commit_;
   bool needs_begin_frame_;
+  bool compositor_has_pending_frame_ = false;
 
   unsigned next_resource_id_;
   HashMap<unsigned, RefPtr<StaticBitmapImage>> cached_images_;
diff --git a/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp b/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
index b02f5de..514fca27 100644
--- a/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
+++ b/third_party/WebKit/Source/web/StorageQuotaClientImpl.cpp
@@ -52,7 +52,7 @@
     unsigned long long new_quota_in_bytes,
     StorageQuotaCallback* success_callback,
     StorageErrorCallback* error_callback) {
-  ExecutionContext* execution_context = script_state->GetExecutionContext();
+  ExecutionContext* execution_context = ExecutionContext::From(script_state);
   DCHECK(execution_context);
   DCHECK(execution_context->IsDocument())
       << "Quota requests are not supported in workers";
diff --git a/third_party/WebKit/Source/web/WebInputEventConversion.cpp b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
index 7b9defc..b3007436 100644
--- a/third_party/WebKit/Source/web/WebInputEventConversion.cpp
+++ b/third_party/WebKit/Source/web/WebInputEventConversion.cpp
@@ -195,9 +195,17 @@
   if (event.NativeEvent()) {
     *static_cast<WebMouseEvent*>(this) =
         event.NativeEvent()->FlattenTransform();
-    WebFloatPoint absolute_root_frame_location = PositionInRootFrame();
-    IntPoint local_point = RoundedIntPoint(layout_item.AbsoluteToLocal(
-        absolute_root_frame_location, kUseTransforms));
+    WebFloatPoint absolute_location = PositionInRootFrame();
+
+    // TODO(dtapuska): |plugin_parent| should never be null. Remove this
+    // conditional code.
+    // Translate the root frame position to content coordinates.
+    if (plugin_parent) {
+      absolute_location = plugin_parent->RootFrameToContents(absolute_location);
+    }
+
+    IntPoint local_point = RoundedIntPoint(
+        layout_item.AbsoluteToLocal(absolute_location, kUseTransforms));
     SetPositionInWidget(local_point.X(), local_point.Y());
     return;
   }
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index a312501..c5c5029 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -710,6 +710,8 @@
   // in the call to HandleEvent. See http://b/issue?id=1362948
   FrameView* parent_view = ToFrameView(Parent());
 
+  // TODO(dtapuska): Move WebMouseEventBuilder into the anonymous namespace
+  // in this class.
   WebMouseEventBuilder transformed_event(
       ToFrameView(Parent()), LayoutItem(element_->GetLayoutObject()), *event);
   if (transformed_event.GetType() == WebInputEvent::kUndefined)
@@ -765,11 +767,17 @@
 }
 
 void WebPluginContainerImpl::HandleWheelEvent(WheelEvent* event) {
-  WebFloatPoint absolute_root_frame_location =
-      event->NativeEvent().PositionInRootFrame();
+  WebFloatPoint absolute_location = event->NativeEvent().PositionInRootFrame();
+
+  FrameView* view = ToFrameView(Parent());
+  // Translate the root frame position to content coordinates.
+  if (view) {
+    absolute_location = view->RootFrameToContents(absolute_location);
+  }
+
   IntPoint local_point =
       RoundedIntPoint(element_->GetLayoutObject()->AbsoluteToLocal(
-          absolute_root_frame_location, kUseTransforms));
+          absolute_location, kUseTransforms));
   WebMouseWheelEvent translated_event = event->NativeEvent().FlattenTransform();
   translated_event.SetPositionInWidget(local_point.X(), local_point.Y());
 
@@ -830,12 +838,19 @@
       WebTouchEvent transformed_event =
           event->NativeEvent()->FlattenTransform();
 
+      FrameView* view = ToFrameView(Parent());
+
       for (unsigned i = 0; i < transformed_event.touches_length; ++i) {
-        WebFloatPoint absolute_root_frame_location =
-            transformed_event.touches[i].position;
+        WebFloatPoint absolute_location = transformed_event.touches[i].position;
+
+        // Translate the root frame position to content coordinates.
+        if (view) {
+          absolute_location = view->RootFrameToContents(absolute_location);
+        }
+
         IntPoint local_point =
             RoundedIntPoint(element_->GetLayoutObject()->AbsoluteToLocal(
-                absolute_root_frame_location, kUseTransforms));
+                absolute_location, kUseTransforms));
         transformed_event.touches[i].position.x = local_point.X();
         transformed_event.touches[i].position.y = local_point.Y();
       }
diff --git a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
index 3dd69fa..dadd454 100644
--- a/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebPluginContainerTest.cpp
@@ -51,6 +51,7 @@
 #include "public/platform/WebLayer.h"
 #include "public/platform/WebMouseWheelEvent.h"
 #include "public/platform/WebThread.h"
+#include "public/platform/WebTouchEvent.h"
 #include "public/platform/WebURLLoaderMockFactory.h"
 #include "public/web/WebDocument.h"
 #include "public/web/WebElement.h"
@@ -464,19 +465,30 @@
         event.GetType() == WebInputEvent::kMouseWheel) {
       const WebMouseEvent& mouse_event =
           static_cast<const WebMouseEvent&>(event);
-      last_mouse_event_location_ = IntPoint(mouse_event.PositionInWidget().x,
-                                            mouse_event.PositionInWidget().y);
+      last_event_location_ = IntPoint(mouse_event.PositionInWidget().x,
+                                      mouse_event.PositionInWidget().y);
+    } else if (WebInputEvent::IsTouchEventType(event.GetType())) {
+      const WebTouchEvent& touch_event =
+          static_cast<const WebTouchEvent&>(event);
+      if (touch_event.touches_length == 1) {
+        last_event_location_ = IntPoint(touch_event.touches[0].position.x,
+                                        touch_event.touches[0].position.y);
+      } else {
+        last_event_location_ = IntPoint();
+      }
     }
 
     return WebInputEventResult::kHandledSystem;
   }
   WebInputEvent::Type GetLastInputEventType() { return last_event_type_; }
 
-  IntPoint GetLastMouseEventLocation() { return last_mouse_event_location_; }
+  IntPoint GetLastEventLocation() { return last_event_location_; }
+
+  void ClearLastEventType() { last_event_type_ = WebInputEvent::kUndefined; }
 
  private:
   WebInputEvent::Type last_event_type_;
-  IntPoint last_mouse_event_location_;
+  IntPoint last_event_location_;
 };
 
 TEST_F(WebPluginContainerTest, GestureLongPressReachesPlugin) {
@@ -560,8 +572,258 @@
   RunPendingTasks();
 
   EXPECT_EQ(WebInputEvent::kMouseWheel, test_plugin->GetLastInputEventType());
-  EXPECT_EQ(rect.width / 2, test_plugin->GetLastMouseEventLocation().X());
-  EXPECT_EQ(rect.height / 2, test_plugin->GetLastMouseEventLocation().Y());
+  EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+}
+
+TEST_F(WebPluginContainerTest, TouchEventScrolled) {
+  RegisterMockedURL("plugin_scroll.html");
+  CustomPluginWebFrameClient<EventTestPlugin>
+      plugin_web_frame_client;  // Must outlive webViewHelper.
+  FrameTestHelpers::WebViewHelper web_view_helper;
+  WebView* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_scroll.html", true, &plugin_web_frame_client);
+  DCHECK(web_view);
+  web_view->GetSettings()->SetPluginsEnabled(true);
+  web_view->Resize(WebSize(300, 300));
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+  web_view->SmoothScroll(0, 200, 0);
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrame()->GetDocument().GetElementById(
+          WebString::FromUTF8("scrolled-plugin"));
+  plugin_container_one_element.PluginContainer()->RequestTouchEventType(
+      WebPluginContainer::kTouchEventRequestTypeRaw);
+  WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(
+                          plugin_container_one_element.PluginContainer())
+                          ->Plugin();
+  EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
+
+  WebTouchEvent event(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
+                      WebInputEvent::kTimeStampForTesting);
+  event.touches_length = 1;
+  WebRect rect = plugin_container_one_element.BoundsInViewport();
+  event.touches[0].state = WebTouchPoint::kStatePressed;
+  event.touches[0].position =
+      WebFloatPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
+
+  web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+  RunPendingTasks();
+
+  EXPECT_EQ(WebInputEvent::kTouchStart, test_plugin->GetLastInputEventType());
+  EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+}
+
+TEST_F(WebPluginContainerTest, MouseWheelEventScrolled) {
+  RegisterMockedURL("plugin_scroll.html");
+  CustomPluginWebFrameClient<EventTestPlugin>
+      plugin_web_frame_client;  // Must outlive webViewHelper.
+  FrameTestHelpers::WebViewHelper web_view_helper;
+  WebView* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_scroll.html", true, &plugin_web_frame_client);
+  DCHECK(web_view);
+  web_view->GetSettings()->SetPluginsEnabled(true);
+  web_view->Resize(WebSize(300, 300));
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+  web_view->SmoothScroll(0, 200, 0);
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrame()->GetDocument().GetElementById(
+          WebString::FromUTF8("scrolled-plugin"));
+  plugin_container_one_element.PluginContainer()->RequestTouchEventType(
+      WebPluginContainer::kTouchEventRequestTypeRaw);
+  WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(
+                          plugin_container_one_element.PluginContainer())
+                          ->Plugin();
+  EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
+
+  WebMouseWheelEvent event(WebInputEvent::kMouseWheel,
+                           WebInputEvent::kNoModifiers,
+                           WebInputEvent::kTimeStampForTesting);
+
+  WebRect rect = plugin_container_one_element.BoundsInViewport();
+  event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+
+  web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+  RunPendingTasks();
+
+  EXPECT_EQ(WebInputEvent::kMouseWheel, test_plugin->GetLastInputEventType());
+  EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+}
+
+TEST_F(WebPluginContainerTest, MouseEventScrolled) {
+  RegisterMockedURL("plugin_scroll.html");
+  CustomPluginWebFrameClient<EventTestPlugin>
+      plugin_web_frame_client;  // Must outlive webViewHelper.
+  FrameTestHelpers::WebViewHelper web_view_helper;
+  WebView* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_scroll.html", true, &plugin_web_frame_client);
+  DCHECK(web_view);
+  web_view->GetSettings()->SetPluginsEnabled(true);
+  web_view->Resize(WebSize(300, 300));
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+  web_view->SmoothScroll(0, 200, 0);
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrame()->GetDocument().GetElementById(
+          WebString::FromUTF8("scrolled-plugin"));
+  plugin_container_one_element.PluginContainer()->RequestTouchEventType(
+      WebPluginContainer::kTouchEventRequestTypeRaw);
+  WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(
+                          plugin_container_one_element.PluginContainer())
+                          ->Plugin();
+  EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
+
+  WebMouseEvent event(WebInputEvent::kMouseMove, WebInputEvent::kNoModifiers,
+                      WebInputEvent::kTimeStampForTesting);
+
+  WebRect rect = plugin_container_one_element.BoundsInViewport();
+  event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+
+  web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+  RunPendingTasks();
+
+  EXPECT_EQ(WebInputEvent::kMouseMove, test_plugin->GetLastInputEventType());
+  EXPECT_EQ(rect.width / 2, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 2, test_plugin->GetLastEventLocation().Y());
+}
+
+TEST_F(WebPluginContainerTest, MouseEventZoomed) {
+  RegisterMockedURL("plugin_scroll.html");
+  CustomPluginWebFrameClient<EventTestPlugin>
+      plugin_web_frame_client;  // Must outlive webViewHelper.
+  FrameTestHelpers::WebViewHelper web_view_helper;
+  WebView* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_scroll.html", true, &plugin_web_frame_client);
+  DCHECK(web_view);
+  web_view->GetSettings()->SetPluginsEnabled(true);
+  web_view->Resize(WebSize(300, 300));
+  web_view->SetPageScaleFactor(2);
+  web_view->SmoothScroll(0, 300, 0);
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrame()->GetDocument().GetElementById(
+          WebString::FromUTF8("scrolled-plugin"));
+  plugin_container_one_element.PluginContainer()->RequestTouchEventType(
+      WebPluginContainer::kTouchEventRequestTypeRaw);
+  WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(
+                          plugin_container_one_element.PluginContainer())
+                          ->Plugin();
+  EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
+
+  WebMouseEvent event(WebInputEvent::kMouseMove, WebInputEvent::kNoModifiers,
+                      WebInputEvent::kTimeStampForTesting);
+
+  WebRect rect = plugin_container_one_element.BoundsInViewport();
+  event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+
+  web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+  RunPendingTasks();
+
+  // rect.width/height divided by 4 because the rect is in viewport bounds and
+  // there is a scale of 2 set.
+  EXPECT_EQ(WebInputEvent::kMouseMove, test_plugin->GetLastInputEventType());
+  EXPECT_EQ(rect.width / 4, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 4, test_plugin->GetLastEventLocation().Y());
+}
+
+TEST_F(WebPluginContainerTest, MouseWheelEventZoomed) {
+  RegisterMockedURL("plugin_scroll.html");
+  CustomPluginWebFrameClient<EventTestPlugin>
+      plugin_web_frame_client;  // Must outlive webViewHelper.
+  FrameTestHelpers::WebViewHelper web_view_helper;
+  WebView* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_scroll.html", true, &plugin_web_frame_client);
+  DCHECK(web_view);
+  web_view->GetSettings()->SetPluginsEnabled(true);
+  web_view->Resize(WebSize(300, 300));
+  web_view->SetPageScaleFactor(2);
+  web_view->SmoothScroll(0, 300, 0);
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrame()->GetDocument().GetElementById(
+          WebString::FromUTF8("scrolled-plugin"));
+  plugin_container_one_element.PluginContainer()->RequestTouchEventType(
+      WebPluginContainer::kTouchEventRequestTypeRaw);
+  WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(
+                          plugin_container_one_element.PluginContainer())
+                          ->Plugin();
+  EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
+
+  WebMouseWheelEvent event(WebInputEvent::kMouseWheel,
+                           WebInputEvent::kNoModifiers,
+                           WebInputEvent::kTimeStampForTesting);
+
+  WebRect rect = plugin_container_one_element.BoundsInViewport();
+  event.SetPositionInWidget(rect.x + rect.width / 2, rect.y + rect.height / 2);
+
+  web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+  RunPendingTasks();
+
+  // rect.width/height divided by 4 because the rect is in viewport bounds and
+  // there is a scale of 2 set.
+  EXPECT_EQ(WebInputEvent::kMouseWheel, test_plugin->GetLastInputEventType());
+  EXPECT_EQ(rect.width / 4, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 4, test_plugin->GetLastEventLocation().Y());
+}
+
+TEST_F(WebPluginContainerTest, TouchEventZoomed) {
+  RegisterMockedURL("plugin_scroll.html");
+  CustomPluginWebFrameClient<EventTestPlugin>
+      plugin_web_frame_client;  // Must outlive webViewHelper.
+  FrameTestHelpers::WebViewHelper web_view_helper;
+  WebView* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_scroll.html", true, &plugin_web_frame_client);
+  DCHECK(web_view);
+  web_view->GetSettings()->SetPluginsEnabled(true);
+  web_view->Resize(WebSize(300, 300));
+  web_view->SetPageScaleFactor(2);
+  web_view->SmoothScroll(0, 300, 0);
+  web_view->UpdateAllLifecyclePhases();
+  RunPendingTasks();
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrame()->GetDocument().GetElementById(
+          WebString::FromUTF8("scrolled-plugin"));
+  plugin_container_one_element.PluginContainer()->RequestTouchEventType(
+      WebPluginContainer::kTouchEventRequestTypeRaw);
+  WebPlugin* plugin = static_cast<WebPluginContainerImpl*>(
+                          plugin_container_one_element.PluginContainer())
+                          ->Plugin();
+  EventTestPlugin* test_plugin = static_cast<EventTestPlugin*>(plugin);
+
+  WebTouchEvent event(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
+                      WebInputEvent::kTimeStampForTesting);
+  event.touches_length = 1;
+  WebRect rect = plugin_container_one_element.BoundsInViewport();
+
+  event.touches[0].state = WebTouchPoint::kStatePressed;
+  event.touches[0].position =
+      WebFloatPoint(rect.x + rect.width / 2, rect.y + rect.height / 2);
+
+  web_view->HandleInputEvent(WebCoalescedInputEvent(event));
+  RunPendingTasks();
+
+  // rect.width/height divided by 4 because the rect is in viewport bounds and
+  // there is a scale of 2 set.
+  EXPECT_EQ(WebInputEvent::kTouchStart, test_plugin->GetLastInputEventType());
+  EXPECT_EQ(rect.width / 4, test_plugin->GetLastEventLocation().X());
+  EXPECT_EQ(rect.height / 4, test_plugin->GetLastEventLocation().Y());
 }
 
 // Verify that isRectTopmost returns false when the document is detached.
diff --git a/third_party/WebKit/Source/web/tests/data/plugin_scroll.html b/third_party/WebKit/Source/web/tests/data/plugin_scroll.html
new file mode 100644
index 0000000..af1dc64
--- /dev/null
+++ b/third_party/WebKit/Source/web/tests/data/plugin_scroll.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style type="text/css">
+    body { margin: 0; padding: 0; }
+  </style>
+</head>
+<body>
+  <div style="width: 30px; height: 400px;"></div>
+  <object id="scrolled-plugin"
+      border=0
+      type="application/x-webkit-test-webplugin"
+      width="40"
+      height="40">
+  </object>
+
+</body>
+</html>
diff --git a/third_party/adobe/OWNERS b/third_party/adobe/OWNERS
index 06a45bd..7b931968 100644
--- a/third_party/adobe/OWNERS
+++ b/third_party/adobe/OWNERS
@@ -1,7 +1,6 @@
 cpu@chromium.org
 jschuh@chromium.org
 raymes@chromium.org
-shess@chromium.org
 viettrungluu@chromium.org
 yzshen@chromium.org
 zelidrag@chromium.org
diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium
index c2d1f27..c6104f5 100644
--- a/third_party/tlslite/README.chromium
+++ b/third_party/tlslite/README.chromium
@@ -56,3 +56,4 @@
 - patches/token_binding_version.patch: Update Token Binding version number.
 - patches/renegotiation_indication.patch: Implement the renegotiation
   indication extension (RFC 5746) without supporting renegotiation.
+- patches/tls13_intolerance.patch: Extend the intolerance simulation to TLS 1.3.
diff --git a/third_party/tlslite/patches/tls13_intolerance.patch b/third_party/tlslite/patches/tls13_intolerance.patch
new file mode 100644
index 0000000..6f19571
--- /dev/null
+++ b/third_party/tlslite/patches/tls13_intolerance.patch
@@ -0,0 +1,66 @@
+diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
+index 82e8c075fe2a..8fb75d0948e4 100644
+--- a/third_party/tlslite/tlslite/constants.py
++++ b/third_party/tlslite/tlslite/constants.py
+@@ -58,6 +58,7 @@ class ExtensionType:    # RFC 6066 / 4366
+     signed_cert_timestamps = 18  # RFC 6962
+     extended_master_secret = 23  # RFC 7627
+     token_binding = 24           # draft-ietf-tokbind-negotiation
++    supported_versions = 43      # draft-ietf-tls-tls13-18
+     tack = 0xF300
+     supports_npn = 13172
+     channel_id = 30032
+diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
+index ac7e563021d9..b29db939c2a8 100644
+--- a/third_party/tlslite/tlslite/messages.py
++++ b/third_party/tlslite/tlslite/messages.py
+@@ -140,6 +140,7 @@ class ClientHello(HandshakeMsg):
+         self.tb_client_params = []
+         self.support_signed_cert_timestamps = False
+         self.status_request = False
++        self.has_supported_versions = False
+         self.ri = False
+ 
+     def create(self, version, random, session_id, cipher_suites,
+@@ -251,6 +252,11 @@ class ClientHello(HandshakeMsg):
+                         if extLength != 1 or p.getFixBytes(extLength)[0] != 0:
+                             raise SyntaxError()
+                         self.ri = True
++                    elif extType == ExtensionType.supported_versions:
++                        # Ignore the extension, but make a note of it for
++                        # intolerance simulation.
++                        self.has_supported_versions = True
++                        _ = p.getFixBytes(extLength)
+                     else:
+                         _ = p.getFixBytes(extLength)
+                     index2 = p.index
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index 8ba1c6e636ab..2309d4fa8f3a 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -1457,6 +1457,15 @@ class TLSConnection(TLSRecordLayer):
+         self._handshakeDone(resumed=False)
+ 
+ 
++    def _isIntolerant(self, settings, clientHello):
++        if settings.tlsIntolerant is None:
++            return False
++        clientVersion = clientHello.client_version
++        if clientHello.has_supported_versions:
++            clientVersion = (3, 4)
++        return clientVersion >= settings.tlsIntolerant
++
++
+     def _serverGetClientHello(self, settings, certChain, verifierDB,
+                                 sessionCache, anon, fallbackSCSV):
+         #Tentatively set version to most-desirable version, so if an error
+@@ -1480,8 +1489,7 @@ class TLSConnection(TLSRecordLayer):
+                 yield result
+ 
+         #If simulating TLS intolerance, reject certain TLS versions.
+-        elif (settings.tlsIntolerant is not None and
+-              clientHello.client_version >= settings.tlsIntolerant):
++        elif self._isIntolerant(settings, clientHello):
+             if settings.tlsIntoleranceType == "alert":
+                 for result in self._sendError(\
+                     AlertDescription.handshake_failure):
diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
index 82e8c075..8fb75d0 100644
--- a/third_party/tlslite/tlslite/constants.py
+++ b/third_party/tlslite/tlslite/constants.py
@@ -58,6 +58,7 @@
     signed_cert_timestamps = 18  # RFC 6962
     extended_master_secret = 23  # RFC 7627
     token_binding = 24           # draft-ietf-tokbind-negotiation
+    supported_versions = 43      # draft-ietf-tls-tls13-18
     tack = 0xF300
     supports_npn = 13172
     channel_id = 30032
diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
index ac7e563..b29db93 100644
--- a/third_party/tlslite/tlslite/messages.py
+++ b/third_party/tlslite/tlslite/messages.py
@@ -140,6 +140,7 @@
         self.tb_client_params = []
         self.support_signed_cert_timestamps = False
         self.status_request = False
+        self.has_supported_versions = False
         self.ri = False
 
     def create(self, version, random, session_id, cipher_suites,
@@ -251,6 +252,11 @@
                         if extLength != 1 or p.getFixBytes(extLength)[0] != 0:
                             raise SyntaxError()
                         self.ri = True
+                    elif extType == ExtensionType.supported_versions:
+                        # Ignore the extension, but make a note of it for
+                        # intolerance simulation.
+                        self.has_supported_versions = True
+                        _ = p.getFixBytes(extLength)
                     else:
                         _ = p.getFixBytes(extLength)
                     index2 = p.index
diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
index 8ba1c6e..2309d4f 100644
--- a/third_party/tlslite/tlslite/tlsconnection.py
+++ b/third_party/tlslite/tlslite/tlsconnection.py
@@ -1457,6 +1457,15 @@
         self._handshakeDone(resumed=False)
 
 
+    def _isIntolerant(self, settings, clientHello):
+        if settings.tlsIntolerant is None:
+            return False
+        clientVersion = clientHello.client_version
+        if clientHello.has_supported_versions:
+            clientVersion = (3, 4)
+        return clientVersion >= settings.tlsIntolerant
+
+
     def _serverGetClientHello(self, settings, certChain, verifierDB,
                                 sessionCache, anon, fallbackSCSV):
         #Tentatively set version to most-desirable version, so if an error
@@ -1480,8 +1489,7 @@
                 yield result
 
         #If simulating TLS intolerance, reject certain TLS versions.
-        elif (settings.tlsIntolerant is not None and
-              clientHello.client_version >= settings.tlsIntolerant):
+        elif self._isIntolerant(settings, clientHello):
             if settings.tlsIntoleranceType == "alert":
                 for result in self._sendError(\
                     AlertDescription.handshake_failure):
diff --git a/tools/chrome_proxy/webdriver/bypass.py b/tools/chrome_proxy/webdriver/bypass.py
index 2b3259fe..7eb98e1c5 100644
--- a/tools/chrome_proxy/webdriver/bypass.py
+++ b/tools/chrome_proxy/webdriver/bypass.py
@@ -126,14 +126,17 @@
         self.assertNotHasChromeProxyViaHeader(response)
         self.assertEqual(u'http/1.1', response.protocol)
 
-      # Check that the BlockTypePrimary histogram has a single entry in the
+      # Check that the BlockTypePrimary histogram has at least one entry in the
       # MissingViaHeader4xx category (which is enum value 4), to make sure that
       # the bypass was caused by the missing via header logic and not something
-      # else.
+      # else. The favicon for this URL may also be fetched, but will return a
+      # 404.
       histogram = test_driver.GetHistogram(
           "DataReductionProxy.BlockTypePrimary")
-      self.assertEqual(1, histogram['count'])
-      self.assertIn({'count': 1, 'high': 5, 'low': 4}, histogram['buckets'])
+      self.assertNotEqual(0, histogram['count'])
+      self.assertEqual(1, len(histogram['buckets']))
+      self.assertEqual(5, histogram['buckets'][0]['high'])
+      self.assertEqual(4, histogram['buckets'][0]['low'])
 
   # Verify that the Data Reduction Proxy understands the "exp" directive.
   def testExpDirectiveBypass(self):
@@ -172,6 +175,23 @@
       for response in responses:
         self.assertHasChromeProxyViaHeader(response)
 
+  # Data Saver uses a HTTPS proxy by default, if that fails it will fall back to
+  # a HTTP proxy.
+  def testBadHTTPSFallback(self):
+    with TestDriver() as test_driver:
+      test_driver.AddChromeArg('--enable-spdy-proxy-auth')
+      # Set the primary (HTTPS) proxy to a bad one.  
+      # That will force Data Saver to the HTTP proxy for normal page requests.
+      test_driver.AddChromeArg('--spdy-proxy-auth-origin='
+                               'https://nonexistent.googlezip.net')          
+      test_driver.AddChromeArg('--data-reduction-proxy-http-proxies='
+                               'http://compress.googlezip.net')  
+          
+      test_driver.LoadURL('http://check.googlezip.net/fallback/')
+      responses = test_driver.GetHTTPResponses()      
+      self.assertNotEqual(0, len(responses))
+      for response in responses:        
+        self.assertEqual(80, response.port)        
 
 if __name__ == '__main__':
   IntegrationTest.RunAllTests()
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 9d3890930..18ad474 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -22498,6 +22498,9 @@
 </histogram>
 
 <histogram name="History.FaviconsRecoveredPercentage" units="%">
+  <obsolete>
+    No longer tracked as of March 2017.
+  </obsolete>
   <owner>rpop@google.com</owner>
   <summary>
     Size of the recovered Favicons database relative to the original corrupt
@@ -22509,6 +22512,9 @@
 </histogram>
 
 <histogram name="History.FaviconsRecoveredRowsFaviconBitmaps">
+  <obsolete>
+    No longer tracked as of March 2017.
+  </obsolete>
   <owner>rpop@google.com</owner>
   <summary>
     Rows recovered from [favicon_bitmaps] table in Favicons recovery.
@@ -22516,11 +22522,17 @@
 </histogram>
 
 <histogram name="History.FaviconsRecoveredRowsFavicons">
+  <obsolete>
+    No longer tracked as of March 2017.
+  </obsolete>
   <owner>rpop@google.com</owner>
   <summary>Rows recovered from [favicons] table in Favicons recovery.</summary>
 </histogram>
 
 <histogram name="History.FaviconsRecoveredRowsIconMapping">
+  <obsolete>
+    No longer tracked as of March 2017.
+  </obsolete>
   <owner>rpop@google.com</owner>
   <summary>
     Rows recovered from [icon_mapping] table in Favicons recovery.
@@ -22528,6 +22540,9 @@
 </histogram>
 
 <histogram name="History.FaviconsRecovery" enum="HistoryFaviconsRecoveryEnum">
+  <obsolete>
+    No longer tracked as of March 2017.
+  </obsolete>
   <owner>rpop@google.com</owner>
   <summary>
     Track results of SQLite database recovery code in thumbnail_database.cc.
@@ -25765,6 +25780,9 @@
 </histogram>
 
 <histogram name="Media.Android.NumMediaServerCrashes">
+  <obsolete>
+    Deprecated as of 04/2017
+  </obsolete>
   <owner>qinmin@chromium.org</owner>
   <summary>
     Android: Number of consecutive media server crashes monitored before it is
@@ -25775,6 +25793,9 @@
 
 <histogram name="Media.Android.ThrottleInfobarResponse"
     enum="ThrottleInfobarResponse">
+  <obsolete>
+    Deprecated as of 04/2017
+  </obsolete>
   <owner>qinmin@chromium.org</owner>
   <summary>
     Android: The distribution of responses to the media throttle infobar prompt.
@@ -38277,6 +38298,22 @@
   </summary>
 </histogram>
 
+<histogram name="Net.SSLVersionInterferenceError" enum="NetErrorCodes">
+  <owner>davidben@chromium.org</owner>
+  <summary>
+    For each detected SSL version interference, what network error the original
+    failed connection reported.
+  </summary>
+</histogram>
+
+<histogram name="Net.SSLVersionInterferenceProbeTrigger" enum="NetErrorCodes">
+  <owner>davidben@chromium.org</owner>
+  <summary>
+    For each SSL version interference probe, what network error triggered it.
+    Probes are only triggered for a small set of network errors.
+  </summary>
+</histogram>
+
 <histogram name="Net.TCP_Connection_Idle_Sockets">
   <obsolete>
     Deprecated 04/2016 as doesn't have data nor owner.
@@ -86427,6 +86464,8 @@
   <int value="-202" label="CERT_AUTHORITY_INVALID"/>
   <int value="-201" label="CERT_DATE_INVALID"/>
   <int value="-200" label="CERT_COMMON_NAME_INVALID"/>
+  <int value="-175" label="SSL_VERSION_INTERFERENCE"/>
+  <int value="-174" label="READ_IF_READY_NOT_IMPLEMENTED"/>
   <int value="-173" label="WS_UPGRADE"/>
   <int value="-172" label="SSL_OBSOLETE_CIPHER"/>
   <int value="-171" label="CT_CONSISTENCY_PROOF_PARSING_FAILED"/>
@@ -97843,6 +97882,9 @@
 
 <enum name="HistoryFaviconsRecoveryEnum" type="int">
   <summary>Error states noted in thumbnail_database.cc recovery code.</summary>
+  <obsolete>
+    History.FaviconsRecovery no longer tracked as of March 2017.
+  </obsolete>
   <int value="0" label="RECOVERY_EVENT_RECOVERED">Successful recovery.</int>
   <int value="1" label="RECOVERY_EVENT_FAILED_SCOPER">
     sql::Recovery failed init.
@@ -97941,7 +97983,7 @@
   <int value="1" label="RECOVERY_EVENT_DEPRECATED">
     Recovery found deprecated version and razed.
   </int>
-  <int value="2" label="RECOVERY_EVENT_FAILED_SCOPER">
+  <int value="2" label="RECOVERY_EVENT_FAILED_SCOPER (obsolete Mar 2017)">
     sql::Recovery failed init.
   </int>
   <int value="3" label="RECOVERY_EVENT_FAILED_META_VERSION">
@@ -97950,13 +97992,14 @@
   <int value="4" label="RECOVERY_EVENT_FAILED_META_WRONG_VERSION">
     Recovery meta table has an unexpected version.
   </int>
-  <int value="5" label="RECOVERY_EVENT_FAILED_META_INIT">
+  <int value="5" label="RECOVERY_EVENT_FAILED_META_INIT (obsolete Mar 2017)">
     Failed sql::MetaTable::Init().
   </int>
-  <int value="6" label="RECOVERY_EVENT_FAILED_SCHEMA_INIT">
+  <int value="6" label="RECOVERY_EVENT_FAILED_SCHEMA_INIT (obsolete Mar 2017)">
     Failed to init target schema.
   </int>
-  <int value="7" label="RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS">
+  <int value="7"
+      label="RECOVERY_EVENT_FAILED_AUTORECOVER_THUMBNAILS (obsolete Mar 2017)">
     Failed recovery on thumbnails table.
   </int>
   <int value="8" label="RECOVERY_EVENT_FAILED_COMMIT">
@@ -104344,6 +104387,8 @@
   <int value="171" label="CT_CONSISTENCY_PROOF_PARSING_FAILED"/>
   <int value="172" label="SSL_OBSOLETE_CIPHER"/>
   <int value="173" label="WS_UPGRADE"/>
+  <int value="174" label="READ_IF_READY_NOT_IMPLEMENTED"/>
+  <int value="175" label="SSL_VERSION_INTERFERENCE"/>
   <int value="200" label="CERT_COMMON_NAME_INVALID"/>
   <int value="201" label="CERT_DATE_INVALID"/>
   <int value="202" label="CERT_AUTHORITY_INVALID"/>
@@ -112666,6 +112711,10 @@
     Autorecover failed setup with NOTADB, then successfully deleted the
     unrecoverable db and verified that it now works.
   </int>
+  <int value="32" label="RECOVERY_FAILED_AUTORECOVERDB_META_VERSION">
+    Autorecover failed because required version information was missing from the
+    [meta] table.
+  </int>
 </enum>
 
 <enum name="SqliteStatsEnum" type="int">
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py
index 06b1d8b7..f37ce44 100644
--- a/tools/perf/benchmarks/media.py
+++ b/tools/perf/benchmarks/media.py
@@ -66,8 +66,6 @@
     category_filter.AddIncludedCategory('rail')
 
     options = timeline_based_measurement.Options(category_filter)
-    options.config.enable_atrace_trace = True
-    options.config.atrace_config.categories = ['sched']
     options.config.enable_battor_trace = True
     options.SetTimelineBasedMetrics(['powerMetric', 'cpuTimeMetric'])
     return options
@@ -142,10 +140,7 @@
 
   @classmethod
   def ShouldDisable(cls, possible_browser):
-    # crbug.com/707286: This benchmark is having issues with devices other
-    # than Nexus 5X. Disabling on those devices until we figure out the cause.
-    return (cls.IsSvelte(possible_browser) or
-            possible_browser.platform.GetDeviceTypeName() != 'Nexus 5X')
+    return cls.IsSvelte(possible_browser)
 
   @classmethod
   def Name(cls):
diff --git a/tools/perf/benchmarks/tab_switching.py b/tools/perf/benchmarks/tab_switching.py
index ed75b50..0b485fbc 100644
--- a/tools/perf/benchmarks/tab_switching.py
+++ b/tools/perf/benchmarks/tab_switching.py
@@ -9,9 +9,10 @@
 from telemetry import benchmark
 
 
-@benchmark.Enabled('has tabs')
+#@benchmark.Enabled('has tabs')
 @benchmark.Disabled('mac-reference')  # http://crbug.com/612774
 @benchmark.Disabled('android')  # http://crbug.com/460084
+@benchmark.Disabled('all') # http://crbug.com/710524
 class TabSwitchingTypical25(perf_benchmark.PerfBenchmark):
   """This test records the MPArch.RWH_TabSwitchPaintDuration histogram.
 
diff --git a/ui/events/blink/web_input_event_builders_win.cc b/ui/events/blink/web_input_event_builders_win.cc
index 56afe59..148d6e468 100644
--- a/ui/events/blink/web_input_event_builders_win.cc
+++ b/ui/events/blink/web_input_event_builders_win.cc
@@ -167,7 +167,7 @@
   WebMouseEvent result(type, modifiers, time_stamp);
   result.pointer_type = pointer_type;
   result.button = button;
-  result.id = ui::PointerEvent::kMousePointerId;
+  result.id = ui::MouseEvent::kMousePointerId;
 
   // set position fields:
   result.SetPositionInWidget(static_cast<short>(LOWORD(lparam)),
diff --git a/ui/events/blink/web_input_event_unittest.cc b/ui/events/blink/web_input_event_unittest.cc
index c48280c..8803cb01 100644
--- a/ui/events/blink/web_input_event_unittest.cc
+++ b/ui/events/blink/web_input_event_unittest.cc
@@ -429,9 +429,6 @@
   {
     // Stylus values for PointerDetails.
     base::TimeTicks timestamp = EventTimeForNow();
-    MouseEvent ui_event(ET_MOUSE_PRESSED, gfx::Point(123, 321),
-                        gfx::Point(123, 321), timestamp, EF_LEFT_MOUSE_BUTTON,
-                        EF_LEFT_MOUSE_BUTTON);
     PointerDetails pointer_details(EventPointerType::POINTER_TYPE_PEN,
                                    /* id */ 63,
                                    /* radius_x */ 0.0f,
@@ -441,7 +438,9 @@
                                    /* tilt_y */ -89.5f,
                                    /* tangential_pressure */ 0.6f,
                                    /* twist */ 269);
-    ui_event.set_pointer_details(pointer_details);
+    MouseEvent ui_event(ET_MOUSE_PRESSED, gfx::Point(123, 321),
+                        gfx::Point(123, 321), timestamp, EF_LEFT_MOUSE_BUTTON,
+                        EF_LEFT_MOUSE_BUTTON, pointer_details);
     blink::WebMouseEvent webkit_event =
         MakeWebMouseEvent(ui_event, base::Bind(&GetScreenLocationFromEvent));
 
diff --git a/ui/events/event.cc b/ui/events/event.cc
index 64f06d0c..07c1753c 100644
--- a/ui/events/event.cc
+++ b/ui/events/event.cc
@@ -533,7 +533,7 @@
       id(pointer_id) {
   if (pointer_id == PointerDetails::kUnknownPointerId) {
     id = pointer_type == EventPointerType::POINTER_TYPE_MOUSE
-             ? PointerEvent::kMousePointerId
+             ? MouseEvent::kMousePointerId
              : 0;
   }
 }
@@ -625,14 +625,15 @@
                        const gfx::Point& root_location,
                        base::TimeTicks time_stamp,
                        int flags,
-                       int changed_button_flags)
+                       int changed_button_flags,
+                       const PointerDetails& pointer_details)
     : LocatedEvent(type,
                    gfx::PointF(location),
                    gfx::PointF(root_location),
                    time_stamp,
                    flags),
       changed_button_flags_(changed_button_flags),
-      pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_MOUSE)) {
+      pointer_details_(pointer_details) {
   DCHECK_NE(ET_MOUSEWHEEL, type);
   latency()->AddLatencyNumber(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, 0);
   if (this->type() == ET_MOUSE_MOVED && IsAnyButton())
@@ -757,14 +758,7 @@
   set_flags(f);
 }
 
-void MouseEvent::set_pointer_details(const PointerDetails& details) {
-  DCHECK_NE(EventPointerType::POINTER_TYPE_TOUCH,
-            pointer_details_.pointer_type);
-  DCHECK_NE(EventPointerType::POINTER_TYPE_TOUCH, details.pointer_type);
-  DCHECK(pointer_details_.id == PointerEvent::kMousePointerId ||
-         details.id != PointerEvent::kMousePointerId);
-  pointer_details_ = details;
-}
+const int MouseEvent::kMousePointerId = std::numeric_limits<int32_t>::max();
 
 ////////////////////////////////////////////////////////////////////////////////
 // MouseWheelEvent
@@ -1086,8 +1080,6 @@
     latency()->set_source_event_type(ui::SourceEventType::OTHER);
 }
 
-const int PointerEvent::kMousePointerId = std::numeric_limits<int32_t>::max();
-
 ////////////////////////////////////////////////////////////////////////////////
 // KeyEvent
 
diff --git a/ui/events/event.h b/ui/events/event.h
index 16dce04e..b6ffd82 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -481,6 +481,8 @@
 
 class EVENTS_EXPORT MouseEvent : public LocatedEvent {
  public:
+  static const int32_t kMousePointerId;
+
   explicit MouseEvent(const base::NativeEvent& native_event);
 
   // |pointer_event.IsMousePointerEvent()| must be true.
@@ -519,7 +521,10 @@
              const gfx::Point& root_location,
              base::TimeTicks time_stamp,
              int flags,
-             int changed_button_flags);
+             int changed_button_flags,
+             const PointerDetails& pointer_details =
+                 PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
+                                kMousePointerId));
 
   // Conveniences to quickly test what button is down
   bool IsOnlyLeftMouseButton() const {
@@ -581,7 +586,6 @@
 
   // Event details common to MouseEvent and TouchEvent.
   const PointerDetails& pointer_details() const { return pointer_details_; }
-  void set_pointer_details(const PointerDetails& details);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(EventTest, DoubleClickRequiresRelease);
@@ -733,8 +737,6 @@
 
 class EVENTS_EXPORT PointerEvent : public LocatedEvent {
  public:
-  static const int32_t kMousePointerId;
-
   // Returns true if a PointerEvent can be constructed from |event|. Currently,
   // only mouse and touch events can be converted to pointer events.
   static bool CanConvertFrom(const Event& event);
diff --git a/ui/events/event_unittest.cc b/ui/events/event_unittest.cc
index 9a6a779..29e5048a 100644
--- a/ui/events/event_unittest.cc
+++ b/ui/events/event_unittest.cc
@@ -708,8 +708,6 @@
 }
 
 TEST(EventTest, PointerDetailsStylus) {
-  ui::MouseEvent stylus_event(ET_MOUSE_PRESSED, gfx::Point(0, 0),
-                              gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0);
   ui::PointerDetails pointer_details(EventPointerType::POINTER_TYPE_PEN,
                                      /* pointer_id*/ 0,
                                      /* radius_x */ 0.0f,
@@ -720,7 +718,9 @@
                                      /* tangential_pressure */ 0.7f,
                                      /* twist */ 196);
 
-  stylus_event.set_pointer_details(pointer_details);
+  ui::MouseEvent stylus_event(ET_MOUSE_PRESSED, gfx::Point(0, 0),
+                              gfx::Point(0, 0), ui::EventTimeForNow(), 0, 0,
+                              pointer_details);
   EXPECT_EQ(EventPointerType::POINTER_TYPE_PEN,
             stylus_event.pointer_details().pointer_type);
   EXPECT_EQ(21.0f, stylus_event.pointer_details().force);
@@ -856,7 +856,7 @@
                                gfx::Point(0, 0), base::TimeTicks(), 0, 0);
     ui::PointerEvent pointer_event(mouse_event);
     EXPECT_EQ(pointer_event.pointer_details().id,
-              ui::PointerEvent::kMousePointerId);
+              ui::MouseEvent::kMousePointerId);
   }
 
   for (int touch_id = 0; touch_id < 8; touch_id++) {
diff --git a/ui/events/events_default.cc b/ui/events/events_default.cc
index fac6472..c609e14902 100644
--- a/ui/events/events_default.cc
+++ b/ui/events/events_default.cc
@@ -54,7 +54,7 @@
       static_cast<const ui::MouseEvent*>(native_event);
   DCHECK(event->IsMouseEvent() || event->IsScrollEvent());
   PointerDetails pointer_detail = event->pointer_details();
-  pointer_detail.id = PointerEvent::kMousePointerId;
+  pointer_detail.id = MouseEvent::kMousePointerId;
   return pointer_detail;
 }
 
diff --git a/ui/events/mojo/event_struct_traits.cc b/ui/events/mojo/event_struct_traits.cc
index 1a5180fa..d2a66cb 100644
--- a/ui/events/mojo/event_struct_traits.cc
+++ b/ui/events/mojo/event_struct_traits.cc
@@ -295,9 +295,9 @@
                             static_cast<int>(pointer_data->wheel_data->delta_x),
                             static_cast<int>(
                                 pointer_data->wheel_data->delta_y)),
-                        ui::PointerEvent::kMousePointerId)
+                        ui::MouseEvent::kMousePointerId)
                   : ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE,
-                                       ui::PointerEvent::kMousePointerId),
+                                       ui::MouseEvent::kMousePointerId),
               ui::EventTimeForNow()));
           break;
         }
diff --git a/ui/events/mojo/struct_traits_unittest.cc b/ui/events/mojo/struct_traits_unittest.cc
index 5f2ba7b..3ec4376 100644
--- a/ui/events/mojo/struct_traits_unittest.cc
+++ b/ui/events/mojo/struct_traits_unittest.cc
@@ -83,22 +83,22 @@
       // Mouse pointer events:
       {ET_POINTER_DOWN, gfx::Point(10, 10), gfx::Point(20, 30), EF_NONE, 0,
        PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
-                      PointerEvent::kMousePointerId),
+                      MouseEvent::kMousePointerId),
        base::TimeTicks()},
       {ET_POINTER_MOVED, gfx::Point(1, 5), gfx::Point(5, 1),
        EF_LEFT_MOUSE_BUTTON, EF_LEFT_MOUSE_BUTTON,
        PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
-                      PointerEvent::kMousePointerId),
+                      MouseEvent::kMousePointerId),
        base::TimeTicks()},
       {ET_POINTER_UP, gfx::Point(411, 130), gfx::Point(20, 30),
        EF_MIDDLE_MOUSE_BUTTON | EF_RIGHT_MOUSE_BUTTON, EF_RIGHT_MOUSE_BUTTON,
        PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
-                      PointerEvent::kMousePointerId),
+                      MouseEvent::kMousePointerId),
        base::TimeTicks()},
       {ET_POINTER_EXITED, gfx::Point(10, 10), gfx::Point(20, 30),
        EF_BACK_MOUSE_BUTTON, 0,
        PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
-                      PointerEvent::kMousePointerId),
+                      MouseEvent::kMousePointerId),
        base::TimeTicks()},
 
       // Touch pointer events:
diff --git a/ui/events/ozone/evdev/event_factory_evdev.cc b/ui/events/ozone/evdev/event_factory_evdev.cc
index c071853..00b18819 100644
--- a/ui/events/ozone/evdev/event_factory_evdev.cc
+++ b/ui/events/ozone/evdev/event_factory_evdev.cc
@@ -218,11 +218,10 @@
   MouseEvent event(ui::ET_MOUSE_MOVED, gfx::Point(), gfx::Point(),
                    params.timestamp,
                    modifiers_.GetModifierFlags() | params.flags,
-                   /* changed_button_flags */ 0);
+                   /* changed_button_flags */ 0, details);
   event.set_location_f(location);
   event.set_root_location_f(location);
   event.set_source_device_id(params.device_id);
-  event.set_pointer_details(details);
   DispatchUiEvent(&event);
 }
 
@@ -279,11 +278,10 @@
   MouseEvent event(params.down ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
                    gfx::Point(), gfx::Point(), params.timestamp,
                    modifiers_.GetModifierFlags() | flag | params.flags,
-                   /* changed_button_flags */ flag);
+                   /* changed_button_flags */ flag, details);
   event.set_location_f(location);
   event.set_root_location_f(location);
   event.set_source_device_id(params.device_id);
-  event.set_pointer_details(details);
   DispatchUiEvent(&event);
 }
 
@@ -341,7 +339,6 @@
   touch_event.set_location_f(location);
   touch_event.set_root_location_f(location);
   touch_event.set_source_device_id(params.device_id);
-  touch_event.set_pointer_details(details);
   DispatchUiEvent(&touch_event);
 
   if (params.type == ET_TOUCH_RELEASED || params.type == ET_TOUCH_CANCELLED) {
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.cc b/ui/ozone/platform/drm/gpu/drm_thread.cc
index 8faec76..06bec8a9 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.cc
+++ b/ui/ozone/platform/drm/gpu/drm_thread.cc
@@ -11,7 +11,6 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
 #include "ui/ozone/platform/drm/gpu/drm_buffer.h"
 #include "ui/ozone/platform/drm/gpu/drm_device_generator.h"
diff --git a/ui/ozone/platform/drm/gpu/drm_thread.h b/ui/ozone/platform/drm/gpu/drm_thread.h
index fe3864e..be12617 100644
--- a/ui/ozone/platform/drm/gpu/drm_thread.h
+++ b/ui/ozone/platform/drm/gpu/drm_thread.h
@@ -14,7 +14,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "ui/gfx/native_pixmap_handle.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/vsync_provider.h"
diff --git a/ui/views/accessibility/ax_view_obj_wrapper.cc b/ui/views/accessibility/ax_view_obj_wrapper.cc
index 37c2af3..2a22590 100644
--- a/ui/views/accessibility/ax_view_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_view_obj_wrapper.cc
@@ -51,7 +51,7 @@
 
   out_node_data->id = GetID();
 
-  if (view_->IsFocusable())
+  if (view_->IsAccessibilityFocusable())
     out_node_data->state |= 1 << ui::AX_STATE_FOCUSABLE;
   if (!view_->visible())
     out_node_data->state |= 1 << ui::AX_STATE_INVISIBLE;
diff --git a/ui/views/mus/mus_client.cc b/ui/views/mus/mus_client.cc
index ee16fd9..136424b6 100644
--- a/ui/views/mus/mus_client.cc
+++ b/ui/views/mus/mus_client.cc
@@ -7,7 +7,6 @@
 #include "base/bind.h"
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread.h"
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ui/public/cpp/gpu/gpu.h"
 #include "services/ui/public/cpp/property_type_converters.h"
diff --git a/ui/views/mus/screen_mus.cc b/ui/views/mus/screen_mus.cc
index a8790496..8618d1b 100644
--- a/ui/views/mus/screen_mus.cc
+++ b/ui/views/mus/screen_mus.cc
@@ -8,7 +8,6 @@
 
 #include "ui/views/mus/screen_mus.h"
 
-#include "services/service_manager/public/cpp/connection.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/ui/public/interfaces/constants.mojom.h"
 #include "ui/aura/env.h"
diff --git a/ui/views/mus/views_mus_test_suite.cc b/ui/views/mus/views_mus_test_suite.cc
index 8483a258..1773510 100644
--- a/ui/views/mus/views_mus_test_suite.cc
+++ b/ui/views/mus/views_mus_test_suite.cc
@@ -205,7 +205,7 @@
 
     // ui/views/mus requires a WindowManager running, so launch test_wm.
     service_manager::Connector* connector = context_->connector();
-    connector->Connect("test_wm");
+    connector->StartService("test_wm");
     service_manager_connector_ = connector->Clone();
     service_manager_identity_ = context_->identity();
     wait->Signal();
diff --git a/ui/views/widget/desktop_aura/x11_desktop_handler.cc b/ui/views/widget/desktop_aura/x11_desktop_handler.cc
index 0e9dec7..4d9ba57 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_handler.cc
+++ b/ui/views/widget/desktop_aura/x11_desktop_handler.cc
@@ -40,6 +40,11 @@
   return g_handler;
 }
 
+// static
+X11DesktopHandler* X11DesktopHandler::get_dont_create() {
+  return g_handler;
+}
+
 X11DesktopHandler::X11DesktopHandler()
     : xdisplay_(gfx::GetXDisplay()),
       x_root_window_(DefaultRootWindow(xdisplay_)),
diff --git a/ui/views/widget/desktop_aura/x11_desktop_handler.h b/ui/views/widget/desktop_aura/x11_desktop_handler.h
index 06d78ba8..00484b2 100644
--- a/ui/views/widget/desktop_aura/x11_desktop_handler.h
+++ b/ui/views/widget/desktop_aura/x11_desktop_handler.h
@@ -38,9 +38,14 @@
 class VIEWS_EXPORT X11DesktopHandler : public ui::PlatformEventDispatcher,
                                        public aura::EnvObserver {
  public:
-  // Returns the singleton handler.
+  // Returns the singleton handler.  Creates one if one has not
+  // already been created.
   static X11DesktopHandler* get();
 
+  // Returns the singleton handler, or nullptr if one has not already
+  // been created.
+  static X11DesktopHandler* get_dont_create();
+
   // Adds/removes X11DesktopHandlerObservers.
   void AddObserver(X11DesktopHandlerObserver* observer);
   void RemoveObserver(X11DesktopHandlerObserver* observer);
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 8d690aac..7590741f 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1749,12 +1749,11 @@
     default:
       NOTREACHED();
   }
-  ui::MouseEvent event(event_type, point, point, base::TimeTicks::Now(), flag,
-                       flag);
   ui::PointerDetails pointer_details(
       input_type, pointer_id, /* radius_x */ 0.0f, /* radius_y */ 0.0f,
       pressure, tilt_x, tilt_y, /* tangential_pressure */ 0.0f, rotation);
-  event.set_pointer_details(pointer_details);
+  ui::MouseEvent event(event_type, point, point, base::TimeTicks::Now(), flag,
+                       flag, pointer_details);
   event.SetClickCount(click_count);
 
   // There are cases where the code handling the message destroys the